vue3绘制和回显多边形

发布时间 2023-10-08 17:50:19作者: waketzheng

参考了这个:https://blog.csdn.net/weixin_42178050/article/details/130012696
将其从vue2的语法改成了vue3,效果如下:

代码如下:

<template>
  <div class="app-container">
    <div class="d-flex j-center">
      <el-container>
        <el-main>
          <!--用来和鼠标进行交互操作的canvas-->
          <canvas
            id="canvas"
            ref="canRef"
            width="600px"
            height="600px"
            @mousedown="canvasDown"
            @mousemove="canvasMove"
          ></canvas>

          <!--存储已生成的点线,避免被清空-->
          <canvas id="canvasSave" ref="canSaveRef" width="600px" height="600px"></canvas>
        </el-main>
        <el-footer>
          <el-button
            id="deleteCanvas"
            class="deleteCanvas"
            type="primary"
            @click="deleteCanvasClick"
            >清空选区</el-button
          >
        </el-footer>
      </el-container>

      <!--canvas回显-->
      <!-- <canvas class="shaped" id="quad"></canvas> -->
    </div>
  </div>
</template>

<script setup lang="ts">
const canRef = ref()
const ctx = ref()
const canSaveRef = ref()
const ctxSave = ref()
let pointX = null
let pointY = null
let oIndex = -1 //判断鼠标是否移动到起始点处,-1为否,1为是
let pointArr = [] //存放坐标的数组
//回显数据
const pointColorArr = [
  {
    color: '#f7b5c1',
    houseName: '601单元',
    ponitArr: [
      { x: 6, y: 134 },
      { x: 6, y: 201 },
      { x: 63, y: 202 },
      { x: 66, y: 129 },
      { x: 6, y: 134 },
    ],
  },
  {
    color: '#bcf7d9',
    houseName: '602单元',
    ponitArr: [
      { x: 442, y: 403 },
      { x: 440, y: 347 },
      { x: 581, y: 347 },
      { x: 584, y: 568 },
      { x: 5, y: 566 },
      { x: 3, y: 401 },
      { x: 442, y: 403 },
    ],
  },
]
onMounted(async () => {
  //初始化画布对象
  //canRef.value = document.getElementById('canvas')
  canRef.value.width = 600
  canRef.value.height = 600
  ctx.value = canRef.value.getContext('2d')
  // canSaveRef.value = document.getElementById('canvasSave')
  canSaveRef.value.width = 600
  canSaveRef.value.height = 600
  ctxSave.value = canSaveRef.value.getContext('2d')

  ctx.value.strokeStyle = 'rgba(102,168,255,1)' //线条颜色
  ctx.value.lineWidth = 3 //线条粗细
  ctxSave.value.strokeStyle = 'rgba(102,168,255,1)' //线条颜色
  ctxSave.value.lineWidth = 2 //线条粗细
  init()
})
//初始化回显
function init() {
  pointColorArr.map(item => {
    canvasFill(item.ponitArr, item.color, item.houseName)
  })
}
/*点击画点*/
function canvasDown(e) {
  if (e.offsetX || e.layerX) {
    pointX = e.offsetX === undefined ? e.layerX : e.offsetX
    pointY = e.offsetY === undefined ? e.layerY : e.offsetY
    let piX, piY
    if (oIndex > 0 && pointArr.length > 0) {
      piX = pointArr[0].x
      piY = pointArr[0].y
      //画点
      makearc(piX, piY, GetRandomNum(2, 2))
      pointArr.push({ x: piX, y: piY })
      canvasSave(pointArr) //保存点线同步到另一个canvas
      saveCanvas() //生成画布
    } else {
      piX = pointX
      piY = pointY
      makearc(piX, piY, GetRandomNum(2, 2))
      pointArr.push({ x: piX, y: piY })
      canvasSave(pointArr) //保存点线同步到另一个canvas
    }
  }
}
// 鼠标移动事件
function canvasMove(e) {
  if (e.offsetX || e.layerX) {
    pointX = e.offsetX === undefined ? e.layerX : e.offsetX
    pointY = e.offsetY === undefined ? e.layerY : e.offsetY
    let piX, piY
    /*清空画布*/
    ctx.value.clearRect(0, 0, canRef.value.width, canRef.value.height)
    /*鼠标下跟随的圆点*/
    makearc(pointX, pointY, GetRandomNum(4, 4))

    if (pointArr.length > 0) {
      if (
        pointX > pointArr[0].x - 15 &&
        pointX < pointArr[0].x + 15 &&
        pointY > pointArr[0].y - 15 &&
        pointY < pointArr[0].y + 15
      ) {
        if (pointArr.length > 1) {
          piX = pointArr[0].x
          piY = pointArr[0].y
          ctx.value.clearRect(0, 0, canRef.value.width, canRef.value.height)
          makearc(piX, piY, GetRandomNum(4, 4))
          oIndex = 1
        }
      } else {
        piX = pointX
        piY = pointY
        oIndex = -1
      }
      /*开始绘制*/
      ctx.value.beginPath()
      ctx.value.moveTo(pointArr[0].x, pointArr[0].y)
      if (pointArr.length > 1) {
        for (let i = 1; i < pointArr.length; i++) {
          ctx.value.lineTo(pointArr[i].x, pointArr[i].y)
        }
      }
      ctx.value.lineTo(piX, piY)
      ctx.value.fillStyle = 'rgba(161,195,255,1)' //填充颜色
      //ctx.value.fill() //填充
      ctx.value.stroke() //绘制
    }
  }
}
// 存储已生成的点线
function canvasSave(pointArr) {
  ctxSave.value.clearRect(0, 0, ctxSave.value.width, ctxSave.value.height)
  ctxSave.value.beginPath()
  if (pointArr.length > 1) {
    ctxSave.value.moveTo(pointArr[0].x, pointArr[0].y)
    for (let i = 1; i < pointArr.length; i++) {
      ctxSave.value.lineTo(pointArr[i].x, pointArr[i].y)
      ctxSave.value.fillStyle = 'rgba(161,195,255,0.2)' //填充颜色
      //ctxSave.value.fill();
      ctxSave.value.stroke() //绘制
    }
    ctxSave.value.closePath()
  }
  console.log('存储已生成的点线', pointArr)
  //判断最后一个点重合则结束绘制
  if (pointArr.length > 1) {
    const { 0: a, [pointArr.length - 1]: b } = pointArr
    if (a.x === b.x && a.y === b.y) {
      console.log('结束绘制')
    }
  }
}
//回显canvas区域
function canvasFill(pointArr, color, houseName) {
  ctxSave.value.clearRect(0, 0, ctxSave.value.width, ctxSave.value.height)
  ctxSave.value.beginPath()
  if (pointArr.length > 1) {
    ctxSave.value.moveTo(pointArr[0].x, pointArr[0].y)
    for (let i = 1; i < pointArr.length; i++) {
      ctxSave.value.lineTo(pointArr[i].x, pointArr[i].y)
    }
    ctxSave.value.fillStyle = `${color}B3` //填充颜色     ${color}6B   ${color}
    ctxSave.value.fill()
    ctxSave.value.stroke() //绘制
    canvasText(houseName, pointArr[0])
  }
}
//绘制文字
function canvasText(text, point) {
  ctxSave.value.font = '30px Consolas' //字体样式的属性
  ctxSave.value.textAlign = 'center' //设置文本对齐方式
  ctxSave.value.textBaseline = 'middle' //文本基线
  const textWidth = ctxSave.value.measureText(text).width
  const canvasWidth = canRef.value.width
  console.log('canvasWidth', canvasWidth)
  ctxSave.value.fillStyle = 'red' //字体颜色
  ctxSave.value.fillText(text, point.x + 70, point.y + 100) //绘制文字
  ctxSave.value.arc(point.x, point.y, 3, 0, Math.PI * 2) //基准点
}
/*生成画布 结束绘画*/
function saveCanvas() {
  ctx.value.clearRect(0, 0, canRef.value.width, canRef.value.height)
  ctxSave.value.closePath() //结束路径状态,结束当前路径,如果是一个未封闭的图形,会自动将首尾相连封闭起来
  ctxSave.value.fill() //填充
  ctxSave.value.stroke() //绘制
  pointArr = []
}
//清空选区
function deleteCanvasClick() {
  ctx.value.clearRect(0, 0, canRef.value.width, canRef.value.height)
  ctxSave.value.clearRect(0, 0, canSaveRef.value.width, canSaveRef.value.height)
  pointArr = []
}
/*验证canvas画布是否为空函数*/
function isCanvasBlank(canvas) {
  const blank = document.createElement('canvas') //创建一个空canvas对象
  blank.width = canvas.width
  blank.height = canvas.height
  return canvas.toDataURL() === blank.toDataURL() //为空 返回true
}
/*canvas生成圆点*/
function GetRandomNum(Min, Max) {
  const Range = Max - Min
  const Rand = Math.random()
  return Min + Math.round(Rand * Range)
}
function makearc(x, y, r) {
  const color = 'rgba(102,168,255,1)'
  const s = 0
  const e = 180
  ctx.value.clearRect(0, 0, 199, 202) //清空画布
  ctx.value.beginPath()
  ctx.value.fillStyle = color
  ctx.value.arc(x, y, r, s, e)
  ctx.value.fill()
}
</script>

<style lang="stylus" scoped>
canvas {
  border: 1px solid #333;
  display: block;
}
.deleteCanvas {
  width: 100px;
  margin-left2: 200px;
  margin-top2: 650px;
}

#canvas {
  position: absolute;
  left: 200px;
  top: 0;
  z-index: 1;
  cursor: crosshair;
}

#canvasSave {
  position: absolute;
  left: 200px;
  top: 0;
}
#canvasSave {
  background-image: url('../assets/office.png');
  background-repeat: no-repeat;
  background-size: 600px;
}
</style>