共计 4150 个字符,预计需要花费 11 分钟才能阅读完成。
前言
在 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。