目录
前言
业务需求 查了很多资料,在这里仅是个人功能记录
很多代码参考https://gitee.com/k21vin/front-end-data-visualization
特别感谢
一、绘制直线
/** 直线
*
* @param {*} data
* @param {*} stroke 颜色
* @param {*} strokeWidth 宽度
* @param {*} id id
* @param {*} zIndex 层级
* @returns
*/
export function drawLine (data) {
let currentLine
let downPoint
let upPoint
let currentType = 'line'
let canvas = data.map
let stroke = data.stroke
let strokeWidth = data.strokeWidth
let id = data.id
let zIndex = data.zIndex
return new Promise((resolve, reject) => {
canvas.on('mouse:down', canvasMouseDown) // 鼠标在画布上按下
canvas.on('mouse:move', canvasMouseMove) // 鼠标在画布上移动
canvas.on('mouse:up', canvasMouseUp) // 鼠标在画布上松开
// 鼠标在画布上按下
function canvasMouseDown (e) {
downPoint = e.absolutePointer
if (currentType === 'line') {
currentLine = new fabric.Line(
[
downPoint.x, downPoint.y, // 起始点坐标
downPoint.x, downPoint.y // 结束点坐标
],
{
stroke: 'rgba(0, 0, 0, 0.2)', // 笔触颜色
selectable: isevented,
selection: true,
}
)
canvas.moveTo(currentLine, zIndex);
canvas.add(currentLine)
canvas.remove(currentLine)
canvas.renderAll()
}
}
// 鼠标在画布上移动
function canvasMouseMove (e) {
if (currentType === 'line' && currentLine) {
const currentPoint = e.absolutePointer
currentLine.set('x2', currentPoint.x)
currentLine.set('y2', currentPoint.y)
canvas.requestRenderAll()
}
}
// 鼠标在画布上松开
function canvasMouseUp (e) {
upPoint = e.absolutePointer
if (currentType === 'line') {
let line = new fabric.Line(
[currentLine.get('x1'), currentLine.get('y1'), currentLine.get('x2'), currentLine.get('y2')],
{
selectable: isevented,
selection: true,
stroke: stroke,
strokeWidth: strokeWidth,
id: id,
scaleX: 1,
scaleY: 1,
scale: 1,
}
)
canvas.moveTo(line, zIndex);
canvas.add(line)
canvas.remove(currentLine)
canvas.renderAll()
stopDraw(canvas)
console.log(currentLine);
data.points = [line.get('x1'), line.get('y1'), line.get('x2'), line.get('y2')]
data.dleft = line.get('left')
data.dtop = line.get('top')
data.scaleX = line.get('scaleX')
data.scaleY = line.get('scaleY')
data.scale = line.get('scale')
resolve(data)
}
}
})
}
二、绘制矩形
/**矩形
*
* @param {*} map 画布
* @param {*} id 用于判断的id
* @param {*} fill 填充色
* @param {*} stroke 边框填充色
* @param {*} strokeWidth 边框宽度
* @param {*} rx 圆角大小
* @param {*} ry 圆角大小
* @param {*} zIndex 层级
* @param {*} angle 旋转
*/
export function drawRect (data) {
let canvas = data.map
let id = data.id
let fill = data.fill
let stroke = data.stroke
let strokeWidth = data.strokeWidth
let rx = data.rx
let ry = data.ry
let angle = data.angle
let zIndex = data.zIndex
let currentType = 'rect'
return new Promise((resolve, reject) => {
canvas.on('mouse:down', canvasMouseDown) // 鼠标在画布上按下
canvas.on('mouse:up', canvasMouseUp) // 鼠标在画布上松开
let downPoint = null // 鼠标按下的坐标
// 鼠标在画布上按下
function canvasMouseDown (e) {
downPoint = e.absolutePointer
}
// 鼠标在画布上松开
function canvasMouseUp (e) {
if (currentType === 'rect') {
// 创建矩形
createRect(e.absolutePointer)
}
}
// 创建矩形
function createRect (pointer) {
// 点击事件,不生成矩形
if (JSON.stringify(downPoint) === JSON.stringify(pointer)) {
return
}
// 创建矩形
// 矩形参数计算
let top = Math.min(downPoint.y, pointer.y)
let left = Math.min(downPoint.x, pointer.x)
let width = Math.abs(downPoint.x - pointer.x)
let height = Math.abs(downPoint.y - pointer.y)
// 矩形对象
const rect = new fabric.Rect({
top,
left,
width,
height,
rx: rx,
ry: ry,
id: id,
fill: fill,
stroke: stroke,
strokeWidth: strokeWidth,
angle: angle,
selection: true,
selectable: isevented,
scaleX: 1,
scaleY: 1,
scale: 1,
})
// 将矩形添加到画布上
canvas.add(rect)
canvas.moveTo(rect, zIndex);
stopDraw(canvas)
data.dleft = left
data.dtop = top
data.width = width
data.height = height
data.scaleX = 1
data.scaleY = 1
data.scale = 1
resolve(data)
downPoint = null
}
})
}
三、绘制圆
/**圆
*
* @param {*} canvas 画布
* @param {*} id 用于判断的id
* @param {*} fill 填充色
* @param {*} stroke 边框填充色
* @param {*} strokeWidth 边框宽度
*/
export function drawCircle (data) {
let canvas = data.map
let id = data.id
let fill = data.fill
let stroke = data.stroke
let strokeWidth = data.strokeWidth
let zIndex = data.zIndex
let currentCircle
let downPoint
let upPoint
let currentType = 'circle'
//Setting the mouse events
return new Promise((resolve, reject) => {
canvas.on('mouse:down', canvasMouseDown) // 鼠标在画布上按下
canvas.on('mouse:move', canvasMouseMove) // 鼠标在画布上移动
canvas.on('mouse:up', canvasMouseUp) // 鼠标在画布上松开
// 鼠标在画布上按下
function canvasMouseDown (e) {
console.log(e);
downPoint = e.absolutePointer
if (currentType === 'circle') {
currentCircle = new fabric.Circle({
top: downPoint.y,
left: downPoint.x,
radius: 0,
fill: 'transparent',
stroke: 'rgba(0, 0, 0, 0.2)',
})
canvas.add(currentCircle)
}
}
// 鼠标在画布上移动
function canvasMouseMove (e) {
if (currentType === 'circle' && currentCircle) {
const currentPoint = e.absolutePointer
let radius = Math.min(Math.abs(downPoint.x - currentPoint.x), Math.abs(downPoint.y - currentPoint.y)) / 2
let top = currentPoint.y > downPoint.y ? downPoint.y : downPoint.y - radius * 2
let left = currentPoint.x > downPoint.x ? downPoint.x : downPoint.x - radius * 2
currentCircle.set('radius', radius)
currentCircle.set('top', top)
currentCircle.set('left', left)
canvas.requestRenderAll()
}
}
// 鼠标在画布上松开
function canvasMouseUp (e) {
upPoint = e.absolutePointer
if (currentType === 'circle') {
if (JSON.stringify(downPoint) === JSON.stringify(upPoint)) {
canvas.remove(currentCircle)
} else {
if (currentCircle) {
currentCircle.set('id', id)
let circle = new fabric.Circle({
top: currentCircle.get('top'),
left: currentCircle.get('left'),
radius: currentCircle.get('radius'),
fill: fill,
strokeWidth: strokeWidth,
stroke: stroke,
selectable: isevented,
id: id,
selection: true,
scaleX: 1,
scaleY: 1,
scale: 1,
})
data.radius = circle.get('radius');
data.dtop = circle.get('top')
data.dleft = circle.get('left')
data.scaleX = circle.get('scaleX')
data.scaleY = circle.get('scaleY')
data.scale = circle.get('scale')
canvas.remove(currentCircle)
canvas.add(circle)
canvas.moveTo(circle, zIndex);
resolve(data)
stopDraw(canvas)
canvas.renderAll();
}
}
currentCircle = null
}
}
});
}
四、添加文字
/**添加文字
*
* @param {*} data
* @param {*} canvas
* @param {*} fontSize 文字大小
* @param {*} textFill 文字颜色
* @param {*} zIndex 层级
* @param {*} backgroundColor 背景色
* @param {*} id
* @returns
*/
export function setText (data) {
let canvas = data.map
let fontSize = data.fontSize
let textFill = data.textFill
let zIndex = data.zIndex
let backgroundColor = data.backgroundColor
let dleft
let dtop
let textObject
let id = data.id
return new Promise((resolve, reject) => {
canvas.on('mouse:down', options => {
console.log('mouse-down:', options, options.e.clientY);
// 注意减去偏移量
dleft = options.e.layerX
dtop = options.e.layerY
if (!textObject) {
textObject = new fabric.Textbox('', {
left: dleft,
top: dtop,
fontSize: fontSize,
fill: textFill,
scaleX: 1,
scaleY: 1,
scale: 1,
hasControls: true, // 设置为false时,选中的时候不出现旋转缩放标识
hasBorders: true, // 设置为false时,选中的时候不出现边框
width: 30,
backgroundColor: backgroundColor,
id: id,
selectable: isevented,
selection: true,
})
canvas.add(textObject)
canvas.moveTo(textObject, zIndex)
// 文本打开编辑模式
textObject.enterEditing()
// 文本编辑框获取焦点
textObject.hiddenTextarea.focus()
} else {
stopDraw(canvas)
stopText(textObject, canvas)
data.text = textObject.get('text')
data.left = dleft
data.top = dtop
data.scaleX = 1
data.scaleY = 1
data.scale = 1
resolve(data)
}
});
})
}
五、添加图片
/** 设置图片
*
* @param {*} url 地址
* @param {*} angle 旋转角度
* @param {*} opacity 透明度
* @param {*} scaleX 宽度百分比
* @param {*} scaleY 高度百分比
* @param {*} zIndex 层级
* @param {*} id 标识
* @returns
*/
export function setImg (data) {
let canvas = data.map
let url = data.url
let angle = data.angle
let opacity = data.opacity
let scaleX = data.scaleX
let scaleY = data.scaleY
let zIndex = data.zIndex
let id = data.id
let dleft
let image
let dtop
return new Promise((resolve, reject) => {
canvas.on('mouse:down', options => {
console.log('mouse-down:', options, options.e.clientY);
// 注意减去偏移量
dleft = options.e.layerX
dtop = options.e.layerY
fabric.Image.fromURL(url, (img) => {
img.set({
left: dleft, // 图片相对画布的左侧距离
top: dtop, // 图片相对画布的顶部距离
angle: angle, // 图片旋转角度
opacity: opacity, // 图片透明度
scaleX: scaleX,
scaleY: scaleY,
id: id,
selection: true,
selectable: isevented, // 是否允许当前对象被选中
scaleX: 1,
scaleY: 1,
scale: 1,
});
// 添加对象
image = img
canvas.add(img);
canvas.moveTo(img, zIndex);
stopDraw(canvas)
data.left = dleft
data.top = dtop
data.width = image.get('width')
data.height = image.get('height')
data.scaleX = 1
data.scaleY = 1
data.scale = 1
resolve(data)
});
});
})
}
六、绘制折线
/** 折线
*
* @param {*} data
* @param {*} stroke 颜色
* @param {*} strokeWidth 宽度
* @param {*} zIndex 层级
* @param {*} id id
* @returns
*/
export function drawPolyline (data) {
let canvas = data.map
let stroke = data.stroke
let strokeWidth = data.strokeWidth
let zIndex = data.zIndex
let id = data.id
let currentType = 'polyline'
let currentPolyline = null
return new Promise((resolve, reject) => {
canvas.on('mouse:down', canvasMouseDown) // 鼠标在画布上按下
canvas.on('mouse:move', canvasMouseMove) // 鼠标在画布上移动
canvas.on('mouse:dblclick', canvasMouseDblclick) // 鼠标在画布上双击
// 创建折线
function createPolyline (e) {
const currentPoint = e.absolutePointer
currentPolyline = new fabric.Polyline(
[
{ x: currentPoint.x, y: currentPoint.y },
{ x: currentPoint.x, y: currentPoint.y }
],
{
fill: 'transparent',
stroke: 'rgba(0, 0, 0, 0.2)',
objectCaching: false
}
)
canvas.add(currentPolyline)
}
// 修改当前正在创建的折线
function changeCurrentPolyline (e) {
const currentPoint = e.absolutePointer
let points = currentPolyline.points
points.push({
x: currentPoint.x,
y: currentPoint.y
})
canvas.requestRenderAll()
}
// 折线橡皮带
function changePolylineBelt (e) {
const currentPoint = e.absolutePointer
let points = currentPolyline.points
points[points.length - 1].x = currentPoint.x
points[points.length - 1].y = currentPoint.y
canvas.requestRenderAll()
}
// 完成折线绘制
function finishPolyline (e) {
const currentPoint = e.absolutePointer
console.log(e, currentPoint, 12313);
let points = currentPolyline.points
points[points.length - 1].x = currentPoint.x
points[points.length - 1].y = currentPoint.y
points.pop()
points.pop()
canvas.remove(currentPolyline)
let polyline
if (points.length > 1) {
polyline = new fabric.Polyline(points, {
stroke: stroke,
fill: 'transparent',
strokeWidth: strokeWidth,
id: id,
selectable: isevented,
selection: true,
scaleX: 1,
scaleY: 1,
scale: 1,
})
canvas.add(polyline)
canvas.moveTo(polyline, zIndex);
}
currentPolyline = null
data.points = points
data.dleft = polyline.get('left')
data.dtop = polyline.get('top')
data.scaleX = polyline.get('scaleX')
data.scaleY = polyline.get('scaleY')
data.scale = polyline.get('scale')
canvas.requestRenderAll()
stopDraw(canvas)
resolve(data)
}
// 鼠标在画布上按下
function canvasMouseDown (e) {
if (currentType === 'polyline') {
if (currentPolyline === null) {
createPolyline(e)
} else {
changeCurrentPolyline(e)
}
}
}
// 鼠标在画布上移动
function canvasMouseMove (e) {
if (currentType === 'polyline' && currentPolyline) {
changePolylineBelt(e)
}
}
// 鼠标在画布上双击
function canvasMouseDblclick (e) {
if (currentType === 'polyline') {
finishPolyline(e)
}
}
})
}
七、绘制多边形
/**绘制多边形
*
* @param {*} data
* @param {*} stroke 颜色
* @param {*} strokeWidth 宽度
* @param {*} zIndex 层级
* @param {*} id id
* @param {*} fill 填充色
* @returns
*/
export function drawPolygon (data) {
let currentPolygon = null
let currentType = 'polygon'
let canvas = data.map
let stroke = data.stroke
let strokeWidth = data.strokeWidth
let id = data.id
let fill = data.fill
let zIndex = data.zIndex
return new Promise((resolve, reject) => {
canvas.on('mouse:down', canvasMouseDown) // 鼠标在画布上按下
canvas.on('mouse:move', canvasMouseMove) // 鼠标在画布上移动
canvas.on('mouse:dblclick', canvasMouseDblclick) // 鼠标在画布上双击
// 创建多边形
function createPolygon (e) {
const currentPoint = e.absolutePointer
currentPolygon = new fabric.Polygon(
[
{ x: currentPoint.x, y: currentPoint.y },
{ x: currentPoint.x, y: currentPoint.y }
],
{
fill: 'transparent',
stroke: 'rgba(0, 0, 0, 0.2)',
objectCaching: false
}
)
canvas.add(currentPolygon)
}
// 修改当前正在创建的多边形
function changeCurrentPolygon (e) {
const currentPoint = e.absolutePointer
let points = currentPolygon.points
points.push({
x: currentPoint.x,
y: currentPoint.y
})
canvas.requestRenderAll()
}
// 多边形橡皮带
function changePolygonBelt (e) {
const currentPoint = e.absolutePointer
let points = currentPolygon.points
points[points.length - 1].x = currentPoint.x
points[points.length - 1].y = currentPoint.y
canvas.requestRenderAll()
}
// 完成多边形绘制
function finishPolygon (e) {
const currentPoint = e.absolutePointer
let points = currentPolygon.points
points[points.length - 1].x = currentPoint.x
points[points.length - 1].y = currentPoint.y
points.pop()
points.pop()
canvas.remove(currentPolygon)
let polygon
if (points.length > 1) {
polygon = new fabric.Polygon(points, {
stroke: stroke,
fill: fill,
strokeWidth: strokeWidth,
id: id,
selectable: isevented,
selection: true,
scaleX: 1,
scaleY: 1,
scale: 1,
})
canvas.moveTo(polygon, zIndex);
canvas.add(polygon)
}
currentPolygon = null
canvas.requestRenderAll()
stopDraw(canvas)
data.points = points
data.dleft = polygon.get('left')
data.dtop = polygon.get('top')
data.scaleX = polygon.get('scaleX')
data.scaleY = polygon.get('scaleY')
data.scale = polygon.get('scale')
resolve(data)
}
// 鼠标在画布上按下
function canvasMouseDown (e) {
if (currentType === 'polygon') {
if (currentPolygon === null) {
createPolygon(e)
} else {
changeCurrentPolygon(e)
}
}
}
// 鼠标在画布上移动
function canvasMouseMove (e) {
if (currentType === 'polygon' && currentPolygon) {
changePolygonBelt(e)
}
}
// 鼠标在画布上双击
function canvasMouseDblclick (e) {
if (currentType === 'polygon') {
finishPolygon(e)
}
}
})
}
以上只是个人功能代码,欢迎大佬们提意见