标尺功能完善
简述
标尺v1.0是以绑定three为主要目的库,在直接使用的canvas上,还有很多问题没有解决,最近空闲,准备将这部分功能完善起来。
功能完善
- 随鼠标缩放
- 自定义标尺列表
随鼠标缩放
缩放事件我参考了three.js的一些逻辑,首先,我们需要给整体逻辑增加一个缩放层级相关属性,在之前的版本中,虽然也有这个属性,但仅用于绑定three
this.zoom = 1;
this._scale = 1;
this.minZoom = 0;
this.maxZoom = Infinity;
this.zoomSpeed = options.zoomSpeed || 1;
this.zoomToCursor = options.zoomToCursor ?? true;
随后改造滚轮滚动事件:
_wheelEvent(e) {
const scale = this._getZoomScale(e.deltaY);
if (e.deltaY > 0) {
// 缩小
this._scale /= scale;
} else {
// 放大
this._scale *= scale;
}
const tempZoom = this.zoom;
this.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.zoom / this._scale));
if (this.zoom <= 0) this.zoom = 0.0001
this._gridSize = this.zoom * this._scaleGridRatio;
if (this.gridChange) {
const step = this._getScaleStep();
this.scaleStep = step;
this._gridSize = this.scaleStep * this.zoom * this._scaleGridRatio;
}
if (this._gridSize < this.minGridSize) {
// if minGridSize is greater than the minimum of scaleStepList, gridSize will be changed when gridSize > minGridSize
this._gridSize = this.minGridSize
this.zoom = tempZoom // reset zoom, greater than minGridSize
}
// 平移
const beforeZoom = this.unproject(e.offsetX, e.offsetY, tempZoom);
const afterZoom = this.unproject(e.offsetX, e.offsetY);
const nx = this.x - beforeZoom.x + afterZoom.x;
const ny = this.y - beforeZoom.y + afterZoom.y;
if (this.zoomToCursor) {
this.reDraw(nx, ny, this.zoom);
} else {
this.reDraw(this.x, this.y, this.zoom);
}
this._scale = 1;
}
_getZoomScale(delta) {
const normalizedDelta = Math.abs(delta / 100);
return Math.pow(0.95, this.zoomSpeed * normalizedDelta);
}
// 鼠标坐标转换为世界坐标(像素)
unproject(x, y, zoom = this.zoom) {
const halfWidth = this.dom.width / 2;
const halfHeight = this.dom.height / 2;
return {
x: (x - halfWidth) / zoom - this.x,
y: (y - halfHeight) / zoom - this.y
}
}
需要注意的是,上述代码中,getZoomScale 计算一次缩放层级的变化值,将zoomSpeed带入计算,这样就可以通过参数去调节缩放速度了;
缩放速度调整后,接下来是随鼠标方向的平移,其计算方式是:通过缩放前和缩放后的鼠标坐标,获取相应的世界坐标,两者的差值便是位移的值,需要注意的是,我这里的说的世界坐标,单位是像素,而非刻度尺中的数值,因为在代码内,x 和 y 是以像素去计算的。
自定义标尺列表
为了能够自定义标尺展示的数组,需要做一些原有逻辑的优化,首先增加一些属性
this.minGridSize = options.minGridSize ?? 20;
this.scaleStepList = options.scaleStepList || [1, 2, 5, 10, 25, 50, 100, 150, 300]; // 必须从小到大
this.scaleStep = options.scaleStep || this.scaleStepList[0]; // 必须是scaleStepList中的一个 标尺上的数值
this._scaleOrigin = this.scaleStep;
this._scaleGridRatio = this._gridSize / this.scaleStep // 标尺上的数值和像素的比例
this.reverseY = options.reverseY ?? false;
这些属性中,主要是增加了_scaleGridRatio,在初版中,忽略了像素与刻度的转换,导致不能自由的定义刻度列表,随后更改每一个gridSize的计算
this._gridSize = this.zoom * this._scaleGridRatio;
这样就完成了这个功能
总结
此次更新至v1.1,功能添加的并不多,主要是修复一些问题,也欢迎提出新的功能需求。
该功能以发布为npm包,欢迎尝试: