标尺功能完善

285 阅读2分钟

标尺功能完善

简述

标尺v1.0是以绑定three为主要目的库,在直接使用的canvas上,还有很多问题没有解决,最近空闲,准备将这部分功能完善起来。

功能完善

  1. 随鼠标缩放
  2. 自定义标尺列表

随鼠标缩放

缩放事件我参考了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带入计算,这样就可以通过参数去调节缩放速度了;

缩放速度调整后,接下来是随鼠标方向的平移,其计算方式是:通过缩放前和缩放后的鼠标坐标,获取相应的世界坐标,两者的差值便是位移的值,需要注意的是,我这里的说的世界坐标,单位是像素,而非刻度尺中的数值,因为在代码内,xy 是以像素去计算的。

自定义标尺列表

为了能够自定义标尺展示的数组,需要做一些原有逻辑的优化,首先增加一些属性

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包,欢迎尝试:

  1. 使用文档
  2. 在线demo
  3. github地址