Vue3+ts+Fabric.js 实现可拖拽变化的多边形

4 篇文章 1 订阅
1 篇文章 0 订阅

需求:

使用canvas绘制多边形,且多边形的位置,大小和形状可拖动修改


使用Fabric.js

Fabric.js是一个可以简化canvas程序编写的库。 Fabric.js为canvas提供所缺少的对象模型
fabric.js官网

cnpm i fabric -D // 或者 npm i fabric -D

页面引入

import { fabric } from 'fabric'

html代码:

<div class="container">
    <div style="border: 1px solid #ccc; margin-right: 10px">
      <canvas ref="myCanvas" id="myCanvas" width="800" height="400">
      </canvas>
    </div>
    <el-button type="primary" @click="Edit">切换</el-button>
  </div>
.container {
  display: flex;
  padding: 8px;
  .toolBox {
  }
}

实现效果:

两个拖动模式
对多边形大小位置的拖动
对多边形形状,点的修改


typescript代码:

这里比较麻烦,参考了
我改写成了vue3.0的,且中的this稍微卡顿了半小时

<script lang="ts">
import { defineComponent, reactive, onMounted, toRefs, ref, watch } from 'vue'
import { fabric } from 'fabric'
import _ from 'lodash'

export default defineComponent({
  name: 'AreaPlan',
  components: {},
  setup() {
    let canvas: any
    const initCanvas = () => {
      // 直接获取Dom
      canvas = new fabric.Canvas('myCanvas')
      // 创建一个矩形数组,上面
      let points = [
        {
          x: 3,
          y: 4,
        },
        {
          x: 16,
          y: 3,
        },
        {
          x: 30,
          y: 5,
        },
        {
          x: 25.0,
          y: 55,
        },
        {
          x: 19,
          y: 44,
        },
        {
          x: 15,
          y: 30,
        },
        {
          x: 15,
          y: 55,
        },
        {
          x: 9,
          y: 55,
        },
        {
          x: 6,
          y: 53,
        },
        {
          x: -2,
          y: 55,
        },
        {
          x: -4,
          y: 40,
        },
        {
          x: 0,
          y: 20,
        },
      ]
      let polygon = new fabric.Polygon(points, {
        left: 100,
        top: 50,
        fill: '#D81B60',
        strokeWidth: 1,
        stroke: 'green',
        scaleX: 4,
        scaleY: 4,
        objectCaching: false,
        transparentCorners: false,
        cornerColor: 'blue',
      })

      canvas.viewportTransform = [0.7, 0, 0, 0.7, -50, 50]
      canvas.add(polygon)
    }
    const polygonPositionHandler = (
      dim,
      finalMatrix,
      fabricObject,
      constrol
    ) => {
      const index = constrol.pointIndex
      var x = fabricObject.points[index].x - fabricObject.pathOffset.x,
        y = fabricObject.points[index].y - fabricObject.pathOffset.y
      return fabric.util.transformPoint(
        { x: x, y: y },
        fabric.util.multiplyTransformMatrices(
          fabricObject.canvas.viewportTransform,
          fabricObject.calcTransformMatrix()
        )
      )
    }

    const actionHandler = (eventData, transform, x, y) => {
      var polygon = transform.target,
        currentControl = polygon.controls[polygon.__corner],
        mouseLocalPosition = polygon.toLocalPoint(
          new fabric.Point(x, y),
          'center',
          'center'
        ),
        polygonBaseSize = polygon._getNonTransformedDimensions(),
        size = polygon._getTransformedDimensions(0, 0),
        finalPointPosition = {
          x:
            (mouseLocalPosition.x * polygonBaseSize.x) / size.x +
            polygon.pathOffset.x,
          y:
            (mouseLocalPosition.y * polygonBaseSize.y) / size.y +
            polygon.pathOffset.y,
        }
      polygon.points[currentControl.pointIndex] = finalPointPosition
      return true
    }
    const anchorWrapper = (anchorIndex, fn) => {
      return function (eventData, transform, x, y) {
        var fabricObject = transform.target,
          absolutePoint = fabric.util.transformPoint(
            {
              x: fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x,
              y: fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y,
            },
            fabricObject.calcTransformMatrix()
          ),
          actionPerformed = fn(eventData, transform, x, y),
          newDim = fabricObject._setPositionDimensions({}),
          polygonBaseSize = fabricObject._getNonTransformedDimensions(),
          newX =
            (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) /
            polygonBaseSize.x,
          newY =
            (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) /
            polygonBaseSize.y
        fabricObject.setPositionByOrigin(absolutePoint, newX + 0.5, newY + 0.5)
        return actionPerformed
      }
    }
    const Edit = () => {
      console.log('canvas', canvas)
      console.log('Edit')
      var poly = canvas.getObjects()[0]
      canvas.setActiveObject(poly)
      poly.edit = !poly.edit
      if (poly.edit) {
        var lastControl = poly.points.length - 1
        poly.cornerStyle = 'circle'
        poly.cornerColor = 'rgba(0,0,255,0.5)'
        poly.controls = poly.points.reduce(function (acc, point, index) {
          const control = new fabric.Control({
            positionHandler: (a, b, c) =>
              polygonPositionHandler(a, b, c, control),
            actionHandler: anchorWrapper(
              index > 0 ? index - 1 : lastControl,
              actionHandler
            ),
            actionName: 'modifyPolygon',
            pointIndex: index,
          })
          acc['p' + index] = control
          return acc
        }, {})
      } else {
        poly.cornerColor = 'blue'
        poly.cornerStyle = 'rect'
        poly.controls = fabric.Object.prototype.controls
      }
      poly.hasBorders = !poly.edit
      canvas.requestRenderAll()
    }
    onMounted(() => {
      initCanvas()
    })
    return {
      //把切换事件返回出去
      Edit,
    }
  },
})
</script>

后面修改成为手动标绘多边形,且支持修改的,有时间就会更新,有不足的地方请留言。阿里嘎多~~~~~~。转载请标明出处,谢谢:

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cyanempty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值