图纸根据坐标画区域。canvas类似画板区域选择可回显,不可重叠、交叉、覆盖(限制最大边数)

6 篇文章 0 订阅

先贴图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1.先来两个canvas,一个存,一个画展示

<div class="box" style="width: 100%;height: 800px " v-if="showThis">
 <!--划线canvas-->
  <canvas id="canvas" width="1000px" height="600px" ref="canvas"></canvas>
  <!--储存-->
  <canvas
    id="canvasSave"
    width="1000px"
    height="600px"
    ref="canvasSave"
  ></canvas>
</div>

2.初始化canvas 并绑定移动点击事件

initCanvas() {
      //初始化
      //初始化
      this.can = document.getElementById("canvas");
      this.ctx = this.can.getContext("2d");
      this.canSave = document.getElementById("canvasSave");
      this.ctxSave = this.canSave.getContext("2d");
      this.ctx.strokeStyle = "rgba(213,16,34,1)"; //线条颜色
      this.ctx.lineWidth = 1; //线条粗细
      this.ctxSave.strokeStyle = "rgba(213,16,34,1)"; //线条颜色
      this.ctxSave.lineWidth = 1; //线条粗细
      var that = this;

      if (this.pointArr.length > 0) {
        //画布回显
        this.canvasSave1(this.hasSave); //保存点线同步到另一个canvas
        this.saveCanvas(); //生成画布
      }

      this.can.addEventListener(
        //点击
        "click",
        function(e) {
          that.canClick(e);
        },
        false
      );

      this.can.addEventListener(
        //移动
        "mousemove",
        function(e) {
          that.canMove(e);
        },
        false
      );
    },

3.画线,画完判断是否重叠,覆盖之后储存展示

    drawLine() {
      //划线
      if (this.oIndex > 0 && this.pointArr.length > 0) {//自动吸合
        var piX = this.pointArr[0].x;
        var piY = this.pointArr[0].y;
        //画点
        this.makearc(
          this.ctx,
          piX,
          piY,
          this.GetRandomNum(2, 2),
          0,
          180,
          "rgba(213,16,34,1)"
        );
        this.pointArr.push({ x: piX, y: piY });

        var checkResult = this.checkLineToLine(this.pointArr); //本次绘画线是否重合
        if (checkResult) {
          //无相交
          var checkLineToSurfaceResult = this.checkLineToSurface([
            this.pointArr[this.pointArr.length - 2],
            this.pointArr[this.pointArr.length - 1]
          ]);

          if (!checkLineToSurfaceResult) {
            //与面相交
            alert("与面相交");
            this.pointArr = [];
            this.ctx.clearRect(0, 0, this.ctx.width, this.ctx.height);
            this.canvasSave(this.pointArr);
          } else {
            if (this.hasSave.length < 1) {
              this.canvasSave(this.pointArr); //保存点线同步到另一个canvas
              this.saveCanvas(); //生成画布
            } else {
              var checkCoverResult = this.checkCover(this.hasSave); //是否覆盖别的图形
              if (checkCoverResult) {
                alert("覆盖");
                this.pointArr = [];
                this.ctx.clearRect(0, 0, this.ctx.width, this.ctx.height);
                this.canvasSave(this.pointArr);
              } else {
                this.canvasSave(this.pointArr); //保存点线同步到另一个canvas
                this.saveCanvas(); //生成画布
              }
            }
          }
        } else {
          alert("与线有交叉");
          //有相交,有相交清除
          this.pointArr = [];
          this.ctx.clearRect(0, 0, this.ctx.width, this.ctx.height);
          this.canvasSave(this.pointArr);
        }
      } else {
        piX = this.pointX;
        piY = this.pointY;
        this.makearc(
          this.ctx,
          piX,
          piY,
          this.GetRandomNum(2, 2),
          0,
          180,
          "rgba(213,16,34,1)"
        );
        this.pointArr.push({ x: piX, y: piY });
        var checkResult = this.checkLineToLine(this.pointArr);
        if (checkResult) {
          //线无相交
          if (this.pointArr.length < 2) {
            //线与面是否相交
          } else {
            var checkLineToSurfaceResult = this.checkLineToSurface([
              this.pointArr[this.pointArr.length - 2],
              this.pointArr[this.pointArr.length - 1]
            ]);

            if (!checkLineToSurfaceResult) {
              //与面相交
              alert("与面相交");
              this.pointArr = [];
              this.ctx.clearRect(0, 0, this.ctx.width, this.ctx.height);
              this.canvasSave(this.pointArr);
            }
          }
        } else {
          alert("线有交叉");
          //有相交,有相交清除
          this.pointArr = [];
          this.ctx.clearRect(0, 0, this.ctx.width, this.ctx.height);
          this.canvasSave(this.pointArr);
        }
      }
    },

4.点的时候判断是否在已画图形内,每次画成线判断是否交叉。

    canMove(e) {
      //跟随鼠标移动划线
      if (e.offsetX || e.layerX) {
        this.pointX = e.offsetX == undefined ? e.layerX : e.offsetX;
        this.pointY = e.offsetY == undefined ? e.layerY : e.offsetY;
        var piX, piY;
        /*清空画布*/
        this.ctx.clearRect(0, 0, this.can.width, this.can.height);
        /*鼠标下跟随的圆点*/
        this.makearc(
          this.ctx,
          this.pointX,
          this.pointY,
          this.GetRandomNum(2, 2),
          0,
          180,
          "rgba(213,16,34,1)"
        );

        if (this.pointArr.length > 0) {
          if (
            this.pointX > this.pointArr[0].x - 15 &&
            this.pointX < this.pointArr[0].x + 15 &&
            this.pointY > this.pointArr[0].y - 15 &&
            this.pointY < this.pointArr[0].y + 15
          ) {
            if (this.pointArr.length > 1) {
              piX = this.pointArr[0].x;
              piY = this.pointArr[0].y;
              this.ctx.clearRect(0, 0, this.can.width, this.can.height);
              this.makearc(
                this.ctx,
                piX,
                piY,
                this.GetRandomNum(2, 2),
                0,
                180,
                "rgba(213,16,34,1)"
              );
              this.oIndex = 1;
            }
          } else {
            piX = this.pointX;
            piY = this.pointY;
            this.oIndex = -1;
          }
          /*开始绘制*/
          this.ctx.beginPath();
          this.ctx.moveTo(this.pointArr[0].x, this.pointArr[0].y);
          if (this.pointArr.length > 1) {
            for (var i = 1; i < this.pointArr.length; i++) {
              this.ctx.lineTo(this.pointArr[i].x, this.pointArr[i].y);
            }
          }
          this.ctx.lineTo(piX, piY);
          this.ctx.fillStyle = "rgba(213,16,34,1)"; //填充颜色
          this.ctx.fill(); //填充
          this.ctx.stroke(); //绘制
        }
      }
    },

5.生成和回显

canvasSave1(pointArr) {
      //回显
      console.log(pointArr);
      this.ctxSave.clearRect(0, 0, this.ctxSave.width, this.ctxSave.height);
      this.ctxSave.beginPath();
      if (pointArr.length > 1) {
        // for (var i = 1; i < pointArr[0].length; i++) {
        //   this.ctxSave.lineTo(pointArr[0][i].x, pointArr[0][i].y);
        //   this.ctxSave.fillStyle =  "rgba(213,16,34,1)"; //填充颜色
        //   //ctxSave.fill();
        //   this.ctxSave.stroke(); //绘制
        // }
        for (var i = 0; i < pointArr.length; i++) {
          this.ctxSave.moveTo(pointArr[i][0].x, pointArr[i][0].y);
          for (var a = 1; a < pointArr[i].length; a++) {
            this.ctxSave.lineTo(pointArr[i][a].x, pointArr[i][a].y);
            this.ctxSave.fillStyle = "rgba(213,16,34,1)"; //填充颜色
            //ctxSave.fill();
            this.ctxSave.stroke(); //绘制
          }
        }
        this.ctxSave.closePath();
      }
    },
    saveCanvas() {
      /*生成画布 结束绘画*/ //双缓冲

      this.ctx.clearRect(0, 0, this.can.width, this.can.height);
      this.ctxSave.closePath(); //结束路径状态,结束当前路径,如果是一个未封闭的图形,会自动将首尾相连封闭起来
      this.ctxSave.fill(); //填充
      this.ctxSave.stroke(); //绘制
      this.hasSave.push(this.pointArr); //已经画好的储存一份,判断面面相交
      this.pointArr = [];
    },
 makearc(ctx, x, y, r, s, e, color) {
      //清空画布,画
      this.ctx.clearRect(0, 0, 199, 202); //清空画布
      this.ctx.beginPath();
      this.ctx.fillStyle = color;
      this.ctx.arc(x, y, r, s, e);
      this.ctx.fill();
    },

6线交叉判断

 checkLineToLine(pointArr) {
      //线交叉 判断 ,
      var arr = [];
      var edgeArr = [];
      var mixArr = [];
      var resultArr = [];
      for (var i = 1; i < pointArr.length; i++) {
        var arr = [];
        arr.push(pointArr[i - 1], pointArr[i]);
        edgeArr.push(arr);
      }
      for (var i = 0; i < edgeArr.length; i++) {
        for (var j = 0; j < edgeArr.length; j++) {
          if (i != j) {
            mixArr.push([edgeArr[i], edgeArr[j]]);
          }
        }
      }
      for (let index = 0; index < mixArr.length; index++) {
        var result = this.segmentsIntr(
          mixArr[index][0][0],
          mixArr[index][0][1],
          mixArr[index][1][0],
          mixArr[index][1][1]
        );
        resultArr.push(result);
      }

      if (resultArr.findIndex(target => target === true) == -1) {
        return true;
      } else {
        return false;
      }
    },

7.线是否和面交叉

checkLineToSurface(lineArr) {
      console.log("lineArr");
      console.log(lineArr);
      //只需检查最新画的一条线是否交叉 //线和已有面是否交叉
      //   console.log(this.hasSave.length);
      //   console.log(lineArr);
      var resultArr = [];
      if (this.hasSave.length == 0) {
      } else {
        for (var j = 0; j < this.hasSave.length; j++) {
          var edgeArr = [];
          for (var i = 1; i < this.hasSave[j].length; i++) {
            var arr = [];
            arr.push(this.hasSave[j][i - 1], this.hasSave[j][i]);
            edgeArr.push(arr);
          }
          for (var i = 0; i < edgeArr.length; i++) {
            // console.log(edgeArr[i]);
            var result = this.segmentsIntr(
              lineArr[0],
              lineArr[1],
              edgeArr[i][0],
              edgeArr[i][1]
            );
            resultArr.push(result);
          }
        }

        // for (var i = 1; i < this.hasSave[0].length; i++) {
        //   var arr = [];
        //   arr.push(this.hasSave[0][i - 1], this.hasSave[0][i]);
        //   edgeArr.push(arr);
        // }

        // console.log(edgeArr);
      }

      if (resultArr.findIndex(target => target === true) == -1) {
        return true;
      } else {
        return false;
      }
    },

8.线是否重合

segmentsIntr(a, b, c, d) {
      //线是否重合

      var area_abc = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
      var area_abd = (a.x - d.x) * (b.y - d.y) - (a.y - d.y) * (b.x - d.x);
      // 面积符号相同则两点在线段同侧,不相交 (对点在线段上的情况,当作不相交处理);
      if (area_abc * area_abd >= 0) {
        return false;
      }
      // 三角形cda 面积的2倍
      var area_cda = (c.x - a.x) * (d.y - a.y) - (c.y - a.y) * (d.x - a.x);
      // 三角形cdb 面积的2倍
      var area_cdb = area_cda + area_abc - area_abd;
      if (area_cda * area_cdb >= 0) {
        return false;
      }
      //计算交点坐标
      var t = area_cda / (area_abd - area_abc);
      var dx = t * (b.x - a.x),
        dy = t * (b.y - a.y);
      // { x: a.x + dx, y: a.y + dy }
      return true;
    },

9.面是否覆盖

    checkCover() {
      //检查面是否覆盖

      var dot = [];
      var resultArr = [];
      console.log(this.hasSave.length);
      for (let i = 0; i < this.hasSave.length; i++) {
        for (let j = 0; j < this.hasSave[i].length; j++) {
          dot.push(this.hasSave[i][j]);
        }
      }
      for (let i = 0; i < dot.length; i++) {
        resultArr.push(this.judge(dot[i], this.pointArr));
      }
      if (resultArr.findIndex(target => target === true) == -1) {
        return false;
      } else {
        return true;
      }
    },

10.是否点击到面内

 judge(dot, coordinates) {
      //点击面,点是否在面内

      var x = dot.x,
        y = dot.y;
      var crossNum = 0;
      for (var i = 0; i < coordinates.length - 1; i++) {
        var start = coordinates[i];
        var end = coordinates[i + 1];

        // 起点、终点斜率不存在的情况
        if (start.x === end.x) {
          // 因为射线向右水平,此处说明不相交
          if (x > start.x) continue;

          if (
            (end.y > start.y && y >= start.y && y <= end.y) ||
            (end.y < start.y && y >= end.y && y <= start.y)
          ) {
            crossNum++;
          }
          continue;
        }
        // 斜率存在的情况,计算斜率
        var k = (end.y - start.y) / (end.x - start.x);
        // 交点的x坐标
        var x0 = (y - start.y) / k + start.x;
        // 因为射线向右水平,此处说明不相交
        if (x > x0) continue;

        if (
          (end.x > start.x && x0 >= start.x && x0 <= end.x) ||
          (end.x < start.x && x0 >= end.x && x0 <= start.x)
        ) {
          crossNum++;
        }
      }

      return crossNum % 2 === 1;
    }

结语:这是功能开发之前自己写的小demo。实际开发还要根据canvas大小和实际图纸大小比例的坐标转化。核心功能就这么多。虽然不复杂,但是没做过的筒子们肯定摸不着头脑。给大家研究研究。demo比较丑注释很详细,凑合看

demo传送门

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老杨、

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

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

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

打赏作者

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

抵扣说明:

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

余额充值