一、缩放原理
viewBox="x, y, width, height"// x:左上角横坐标,y:左上角纵坐标,width:宽度,height:高度
以鼠标为焦点缩放 = 以原点为焦点缩放 + 位移。利用svg的属性viewbox:x,y控制位移,width,height控制缩放。
在当前视窗内,改变viewBox的width与height即可实现以左上角为原点的缩放,故只需计算以左上角为焦点缩放后和以鼠标位置为焦点缩放后两个原点的偏移量即可。后文不再赘述scale与viewbox的关系。
二、计算偏移量(缩放前后的原点偏移量)
- 得到当前缩放倍数下x、y轴鼠标位置与原点的距离:获取鼠标位置和画布原点位置,并做差值再除以当前缩放倍数。
const x = ($event.clientX - CANVAS_LEFT) / this.transform.scale;
const y = ($event.clientY - CANVAS_TOP) / this.transform.scale;
- 分别得到x、y轴缩放后鼠标位置与新原点的距离:原距离 / 缩放前倍数 * 缩放后倍数
以鼠标位置为基准计算新原点位置
得到偏移量:2与1做差即得到两个原点的偏移量
为viewBox赋值
三、伪代码示例
// 按住ctrl后,不能通过滚轮使页面滚动
if ($event.ctrlKey || $event.metaKey) {
$event.preventDefault();
$event.stopPropagation();
let preScale = Math.max(this.transform.scale, 0.5);
if ($event.deltaY < 0 && ($event.ctrlKey || $event.metaKey) && this.transform.scale < 2) {
preScale = this.transform.scale;
this.transform.scale = this.transform.scale + 0.02;
}
if ($event.deltaY > 0 && ($event.ctrlKey || $event.metaKey) && this.transform.scale >= 0.5) {
preScale = this.transform.scale;
this.transform.scale = this.transform.scale - 0.02;
}
const x = ($event.clientX - CANVAS_LEFT) / this.transform.scale; // 鼠标位置与左上角在画布中的距离
const y = ($event.clientY - CANVAS_TOP) / this.transform.scale;
const offsetX = x * (this.transform.scale - preScale) / preScale; // 得到偏移量
const offsetY = y * (this.transform.scale - preScale) / preScale;
this.transform.translateX += offsetX;
this.transform.translateY += offsetY;
// 进行scale与translate到viewBox的换算和赋值
this.handleTransform();
}