前言
在canvas中实现图片挪动、实现矩形挪动,大家可能看的很多了。然而我为什么还要去写这样的一篇文章呢,因为笔者已经做到3维图形下的挪动。包含挪动一个立方体上的一条边线、一个面、挪动多边形的一个点。最近始终在写canvas的相干的文章,想着温习下,读完本篇文章你能够学到,通过挪动矩形的一个点, 一个条边线,以及整个面的挪动。本篇文章从浅到深,心愿你急躁读上来。
面的挪动
试想一下,在canvas 下实现挪动性能。第一步必定创立canvas 并对canvas 增加move 事件, 这样咱们实时获取到咱们鼠标的地位,而后咱们只须要一直的革除画布,而后从新画矩形。就OK了,面的挪动初步实现。我在上面写点的挪动会把这里重写了, 这里先写个疾速繁难版本的。
const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');const width = 100;const height = 100;drawRect();function drawRect(x = 10,y = 10, scale = 1) { ctx.clearRect( 0, 0, 1800, 800 ); const halfwidth = width * scale / 2; const halfheight = height * scale / 2; ctx.strokeRect(x - halfwidth, y - halfheight,width * scale, height * scale)}let isMove = true;canvas.addEventListener('mousemove',(e)=>{ if(!isMove) { return } const x = e.clientX; const y = e.clientY; drawRect(x,y)})canvas.addEventListener('click',(e)=> { isMove = !isMove;});
isMove变量就是个开关,咱们总不能始终挪动吧,那也太累了,鼠标点击的就暂停。 对于上文为什么要x - halfwidth, y - halfheight
这里和大家解释下: strokeRect 是从矩形的左上角开始画的,然而呢我想把矩形放在鼠标核心地位, 所以做一个宽度和高度相减就能够完满展现了。
点的挪动
首先第一个问题就是? 咱们怎么晓得咱们抉择的是哪一个点呢,这里我做了一个简略的判断就是通过判断鼠标点击的地位和矩形的每个点的地位作比拟,看看哪一个离得近就作为指标点。因为咱们2d其实点的挪动其实也就是找这个点关联的线段, 所以咱们只须要从新生成关联的线段就好了,然而这里有一个比拟难以解决的中央? 就是挪动一个半圆? 如果咱们挪动半圆的断点, 这里就波及到圆弧的扭转了,可能变成椭圆弧或者说用二阶、三阶贝塞尔曲线去表白。还有就是挪动一个图形和画布上其余图形造成了切割? 是不是也要切割算法?其实能够用Clipper去求交并差,感兴趣的同学能够自行去理解一下,然而这些不在本篇文章所想要论述中。 本篇文章所有的例子(只反对直线也就是LineSegment)。
OK,咱们第一步咱们得去从新表白矩形,因为他不够通用精确的是从新表白四边形, 矩形和正方形只是其中的特列。这里我给出起因? 为什么呢一个很简答的case,挪动四边形的一个点,他可能变成上面这样:
ok 为了上面好表白咱们新建一个Point2d这个类, 将画布上的每一个点都用一个实例去示意。
class Point2d { constructor(x,y) { this.x = x || 0; this.y = y || 0; } clone() { return this.constructor(this.x, this.y); } add(v) { this.x += v.x; this.y += v.y return this; } random() { this.x = Math.random() *1800; this.y = Math.random() * 800; return this }}
接下来咱们就轻易在画布上一鼠标的地位别离加上矩形的长度和宽度,画出矩形。 代码如下:
function drawFourPolygon(x, y ,width = 50, height = 50) { ctx.clearRect( 0, 0, 1800, 800 ); ctx.beginPath(); ctx.moveTo(x- width /2, y - height/2) ctx.lineTo(x+ width / 2, y -height/2 ) ctx.lineTo(x+ width / 2, y + height/2 ) ctx.lineTo(x - width / 2, y + height/2 ) ctx.closePath() ctx.stroke()}
为了交互更加完满, 鼠标第一次点击确定挪动的开始点, 而后 鼠标不停地挪动就是挪动的终止点, 这样就确定了一个向量。 这里为了挪动的时候更加显著我减少了虚线性能,代码如下
function drawDashLine(start, end) { if (!start || !end) { return } ctx.strokeStyle = 'red'; ctx.setLineDash( [5, 10] ); ctx.beginPath(); ctx.moveTo( start.x, start.y ); ctx.lineTo( end.x, end.y ); ctx.closePath() ctx.stroke(); }
这里用到的就是canvas setLineDash 这个api 参数的含意,实线的间隔5、空白的间隔10 如此往返的走上来造成虚线。start和end 就是鼠标点击确定的就是start 点, 而后鼠标不停的挪动就是end点。 这里有一个小揭示就是我鼠标挪动的过程中先画了虚线,而后又画了矩形所以呢? 矩形咱们还是实线。咱们这里对画矩形代码做了批改,还是把虚线还原过去。
代码如下:
ctx.setLineDash([]);
OK整体的交互进去了,我先给大家看下成果:
是不是有点感觉了哈哈哈?从画面上看这还是整体的挪动不是点的挪动, 因为我画的图形以鼠标点击的那个点去画矩形的,我的下一篇文章会给大家介绍不规则多边形点的挪动,本篇文章咱们还是假如我挪动的是右上角的那个点。OK咱们由挪动的开始点和完结点, 能够失去一个挪动的向量, 所以咱们只有将要挪动的点 和这个向量相加。这样咱们是不是实现了点的挪动。
const moveVec = end.clone().sub(start); const rightTop = new Point2d(x+ width / 2, y - height/2).clone().add(moveVec)
这里我扭转了右上角的点,然而呢有一个问题就是咱们点击也是走的同一个函数,所以咱们得加个开关去判断下,次要是用来判读是第一次点击还是挪动就好了代码如下:
ctx.lineTo(isSelect ? rightTop.x : x+ width / 2, isSelect ? rightTop.y : y height/2)// 看下click和move 事件 开关就是isSelect这个变量canvas.addEventListener('mousemove',(e)=>{ if(!isMove) { return } const x = e.clientX; const y = e.clientY; clearRect(); end = new Point2d(x,y); drawDashLine(start,end); drawFourPolygon(start)})canvas.addEventListener('click',(e)=> { // 这是一个每次革除画布的函数 clearRect() isMove = !isMove; const x = e.clientX; const y = e.clientY; start = new Point2d(x,y); drawFourPolygon(start) isSelect = true;});
效果图如下:
哈哈哈是不是非常的丝滑和晦涩, 发现canvas 的画图的性能还是十分不错的。然而还是有一个问题就是,确定后果,看下面代码咱们确定后果是有问题的。 所以我以按住alt键完结为确定后果这就非常完满了,代码就不在这里展示了。
线的挪动
有了点的挪动,线的挪动就显示的非常简略。 线的挪动其实就是对应的点的挪动。 咱们以左边这条线为例子: 代码改写如下:
function drawFourPolygon( point, width = 50, height = 50) { if(!point) { return } ctx.strokeStyle = 'black' ctx.setLineDash([]); ctx.beginPath(); const { x, y } = point; const moveVec = end.clone().sub(start); // 其实就是 右上和右下这两个点同时挪动 const rightTop = new Point2d(x+ width / 2, y - height/2).clone().add(moveVec) const rightBottom = new Point2d(x+ width / 2, y + height/2).clone().add(moveVec) ctx.moveTo(x- width /2, y - height/2) ctx.lineTo(isSelect ? rightTop.x : x+ width / 2, isSelect ? rightTop.y : y - height/2) ctx.lineTo(isSelect ? rightBottom.x : x+ width / 2, isSelect ? rightBottom.y : y + height/2) ctx.lineTo(x - width / 2, y + height/2 ) ctx.closePath() ctx.stroke() }
咱们看下效果图:
总结
本篇文章次要介绍的2d图形下最根本的变动挪动,无论是线的挪动还是面的挪动最终都是点的挪动。其实挪动除了用向量示意还能够用矩阵, 或者说咱们旋转挪动缩放等等命令都能够用矩阵变动示意。 最初还是感激大家看到最初,码字不容易,如果看了对你有帮忙的, 欢送点个赞和关注。 你的反对是我继续更新好文章的最大能源。 所有代码都在我的github上。欢送大家star。