canvas绘制基础图形图像

趁着清明放假的空闲,将之前写过的代码整理了一下,发现了一个比较有意思的项目,该项目其实也比较简单,就是利用Canvas的各种原生API在图像中绘制一些基础图形,以及一些图形的更改操作。顺便借此项目复习一下Canvas基础。 目前实现功能 基本实现功能 图片的放大缩小和拖拽 绘制多边形并修改 绘制矩形并修改 绘制线段(暂无修改) 绘制箭头(暂无修改) 图片的放大和缩小 drawImage() 图片的绘制 // 绘制图片 drawImage = () => { if (this.$imageDom) { try { this._context.drawImage( this.$imageDom, // 图片元素 0, // 开始剪切的 x 坐标位置 0, // 开始剪切的 y 坐标位置 this.imageOriginWidth, //被剪切图像的宽度 this.imageOriginHeight, //被剪切图像的宽度 this.offsetX, // 在画布上放置图像的 x 坐标位置 this.offsetY, //在画布上放置图像的 y 坐标位置 this.imageOriginWidth * this.currentRatio, //要使用的图像的宽度 this.imageOriginHeight * this.currentRatio //要使用的图像的高度 ); return Promise.resolve(); } catch (e) { console.log(e) } } } 计算画布上放置图像的坐标位置 按照上图方式去计算要放置的图像的点坐标 getOffset = (pointX, pointY, scale, ratio, dir) => { if (pointX && pointY) { // 获取图片 const width = this.imageOriginWidth * (scale - ratio * dir); const height = this.imageOriginHeight * (scale - ratio * dir); const x = this.offsetX; const y = this.offsetY; if ((pointX < x) && (pointY >= y && pointY <= y + height) ) { // 1 this.offsetY = pointY - (pointY - this.offsetY) / (scale - ratio * dir) * scale; } else if ((pointX < x) && pointY >= y + height) { // 2 this.offsetX = x; this.offsetY = (ratio * dir * this.imageOriginHeight - this.offsetY) * (-1); } else if (pointX > x + width && (pointY >= y && pointY <= y + height)) { // 5 this.offsetY = pointY - (pointY - this.offsetY) / (scale - ratio * dir) * scale; this.offsetX = (ratio * dir * this.imageOriginWidth - this.offsetX) * (-1); } else if ((pointX >= x && pointX <= x + width) && (pointY > y + height)) { // 3 this.offsetX = pointX - (pointX - this.offsetX) / (scale - ratio * dir) * scale; this.offsetY = (ratio * dir * this.imageOriginHeight - this.offsetY) * (-1); } else if (pointY < y && (pointX >= x && pointX <= x + width)) { // 7 this.offsetX = pointX - (pointX - this.offsetX) / (scale - ratio * dir) * scale; this.offsetY = y; } else if (pointX > x + width && (pointY > y + height)) { // 4 this.offsetX = (ratio * dir * this.imageOriginWidth - this.offsetX) * (-1); this.offsetY = (ratio * dir * this.imageOriginHeight - this.offsetY) * (-1); } else if (pointX > x + width && pointY < y) { // 6 this.offsetY = y; this.offsetX = (ratio * dir * this.imageOriginWidth - this.offsetX) * (-1); } else if (pointX < x && pointY < y) { // 8 this.offsetX = x; this.offsetY = y; } else { // 9 this.offsetX = pointX - (pointX - this.offsetX) / (scale - ratio * dir) * scale; this.offsetY = pointY - (pointY - this.offsetY) / (scale - ratio * dir) * scale; } } } 多边形的绘制(线的绘制、箭头的绘制) moveTo() lineTo() closePath() 根据上述原生API绘制线,多边形的绘制即为坐标点大于2的路径的闭合曲线。 判断点是否在多边形内 isPointInPath 绘制当前闭合路径,根据该函数判断点是否在路径内。 判断点是否在线上 由于上述方法是判断点是否在路径内,就无法判断点是否在线上了,我采用的方法如下: 先判断点的坐标是否在线的坐标范围内,如果不在则点不在线上 如果1满足,则根据直线公式 y = kx + b 通过线段已知两点坐标求出斜率k和偏移值b; 根据线段的斜率和垂直线的斜率 k * k1 = -1,求出垂直线斜率,再根据当前点计算出通过该点的垂直线公式 y = (-1/k)x + m; 根据垂直相交线公式求出交点坐标,根据两点(当前点和交点坐标)求出线段距离,如果该距离小于误差范围值,则认为点在线上,反之则认为不在线上。 判断点是否在线上 function isPointInLinePath(line, dot, threshold) { const x2 = dot[0] ? dot[0] : 0; const y2 = dot[1] ? dot[1] : 0; const p1 = line[0]; const p2 = line[1]; const [p1X, p1Y] = p1; const [p2X, p2Y] = p2; let l = threshold + 1; let x = 0; let y = 0; if ( ((p1X <= x2 && x2 <= p2X) || (p2X <= x2 && x2 <= p1X)) && ((p1Y <= y2 && y2 <= p2Y) || (p2Y <= y2 && y2 <= p1Y)) ) { const slop = _calSlop(p1, p2); // 计算斜率 const verSlop = _calVerticalSlop(slop); // 计算垂直斜率 const x1 = p1[0] || 0; const y1 = p1[1] || 0; if (slop != 0 && verSlop != 0) { if (y2 == slop * x2 + y1 - slop * y1) { // 点在当前直线上 x = x2; y = y2; } else { x = parseFloat( (y2 - y1 + slop * x1 - verSlop * x2) / (slop - verSlop) ); y = parseFloat(slop * x + y1 - slop * x1); } } else { // 垂直于x轴或平行于x轴 if (x1 == p2X) { // 平行于y轴 x = x1; y = y2; } else if (y1 == p2Y) { // 平行于x轴 x = x2; y = y1; } } if ( (p1X <= x && x <= p2X) || (p2X <= x && x <= p1X && (p1Y <= y && y <= p2Y)) || (p2Y <= y && y <= p1Y) ) { l = parseInt(Math.sqrt(Math.pow(x2 - x, 2) + Math.pow(y2 - y, 2))); } } if (l < threshold) { // 说明是点在线上 return true; } return false; } 绘制矩形 rect() 根据原生API绘制图形,修改时的判断方式同多边形的判断。 实现原理就介绍到这里,更多详细信息请去https://github.com/jdkwky/my-vue-example/tree/master/src/view/canvas中了解~

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):