一、安装
npm install fabric
二、引入创建
import { fabric } from 'fabric'
initCanvas () {
// 初始化一张画布
this.fabricObj = new fabric.Canvas('canvas', {
isDrawingMode: true,
selectable: false,
selection: false,
devicePixelRatio: true // Retina 高清屏 屏幕支持
})
// 设置笔刷的颜色和宽度
this.fabricObj.freeDrawingBrush.color = this.drawOption.color
this.fabricObj.freeDrawingBrush.width = this.drawOption.lineWidth
// 设置画笔的大小,整屏可书写
this.fabricObj.setWidth(document.body.clientWidth)
this.fabricObj.setHeight(document.body.clientHeight)
// 如果传过来的数据中自带有画笔的笔记
if (this.currentPage.fabricHistoryJson) {
const state = JSON.parse(this.currentPage.fabricHistoryJson)
this.fabricHistoryJson = state
this.fabricObj.loadFromJSON(state[state.length - 1])
} else {
this.fabricObj.clear()
}
// 绑定画板事件
this.fabricObjAddEvent()
},
三、绑定画板的一些事件
主要是画笔的一些事件,以及选中删除事件
fabricObjAddEvent () {
this.fabricObj.on({
'mouse:down': (o) => {
this.toggleClear()
this.mouseFrom.x = o.pointer.x
this.mouseFrom.y = o.pointer.y
this.doDrawing = true
if (this.currentTool === 'text') {
this.drawText()
}
},
'mouse:up': (o) => {
this.mouseTo.x = o.pointer.x
this.mouseTo.y = o.pointer.y
this.drawingObject = null
this.moveCount = 1
this.doDrawing = false
this.updateModifications(true)
},
'mouse:move': (o) => {
if (this.moveCount % 2 && !this.doDrawing) {
// 减少绘制频率
return
}
this.moveCount++
this.mouseTo.x = o.pointer.x
this.mouseTo.y = o.pointer.y
this.drawing()
},
// 对象移动时间
'object:moving': (e) => {
e.target.opacity = 0.5
},
// 增加对象
'object:added': (e) => {
},
'object:modified': (e) => {
e.target.opacity = 1
// const object = e.target
this.updateModifications(true)
},
'selection:created': (e) => {
if (e.selected.length > 1 && e.target._objects) {
// 多选删除
var etCount = e.target._objects.length
for (var etindex = 0; etindex < etCount; etindex++) {
this.fabricObj.remove(e.target._objects[etindex])
}
} else {
// 单选删除
this.fabricObj.remove(e.target)
}
this.fabricObj.discardActiveObject() // 清楚选中框
this.updateModifications(true)
}
})
},
// 储存历史记录
updateModifications (savehistory) {
if (savehistory === true) {
this.fabricHistoryJson.push(JSON.stringify(this.fabricObj))
}
}
四、绘制各种图形
路径的绘制方法以五边形作为例子
fabricObject = new fabric.Path(drawPentagon(this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y), {
right: this.mouseFrom.x,
bottom: this.mouseFrom.y,
stroke: this.drawOption.color,
strokeWidth: this.drawOption.lineWidth,
strokeLineJoin: 'round',
fill: 'rgba(255, 255, 255, 0)'
})
if (fabricObject) {
this.fabricObj.add(fabricObject)
}
drawPentagon = (fromX, fromY, toX, toY) => {
const width = toX - fromX
const height = toY - fromY
let path = 'M' + fromX + ' ' + fromY
path += 'L' + (fromX + width / 2) + ' ' + (fromY - (height * 0.618))
path += 'L' + (fromX + width) + ' ' + fromY
path += 'L' + (toX - width * 0.191) + ' ' + toY
path += 'L' + (fromX + width * 0.191) + ' ' + toY
path += 'z'
return path
}
复杂的图形需要使用 fabric.Group
fabricObject = new fabric.Group(drawSmile(this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y, {
right: this.mouseFrom.x,
bottom: this.mouseFrom.y,
stroke: this.drawOption.color,
strokeWidth: this.drawOption.lineWidth,
srokeLineJoin: 'round',
fill: 'rgba(255, 255, 255, 0)'
}))
if (fabricObject) {
this.fabricObj.add(fabricObject)
}
drawSmile = (fromX, fromY, toX, toY, pathConfig) => {
const R = Math.sqrt(Math.pow((toX - fromX), 2) + Math.pow((toY - fromY), 2)) / 2
const px = (toX - fromX) > 0 ? 0 : (toX - fromX)
const py = (toY - fromY) > 0 ? 0 : (toY - fromY)
const circle = new fabric.Circle({
left: fromX + px,
top: fromY + py,
radius: R,
stroke: pathConfig.stroke,
strokeWidth: pathConfig.strokeWidth,
fill: pathConfig.fill
})
const leftEye = new fabric.Circle({
left: fromX + px + (R / 2),
top: fromY + py + R / 2,
radius: R / 10,
stroke: pathConfig.stroke,
strokeWidth: pathConfig.strokeWidth,
fill: pathConfig.stroke
})
const rightEye = new fabric.Circle({
left: fromX + px + ((R) / 3) + (R),
top: fromY + py + (R) / 2,
radius: R / 10,
stroke: pathConfig.stroke,
strokeWidth: pathConfig.strokeWidth,
fill: pathConfig.stroke
})
const mouth = new fabric.Circle({
left: fromX + px + (R) / 2,
top: fromY + py + 2 * (R) / 3,
radius: R / 2,
angle: 0,
startAngle: 0,
endAngle: Math.PI,
stroke: pathConfig.stroke,
strokeWidth: pathConfig.strokeWidth,
fill: pathConfig.stroke
})
return [circle, leftEye, rightEye, mouth]
}
正方体
drawCube = (fromX, fromY, toX, toY, pathConfig) => {
const width = toX - fromX
const height = toY - fromY
let path1 = 'M' + (fromX + width / 4) + ' ' + fromY
path1 += 'L' + toX + ' ' + fromY
path1 += 'L' + (toX - width / 4) + ' ' + (fromY + height / 4)
path1 += 'L' + fromX + ' ' + (fromY + height / 4)
path1 += 'z'
let path2 = 'M' + fromX + ' ' + (fromY + height / 4)
path2 += 'L' + fromX + ' ' + toY
path2 += 'L' + (toX - width / 4) + ' ' + toY
path2 += 'L' + toX + ' ' + (toY - height / 4)
path2 += 'L' + toX + ' ' + fromY
const path3 = 'M' + (toX - width / 4) + ' ' + (fromY + height / 4) + 'L' + (toX - width / 4) + ' ' + toY
return [new fabric.Path(path1, pathConfig), new fabric.Path(path2, pathConfig), new fabric.Path(path3, pathConfig)]
}
圆柱体
drawCylinder = (fromX, fromY, toX, toY, pathConfig) => {
const Tuoyuan = new fabric.Ellipse({
left: fromX,
top: fromY,
originX: 'center',
originY: 'center',
rx: Math.abs(fromX - toX) / 2,
ry: 30,
stroke: pathConfig.stroke,
strokeWidth: pathConfig.strokeWidth,
fill: 'rgba(255,255,255,0)'
})
const directionX = toX - fromX
const directionY = toY - fromY
let sweepFlag
if ((directionX > 0 && directionY > 0) || (directionX < 0 && directionY < 0)) {
sweepFlag = '0'
} else {
sweepFlag = '1'
}
const huPath = 'M' + (fromX - (toX - fromX) / 2) + ',' + toY + ' A' + Math.abs(fromX - toX) / 2 + ',30,0,0,' + sweepFlag + ',' + (fromX + (toX - fromX) / 2) + ',' + toY
const hu = new fabric.Path(huPath, pathConfig)
const pathleft = 'M' + (fromX - (toX - fromX) / 2) + ' ' + fromY + 'L' + (fromX - (toX - fromX) / 2) + ' ' + toY
const lineleft = new fabric.Path(pathleft, pathConfig)
const pathright = 'M' + (fromX + (toX - fromX) / 2) + ' ' + fromY + 'L' + (fromX + (toX - fromX) / 2) + ' ' + toY
const lineright = new fabric.Path(pathright, pathConfig)
return [Tuoyuan, hu, lineleft, lineright]
}