在实现缩放功能之前,我们无非需要考虑的是图形中心点的位置确定问题,在默认状态下不论是原点还是中心点均在画布的左上角位置,在不改变原点坐标的情况下对图形进行位移操作以实现缩放后确立中心点的位置。
业务场景
当我们在画布中以鼠标的指针作为中心点对画布上的图形进行缩放时,在鼠标指针的中心点位置不变的情况下对图形进行缩放,以scale为缩放系数进行横纵坐标等比缩放,其中x,y为某个浮点数(浮点数越小缩放越平滑),在缩放系数中存在一个缩放增量step的概念,所谓缩放增量是指每一个缩放较上一次增加了多少缩放量,除此之外我们还需要定义一个总的缩放量scaleAll,以记录前后缩放的缩放系数总量。缩放系数的换算如 缩放系数为scale,即放大后的图形相对于原图放大了scale倍,例如原图是1,放大后为1.1,scale = 1.1 / 1;
缩放前和缩放后会得到两个不同的偏移坐标,我们可以先定义缩放前坐标A₁{x₁,y₁}和缩放后坐标A₂{x₂,y₂},当我们完成缩放后其实我们鼠标的中心点已经产生了偏移到了A₂{x₂,y₂}的位置,但为了使鼠标中心点保持不变,我们需要对鼠标的中心点进行偏移回到A₁{x₁,y₁}点,那么就需要对前后两次偏移进行换算,于是得到x₂ - x₁,y₂ - y₁。
例举以A₁点为鼠标的位置,正常放大是以原点放大的,那么放大后A₁点的位置就会变成了A₂点,为了保证鼠标点不变然后需要对画布进行位移,将A₂点位置移到A₁点,就可以完成A₁点的缩放功能。A₁点坐标为x₁, y₁,A₂点坐标为x₂, y₂,放大系数为scale,那么默认状态下相对于原点放大后,A₁点的位置变成了A₂的位置,而我们的需求是要相对于A₁点放大,A₁点位置应该保持不变的,所以我们需要在放大后调整位置,就是将A₂的位置移动到A₁,于是得到 offsetX = x₂ - x₁,offsetY = y₂ - y₁。
以下是偏移公式:
let scaleAll = scale + step;
A1.x = A2.x - (A2.x - A1.x) * scaleAll / scale;
A1.y = A2.y - (A2.y - A1.y) * scaleAll / scale;
scale = scaleAll;
话不多说,上实例代码:
var scale,scaleAll = 1; //初始化缩放系数缩放总系数
// 鼠标缩放事件
function mouseWheel(event){
let e = event || window.event;
let A2 = {x: e.offsetX,y: e.offsetY};
let step = 0; // 缩放增量
if (e.wheelDelta) { //判断浏览器IE,谷歌滑轮事件
//TODO 大于0滑轮向上滚动时,小于0向下滚
step = e.wheelDelta > 0 ? 0.03 : -0.03;
} else if (e.detail) { //Firefox滑轮事件
// TODO 大于0滑轮向下滚动,小于0向上滚
step = e.detail > 0 ? -0.03 : 0.03;
}
/*
* 缩放系数的换算公式为每次缩放总系数=缩放系数+缩放增量,
* 每缩放一次最后缩放缩放系数和缩放总系数值需要互换
*/
scaleAll = scale + step;
scale = scaleAll;
A1.x = A2.x - (A2.x - A1.x) * scaleAll / scale;
A1.y = A2.y - (A2.y - A1.y) * scaleAll / scale;
draw(A1.x, A1.y, scaleAll);
}
// 绘制图形
function draw(x, y, scale){
ctx.clearRect(0,0,canvas.offsetWidth,canvas.offsetHeight);
ctx.save();
ctx.translate(x, y);
ctx.scale(scale, scale);
ctx.drawImage(image,0,0,canvas.width / 2,image.height / (image.width / canvas.width) / 2);
ctx.restore();
}
以上就是本缩放功能的解题思路,供小伙伴们参考,如有不足可多多发表评论加以探讨。