fabric 画板,绘制几何图形复杂图形

一、安装

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]
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值