首页 > 其他分享 >vue3绘制和回显多边形

vue3绘制和回显多边形

时间:2023-10-08 17:57:43浏览次数:36  
标签:canvas 多边形 回显 vue3 ctx value pointArr ctxSave const

参考了这个: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>

标签:canvas,多边形,回显,vue3,ctx,value,pointArr,ctxSave,const
From: https://www.cnblogs.com/waketzheng/p/vue3-ploygen-canvas.html

相关文章

  • vue3 watchEffect 的用法
    watchEffect 是Vue3中用于监听响应式数据变化并执行副作用函数的函数。它的使用方式和作用如下:基本用法:javascript插入代码复制代码import{ref,watchEffect}from'vue';constmyData=ref(0);watchEffect(()=>{console.log('myDatahaschanged:',myData.......
  • vue3
    vue3介绍vue3完全兼容vue2#tree-shaking是一种消除死代码的性能优化理论#TypeScript -javascript:坑---》填坑---》弱类型-typeScript:强类型语言 组合式api和配置项apivue3兼容vue2---》vue2的内容,vue3完全适用vue3不建议这么用了,建议使用组合式api,不建议使用配置......
  • vue3比vue2优势
    Vue3相对于Vue2有一些显著的优势,主要集中在性能、开发体验和一些新的特性上:性能提升:虚拟DOM的优化:Vue3使用了更高效的虚拟DOM算法,减少了不必要的DOM操作,提高了渲染性能。编译器优化:Vue3的编译器生成的代码更为紧凑和高效,加速了首次渲染和更新速度。更小的包大小:Vu......
  • vue3 新增 mitt 的使用
    在Vue3中,你可以使用 mitt 库来实现事件总线,以便在组件之间进行通信。下面是详细的介绍如何使用 mitt:安装 mitt 库: 首先,确保你已经安装了 mitt 库。你可以使用npm或yarn来安装它:插入代码复制代码npminstallmitt或插入代码复制代码yarnaddmitt......
  • 创建vue3项目、setup函数、ref函数、reactive函数、计算监听属性、生命周期、torefs、
    创建vue3项目#两种方式-vue-cli:vue脚手架---》创建vue项目---》构建vue项目--》工具链跟之前一样-vite:https://cn.vitejs.dev/-npmcreatevue@latest一路选择即可#运行vue3项目-vue-cli跟之前一样-vi......
  • vue3中defineComponent 的作用详解
    转自:https://www.jb51.net/article/263096.htm 这篇文章主要介绍了vue3中defineComponent 的作用,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 vue3中,新增了defineComponent,它并没有实现任何的逻辑,只是把接收的......
  • 是用非构建工具开始使用Vue3
     <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title>......
  • Vue3中shallowReactive 与 shallowRef 的用法
    转自:https://blog.csdn.net/qq_54527592/article/details/119840044  shallowReactive与shallowRef   shallowReactive:只处理对象最外层属性的响应式(浅响应式)。   shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理。   什么时候使用?     ......
  • Vue3
    vue3.3.4+vite4.4.91.组件安装1.1ElementPlusnpminstallelement-plus--savemain.jsimportElementPlusfrom'element-plus'import'element-plus/dist/index.css'constapp=createApp(App);app.use(ElementPlus).mount('#app'......
  • Vue3 Div 与 v-for 的配合应用,超出自动带滚动条
    效果图 代码<li><ahref="javascript:;"class="IndReaflexCHuans"><i></i><p>当前会议[0]</p></a><divstyle="height:80%;overflow:auto;"><divv-for="......