【无标题】vue canvas画多边形

绘制单个多边形

<template>
  <div>
    <div>
      <button @click="onClear">清空</button>
    </div>
    <div>
      <canvas
        id="mycanvas"
        ref="mycanvas"
        width="700"
        height="450"
        @mousedown="canvasDown($event)"
        @mousemove="canvasMove($event)"
        @mouseup="canvasUp($event)"
        @dblclick="doubleclick()"
      >浏览器不持之canvas</canvas>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isdraw: false, //是否在画图形
      ctx: null, //canvas对象
      coordinates: [], //一个多边形的坐标信息
      cor_index: 0, //当前多边形的索引
      endtip: false //是否结束一个多边形的绘制
    };
  },
  mounted() {
    this.initDraw();
  },
  methods: {
    initDraw() {
      //初始化画布对象
      const canvas = document.querySelector("#mycanvas");
      this.ctx = canvas.getContext("2d"); //getContext() 方法返回一个用于在画布上绘图的环境,2d二维绘图
      this.ctx.strokeStyle = "rgb(0, 195, 155)"; //图形边框颜色
    },
    // 清空
    onClear() {
      this.coordinates = [];
      this.isdraw = false;
      this.endtip = false;
      this.ctx.clearRect(0, 0, 700, 450); //在给定的矩形内清除指定的像素
    },
    // 按下鼠标左键时--------------------------------------
    canvasDown(e) {
      console.log("点击");
      var x = e.offsetX;
      var y = e.offsetY;
      //获取鼠标按下的坐标,放入数组中
      this.coordinates.push({ cor_x: x, cor_y: y });
      this.drawcircle();
      this.isdraw = true; //正在画多边形
      if (this.endtip) {
        this.endtip = false; //清空,重新画
        console.log("重新画");
      }
      console.log(this.coordinates);
    },
    // 鼠标移动时----------------------------------------------------------
    canvasMove(e) {
      //没开始画或者结束画之后不进行操作
      if (this.coordinates.length == 0 || !this.isdraw || this.endtip) {
        return;
      }
      var x = e.offsetX;
      var y = e.offsetY;
      //获取上一个点
      var last_x = this.coordinates[this.coordinates.length - 1].cor_x;
      var last_y = this.coordinates[this.coordinates.length - 1].cor_y;
      this.ctx.clearRect(0, 0, 700, 450); //清空画布
      this.drawline(); //把之前的点连线
      this.drawcircle(); //画之前的点

      //获取鼠标移动时的点,画线,实现线段跟踪效果。
      this.ctx.beginPath();
      this.ctx.moveTo(last_x, last_y);
      this.ctx.lineTo(x, y); //追踪鼠标
      this.ctx.stroke(); //绘制已定义的路径 追踪鼠标
      //   this.ctx.closePath();
    },
    // 释放鼠标按钮-------------------------------------------------
    canvasUp(e) {},
    // 双击按钮时---------------------------------------
    doubleclick() {
      console.log("双击");
      //双击画布,在最后一个点的时候双击,自动连线第一个点,同时宣告画结束
      var x0 = this.coordinates[0].cor_x;
      var y0 = this.coordinates[0].cor_y;
      var x1 = this.coordinates[this.coordinates.length - 1].cor_x;
      var y1 = this.coordinates[this.coordinates.length - 1].cor_y;
      this.ctx.beginPath();
      this.ctx.moveTo(x0, y0);
      this.ctx.lineTo(x1, y1);
      this.ctx.stroke();
      //   this.ctx.closePath();
      this.isdraw = false;
      this.endtip = true;
      this.coordinates.pop();
      //   this.drawcircle();

      this.ctx.fillStyle = "rgba(0, 195, 155,0.4)";
      var bx = this.coordinates[0].cor_x;
      var by = this.coordinates[0].cor_y;
      this.ctx.beginPath();
      this.ctx.moveTo(bx, by);
      for (var k = 1; k < this.coordinates.length; k++) {
        var x = this.coordinates[k].cor_x;
        var y = this.coordinates[k].cor_y;
        this.ctx.lineTo(x, y);
      }
      this.ctx.fill();
      //   this.ctx.closePath();
      console.log(this.coordinates);
      this.coordinates = [];
    },
    //画线-把当前绘制的多边形之前的坐标线段绘制出来
    drawline() {
      for (var i = 0; i < this.coordinates.length - 1; i++) {
        this.ctx.beginPath();
        var x0 = this.coordinates[i].cor_x;
        var y0 = this.coordinates[i].cor_y;
        var x1 = this.coordinates[i + 1].cor_x;
        var y1 = this.coordinates[i + 1].cor_y;
        this.ctx.moveTo(x0, y0);
        this.ctx.lineTo(x1, y1);
        this.ctx.stroke();
        // this.ctx.closePath();
      }
    },
    //画点-把当前绘制的多边形之前的端点画圆
    drawcircle() {
      this.ctx.fillStyle = "rgb(0, 195, 155)";
      for (var i = 0; i < this.coordinates.length; i++) {
        var x = this.coordinates[i].cor_x;
        var y = this.coordinates[i].cor_y;
        this.ctx.beginPath(); //起始一条路径,或重置当前路径
        this.ctx.moveTo(x, y); //把路径移动到画布中的指定点(x,y)开始坐标
        this.ctx.arc(x, y, 5, 0, Math.PI * 2); //点
        this.ctx.fill(); //填充点
        // this.ctx.closePath();//创建从当前点回到起始点的路径
      }
    }
  }
};
</script>
<style lang="scss"  scoped>
.main {
  height: 90vh;
  color: black;
  background: white;
}
#mycanvas {
  border: 1px solid red;
  position: fixed;
  left: 0;
  right: 0;
  margin: auto;
}
</style>

绘制多个多边形 最终版本 包含判断线段交叉

<template>
  <div>
    <div>
      <div v-for="(item,index) in all_coordinates" :key="index">
        区域{{index+1}}
        <el-input :maxlength="20" v-model="item.identify" placeholder="请输入区域名称" clearable></el-input>
      </div>
      <button @click="onClear">清空</button>
    </div>
    <div>
      <canvas
        id="mycanvas"
        ref="mycanvas"
        width="700"
        height="450"
        @mousedown="canvasDown($event)"
        @mousemove="canvasMove($event)"
        @mouseup="canvasUp($event)"
        @dblclick="doubleclick()"
      >浏览器不持之canvas</canvas>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isdraw: false, //是否在画图形
      ctx: null, //canvas对象
      coordinates: [], //一个多边形的坐标信息
      cor_index: 0, //当前多边形的索引
      endtip: false, //是否结束一个多边形的绘制
      all_coordinates: [] //所有多边形的信息
    };
  },
  mounted() {
    this.initDraw();
  },
  methods: {
    initDraw() {
      //初始化画布对象
      const canvas = document.querySelector("#mycanvas");
      this.ctx = canvas.getContext("2d"); //getContext() 方法返回一个用于在画布上绘图的环境,2d二维绘图
      this.ctx.strokeStyle = "rgb(0, 195, 155)"; //图形边框颜色
    },
    // 清空
    onClear() {
      this.all_coordinates = [];
      this.coordinates = [];
      this.isdraw = false;
      this.endtip = false;
      this.ctx.clearRect(0, 0, 700, 450); //在给定的矩形内清除指定的像素
    },
    // 按下鼠标左键时--------------------------------------
    canvasDown(e) {
      if (this.endtip) {
        if (this.all_coordinates.length < 10) {
          this.endtip = false; //清空,重新画
        } else {
          this.$message.warning("最多可绘制十个闭合的凸多边形区域");
          return;
        }
      }
      var x = e.offsetX;
      var y = e.offsetY;
      //获取鼠标按下的坐标,放入数组中
      var insertFlag = true;
      this.coordinates.forEach((item, index) => {
        if (item.cor_x == x && item.cor_y == y) {
          insertFlag = false;
        }
      });
      if (insertFlag) {
        this.coordinates.push({ cor_x: x, cor_y: y });
        // 判断相交
        var lineList = [];
        this.coordinates.forEach((item, index) => {
          if (index < this.coordinates.length - 1) {
            lineList.push([
              item.cor_x,
              item.cor_y,
              this.coordinates[index + 1].cor_x,
              this.coordinates[index + 1].cor_y
            ]);
          }
        });
        lineList.forEach((item, index) => {
          if (index > 0 && index < lineList.length - 1) {
            var flag = this.judgeIntersect(
              lineList[lineList.length - 1][0],
              lineList[lineList.length - 1][1],
              lineList[lineList.length - 1][2],
              lineList[lineList.length - 1][3],
              lineList[index - 1][0],
              lineList[index - 1][1],
              lineList[index - 1][2],
              lineList[index - 1][3]
            );
            if (flag) {
              console.log("相交");
              this.coordinates.pop();
            }
          }
        });
      }
      if (this.coordinates.length > 19) {
        this.$message.warning("每个区域最多可绘制20个点坐标");
        this.doubleclick();
        this.drawcircles();
        return;
      }
      this.drawcircle();
      this.isdraw = true; //正在画多边形
    },
    // 鼠标移动时----------------------------------------------------------
    canvasMove(e) {
      //没开始画或者结束画之后不进行操作
      if (this.coordinates.length == 0 || !this.isdraw || this.endtip) {
        return;
      }
      var x = e.offsetX;
      var y = e.offsetY;
      //获取上一个点
      var last_x = this.coordinates[this.coordinates.length - 1].cor_x;
      var last_y = this.coordinates[this.coordinates.length - 1].cor_y;
      this.ctx.clearRect(0, 0, 700, 450); //清空画布
      this.drawline(); //把之前的点连线
      this.drawcircle(); //画之前的点
      if (this.all_coordinates.length != 0) {
        //不止一个多边形,把多边形们画出来
        this.drawlines();
        this.drawcircles();
        this.fillarea();
      }
      //获取鼠标移动时的点,画线,实现线段跟踪效果。
      this.ctx.beginPath();
      this.ctx.moveTo(last_x, last_y);
      this.ctx.lineTo(x, y); //追踪鼠标
      this.ctx.stroke(); //绘制已定义的路径 追踪鼠标
      this.ctx.closePath();
    },
    // 释放鼠标按钮-------------------------------------------------
    canvasUp(e) {
      this.ctx.clearRect(0, 0, 700, 450); //清空画布
      this.drawline(); //把之前的点连线
      this.drawcircle(); //画之前的点
      if (this.all_coordinates.length != 0) {
        //不止一个多边形,把多边形们画出来
        this.drawlines();
        this.drawcircles();
        this.fillarea();
      }
    },
    // 双击按钮时---------------------------------------
    doubleclick() {
      console.log("双击");
      //双击画布,在最后一个点的时候双击,自动连线第一个点,同时宣告画结束
      var x0 = this.coordinates[0].cor_x;
      var y0 = this.coordinates[0].cor_y;
      var x1 = this.coordinates[this.coordinates.length - 1].cor_x;
      var y1 = this.coordinates[this.coordinates.length - 1].cor_y;
      this.ctx.beginPath();
      this.ctx.moveTo(x0, y0);
      this.ctx.lineTo(x1, y1);
      this.ctx.stroke();
      this.ctx.closePath();
      this.isdraw = false;
      this.endtip = true;
      //   this.coordinates.pop();
      this.all_coordinates.push(this.coordinates);
      //   this.drawcircle();
      this.ctx.fillStyle = "rgba(0, 195, 155,0.4)";
      var bx = this.coordinates[0].cor_x;
      var by = this.coordinates[0].cor_y;
      this.ctx.beginPath();
      this.ctx.moveTo(bx, by);
      for (var k = 1; k < this.coordinates.length; k++) {
        var x = this.coordinates[k].cor_x;
        var y = this.coordinates[k].cor_y;
        this.ctx.lineTo(x, y);
      }
      this.ctx.fill();
      this.ctx.closePath();
      console.log(this.coordinates);
      console.log(this.all_coordinates);
      this.coordinates = [];
    },
    //画线-把当前绘制的多边形之前的坐标线段绘制出来
    drawline() {
      for (var i = 0; i < this.coordinates.length - 1; i++) {
        this.ctx.beginPath();
        var x0 = this.coordinates[i].cor_x;
        var y0 = this.coordinates[i].cor_y;
        var x1 = this.coordinates[i + 1].cor_x;
        var y1 = this.coordinates[i + 1].cor_y;
        this.ctx.moveTo(x0, y0);
        this.ctx.lineTo(x1, y1);
        this.ctx.stroke();
        this.ctx.closePath();
      }
    },
    //画点-把当前绘制的多边形之前的端点画圆
    drawcircle() {
      this.ctx.fillStyle = "rgb(0, 195, 155)";
      for (var i = 0; i < this.coordinates.length; i++) {
        var x = this.coordinates[i].cor_x;
        var y = this.coordinates[i].cor_y;
        this.ctx.beginPath(); //起始一条路径,或重置当前路径
        this.ctx.moveTo(x, y); //把路径移动到画布中的指定点(x,y)开始坐标
        this.ctx.arc(x, y, 5, 0, Math.PI * 2); //点
        this.ctx.fill(); //填充点
        this.ctx.closePath(); //创建从当前点回到起始点的路径
      }
    },
    drawlines() {
      //把所有多边形画出来
      for (var i = 0; i < this.all_coordinates.length; i++) {
        var cors = this.all_coordinates[i];
        //前后坐标连线
        for (var j = 0; j < cors.length - 1; j++) {
          this.ctx.beginPath();
          var x0 = cors[j].cor_x;
          var y0 = cors[j].cor_y;
          var x1 = cors[j + 1].cor_x;
          var y1 = cors[j + 1].cor_y;
          this.ctx.moveTo(x0, y0);
          this.ctx.lineTo(x1, y1);
          this.ctx.stroke();
          this.ctx.closePath();
        }
        //最后一个与第一个连线
        var begin_x = cors[0].cor_x;
        var begin_y = cors[0].cor_y;
        var end_x = cors[cors.length - 1].cor_x;
        var end_y = cors[cors.length - 1].cor_y;
        this.ctx.beginPath();
        this.ctx.moveTo(begin_x, begin_y);
        this.ctx.lineTo(end_x, end_y);
        this.ctx.stroke();
        this.ctx.closePath();
      }
    },
    drawcircles() {
      //为所有的多边形端点画圆
      this.ctx.fillStyle = "rgb(0, 195, 155)";
      for (var i = 0; i < this.all_coordinates.length; i++) {
        var cors = this.all_coordinates[i];
        for (var j = 0; j < cors.length; j++) {
          var x = cors[j].cor_x;
          var y = cors[j].cor_y;
          this.ctx.beginPath();
          this.ctx.moveTo(x, y);
          this.ctx.arc(x, y, 5, 0, Math.PI * 2);
          this.ctx.fill();
          this.ctx.closePath();
        }
      }
    },
    // 颜色填充
    fillarea() {
      this.ctx.fillStyle = "rgba(0, 195, 155,0.4)";
      for (var i = 0; i < this.all_coordinates.length; i++) {
        var cors = this.all_coordinates[i];
        var x0 = cors[0].cor_x;
        var y0 = cors[0].cor_y;
        this.ctx.beginPath();
        this.ctx.moveTo(x0, y0);
        for (var j = 1; j < cors.length; j++) {
          var x = cors[j].cor_x;
          var y = cors[j].cor_y;
          this.ctx.lineTo(x, y);
        }
        this.ctx.fill();
        this.ctx.closePath();
      }
    },
    // 判断直线是否相交
    judgeIntersect(x1, y1, x2, y2, x3, y3, x4, y4) {
      if (
        !(
          Math.min(x1, x2) <= Math.max(x3, x4) &&
          Math.min(y3, y4) <= Math.max(y1, y2) &&
          Math.min(x3, x4) <= Math.max(x1, x2) &&
          Math.min(y1, y2) <= Math.max(y3, y4)
        )
      )
        return false;
      var u, v, w, z;
      u = (x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1);
      v = (x4 - x1) * (y2 - y1) - (x2 - x1) * (y4 - y1);
      w = (x1 - x3) * (y4 - y3) - (x4 - x3) * (y1 - y3);
      z = (x2 - x3) * (y4 - y3) - (x4 - x3) * (y2 - y3);
      return u * v <= 0.00000001 && w * z <= 0.00000001;
    }
  }
};
</script>
<style lang="scss"  scoped>
.main {
  height: 90vh;
  color: black;
  background: white;
}
#mycanvas {
  border: 1px solid red;
  position: fixed;
  left: 0;
  right: 0;
  margin: auto;
}
</style>
要实现这个功能,你可以使用 Vue.js 和 canvas 标签来创建一个图片编辑器。以下是一个简单的示例代码,可以用来实现在图片上绘制矩形、箭头和多边形,并支持撤销操作。 ```vue <template> <div> <canvas ref="canvas" @mousedown="startDrawing" @mousemove="draw" @mouseup="endDrawing"></canvas> <button @click="undo">Undo</button> </div> </template> <script> export default { data() { return { canvas: null, ctx: null, isDrawing: false, startX: 0, startY: 0, endX: 0, endY: 0, shapes: [] } }, mounted() { this.canvas = this.$refs.canvas this.ctx = this.canvas.getContext('2d') const img = new Image() img.src = 'your-image-src' img.onload = () => { this.canvas.width = img.width this.canvas.height = img.height this.ctx.drawImage(img, 0, 0) } }, methods: { startDrawing(e) { this.isDrawing = true this.startX = e.clientX - this.canvas.offsetLeft this.startY = e.clientY - this.canvas.offsetTop this.shapes.push({ type: 'start', x: this.startX, y: this.startY }) }, draw(e) { if (!this.isDrawing) return this.endX = e.clientX - this.canvas.offsetLeft this.endY = e.clientY - this.canvas.offsetTop this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) this.ctx.drawImage(this.$refs.canvas, 0, 0) switch (this.shape) { case 'rectangle': this.ctx.strokeRect(this.startX, this.startY, this.endX - this.startX, this.endY - this.startY) break case 'arrow': // draw arrow break case 'polygon': // draw polygon break } }, endDrawing() { this.isDrawing = false this.shapes.push({ type: this.shape, x: this.startX, y: this.startY, w: this.endX - this.startX, h: this.endY - this.startY }) }, undo() { if (this.shapes.length === 0) return const lastShape = this.shapes.pop() if (lastShape.type === 'start') { this.shapes.pop() return } this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) this.ctx.drawImage(this.$refs.canvas, 0, 0) this.shapes.forEach(shape => { switch (shape.type) { case 'rectangle': this.ctx.strokeRect(shape.x, shape.y, shape.w, shape.h) break case 'arrow': // draw arrow break case 'polygon': // draw polygon break } }) } } } </script> ``` 这个示例中,我们在 canvas 标签上绑定了三个事件:mousedown、mousemove 和 mouseup。当用户按下鼠标左键时,我们会记录起始坐标,并将其添加到 shapes 数组中。在 mousemove 事件中,我们会实时更新结束坐标,并使用 strokeRect 方法出一个矩形。在 mouseup 事件中,我们会将当前的形状类型和坐标信息添加到 shapes 数组中。 我们还添加了一个 undo 方法,用于撤销上一步操作。当用户点击撤销按钮时,我们会从 shapes 数组中取出最后一个元素,然后根据其类型和坐标信息重新绘制布。 你可以根据这个示例,使用 canvas 的 API 来实现箭头、多边形等其他形状,并支持更多的操作和功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值