使用Canvas手画不规则多边形,并限制相交线和凹多边形 您所在的位置:网站首页 相交线问题 使用Canvas手画不规则多边形,并限制相交线和凹多边形

使用Canvas手画不规则多边形,并限制相交线和凹多边形

2023-08-25 16:54| 来源: 网络整理| 查看: 265

使用Canvas手画不规则多边形,并限制相交线和凹多边形 ​简介 ​

使用 Canvas 实现的手画不规则多边形功能。通过鼠标在画面上点击的点作为多边形的顶点,连线形成多边形。除了手画之外,还加入了随机生成和回显,检测多边形横穿,凹凸性的检测。注意:两个点如果靠太近会被认为是同一个点而忽略。闭合区域需要点击图形中的第一个点,或者点击“闭合图形”按钮。

两个 Canvas 图层 ​

由于要实现线条跟随鼠标运动功能,而且 Canvas 的图形无法清除单个绘制命令,因此我用 CSS 的绝对定位,在同一个区域叠加了两个 Canvas 对象。一个在下面,表示已经绘制结束的图形,叫做固定 Canvas;一个在上面,每次鼠标移动就重新绘制跟随鼠标移动的线条,叫做临时 Canvas。canvasTemp 即为临时 Canvas。

js .canvas-box { margin: 5px auto; background: #aaa; position: relative; .canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: crosshair; } } 绘制过程 ​

绘画过程简要描述为:

在绘画区域点击第 1 个点,随后线条跟随鼠标移动。随后点击第 2 — 到第 n 个点,每个点即为多边形的顶点。点击第一个点闭合图形,或者点击自动闭合图形按钮。固定 Canvas 绘制 ​

临时 Canvas接收点击事件,得到当前点击的坐标点。

如果是第一个点,则清空之前的绘画区域,并且在固定 Canvas 中移动位置到当前点。否则检查符合要求后,在固定 Canvas 中绘制一条上一个点到当前点的线。如果符合条件,则闭合图形。让线跟随鼠标移动。jsdraw(e) { // 点一个当前点 let pointDown = { x: e.offsetX, y: e.offsetY, }; // 第一个点 if (this.pointList.length === 0 || this.closeStatus) { this.clear(); this.canvasObj.beginPath(); this.canvasObj.moveTo(pointDown.x, pointDown.y); } else { // 首先检查生成的点是否符合要求 const check = this.checkPoint(pointDown, this.pointList); switch (check) { case "closeFirst": this.closeFigure(); return; case false: return; case true: break; } // 已经有点了,连成线 this.canvasObj.lineTo(pointDown.x, pointDown.y); this.canvasObj.stroke(); } this.pointList.push({ ...pointDown, }); // 如果已经到达最大数量,则直接闭合图形 if (this.pointList.length >= this.maxPointNum) { this.closeFigure(); return; } // 让线跟随鼠标移动 后面一节描述 }临时 Canvas 跟随鼠标移动 ​

在鼠标松开后,监听鼠标移动。在每次鼠标移动的时候,清空临时 Canvas。重新绘制一条点击的坐标点到当前鼠标位置的线。 由于鼠标位置移动很频繁,因此加入了简单的防抖:在下一次dom更新数据后,仅绘制鼠标最后移动到的位置。

js// 让线跟随鼠标移动 document.onmouseup = () => { document.onmousemove = (event) => { // 防抖 if (this.timeout) { clearTimeout(this.timeout); } this.timeout = setTimeout(() => { this.canvasTempObj.clearRect( 0, 0, this.canvasWidth, this.canvasHeight ); this.canvasTempObj.beginPath(); this.canvasTempObj.moveTo(e.offsetX, e.offsetY); this.canvasTempObj.lineTo(event.offsetX, event.offsetY); this.canvasTempObj.stroke(); this.timeout = null; }); }; };初始化和绘制结束 ​

初始化放在mounted中,主要是设置canvas对象。绘制结束则在检查图形符合要求后,直接闭合图形。检查是否符合要求的方法在后面描述。

js// 初始化 mounted() { this.canvasObj = this.$refs.canvas.getContext("2d"); this.canvasObj.lineWidth = 2; this.canvasObj.strokeStyle = "red"; this.canvasObj.fillStyle = "rgba(128, 100, 162, 0.5)"; this.canvasTempObj = this.$refs.canvasTemp.getContext("2d"); this.canvasTempObj.lineWidth = 2; this.canvasTempObj.strokeStyle = "red"; },js// 闭合图形 closeFigure() { // 检查部分 if (!this.checkPointCross(this.pointList[0], this.pointList)) { this.$message.error("闭合图形时发生横穿线,请重新绘制!"); this.clear(); return; } if (!this.checkPointConcave(this.pointList[0], this.pointList, true)) { this.$message.error("闭合图形时出现凹多边形,请重新绘制!"); this.clear(); return; } if (this.pointList.length >= this.minPointNum && !this.closeStatus) { // 符合要求 this.canvasTempObj.lineTo(this.pointList[0].x, this.pointList[0].y); this.canvasObj.closePath(); this.canvasObj.stroke(); this.canvasObj.fill(); document.onmousemove = document.onmouseup = null; this.canvasTempObj.clearRect(0, 0, this.canvasWidth, this.canvasHeight); this.closeStatus = true; // 绘制结束,返回数据 this.$emit("drawFinished", this.pointList); } }, // 清除图形 clear() { this.pointList = []; document.onmousemove = document.onmouseup = null; this.canvasTempObj.clearRect(0, 0, this.canvasWidth, this.canvasHeight); this.canvasObj.clearRect(0, 0, this.canvasWidth, this.canvasHeight); this.closeStatus = false; },随机生成和回显图形 ​

随机生成两个整数点作为xy坐标形成多边形顶点,判断是否符合要求,符合要求的顶点列表作为多边形。如果符合要求,则调用回显函数。

随机生成图形 ​

可以看到随机生成的图形中有while (1)循环,还有if (j > num * 100) 这种限制。这是因为目前是随机生成点,再判断是否符合要求,在遇到较复杂的图形限制时,随机生成函数很容易陷入死循环,因此加入了循环失败次数限制。

js// 辅助函数,获取随机点 getRandomPoint() { const x = Math.floor(Math.random() * this.canvasWidth + 1); const y = Math.floor(Math.random() * this.canvasHeight + 1); return { x, y, }; }, // 随机生成点并绘制图形 randomRegion() { while (1) { const num = this.regionNum.min; const pointList = [this.getRandomPoint()]; let i = 1; let j = 0; while (i num * 100) break; ++i; pointList.push(point); } // 判断生成的图形是否符合要求 if ( pointList.length


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有