【问题标题】:Canvas Coordinate after scaling/Panning缩放/平移后的画布坐标
【发布时间】:2016-11-11 05:10:25
【问题描述】:

我正在通过我从 api 接收的一些数据构建一个 Canvas,这一切都很好。无论如何,我坚持使用以下代码 `canvas.addEventListener('wheel', (event: MouseWheelEvent) => { event.preventDefault();

    let coords = Positioning.transformedPoint(
      event.pageX - canvas.offsetLeft,
      event.pageY - canvas.offsetTop
    );

    canvasMethods.clear();
    canvasMethods.translate(coords.x, coords.y);

    if (event.wheelDeltaY > 0) {
      canvasMethods.scale(ZoomDirection.ZOOM_IN);
    } else if (event.wheelDeltaY < 0) {
      canvasMethods.scale(ZoomDirection.ZOOM_OUT);
    }

    canvasMethods.translate(-coords.x, -coords.y);

    this._renderFn();
  }, false);

  canvas.addEventListener('mousedown', (event: MouseEvent) => {
    event.preventDefault();

    this._dragging = true;
    this._dragStart = Positioning.transformedPoint(
      event.clientX - canvas.offsetLeft,
      event.clientY - canvas.offsetTop
    );
  }, false);

  canvas.addEventListener('dblclick', (event: MouseEvent) => {
    let coords = Positioning.transformedPoint(
      event.clientX - canvas.offsetLeft,
      event.clientY - canvas.offsetTop
    );
    this._clickFn(coords);
  });

  canvas.addEventListener('mousemove', (event: MouseEvent) => {
    if (this._dragging) {
      event.preventDefault();

      this._dragEnd = Positioning.transformedPoint(
        event.pageX - canvas.offsetLeft,
        event.pageY - canvas.offsetTop
      );

      let coords = Positioning.transformedPoint(
        event.clientX - canvas.offsetLeft,
        event.clientY - canvas.offsetTop
      );

      canvasMethods.translate(coords.x - this._dragStart.x, coords.y - this._dragStart.y);
      canvasMethods.clear();

      this._renderFn();
      this._dragStart = this._dragEnd;
    }
  }, false);

  canvas.addEventListener('mouseup', (event: MouseEvent) => {
    event.preventDefault();

    this._dragging = false;
    this._dragStart = null;
    this._dragEnd = null;
  })
}`

当它处于正常比例时,我得到了正确的坐标,但是当我缩放时,我得到一个增量错误(基本上实际点和鼠标光标之间的距离越来越大),我不知道为什么。为了计算矩阵中的坐标,我使用 SVG 方法作为包装器,方法如下 `export class Positioning { 静态 svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 私有静态 xform = Positioning.svg.createSVGMatrix();

static transformedPoint(x: number, y: number): SVGPoint {
  let coords = Positioning.svg.createSVGPoint();

  coords.x = x;
  coords.y = y;

  return coords.matrixTransform(Positioning.xform.inverse());
}

}`

我知道这在某种程度上与校准有关,但我真的无法弄清楚如何获得缩放比例并进行适当的操作以获得比例。我还检查了这个答案Zoom Canvas to Mouse Cursor,这非常准确,但实际上他以某种我无法理解的方式得到了它的说明。有其他人遇到过同样的问题吗?

【问题讨论】:

  • 你有正确的想法:通过transformation matrix 路由所有变换,然后使用矩阵在变换坐标和未变换坐标之间进行转换。
  • 是的,我已经很接近了,但我无法弄清楚拼图的最后一块,你的意思是通过反转矩阵在转换和未转换之间进行转换?因为你可以看到我的服务已经反转了矩阵。

标签: javascript html canvas


【解决方案1】:

我已经解决了这个问题,我忘记了一个重要的东西,来跟踪我的转变。现在我将链接代码以对可能遇到我同样问题的人有用(如果您不使用 Typescript 可以避免打字 ofc)

基本上我使用 SVG 矩阵方法来追踪画布中发生的事情。

这个类通过在其自身中存储由 createSVGMatrix() 创建的未转换画布(1,0,0,1,0,0)的基本矩阵并通过本机 SVGMatrix 方法跟踪转换来了解画布转换正在更新原始矩阵。然后,当我需要时,我只需使用变换点方法将鼠标的正确 x,y 坐标按比例缩放到矩阵。

export class Positioning {
static svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
static MatrixTransformationProxy = Positioning.svg.createSVGMatrix();

static transformedPoint(x: number, y: number): SVGPoint {
  let coords = Positioning.svg.createSVGPoint();

  coords.x = x;
  coords.y = y;

  return coords.matrixTransform(Positioning.MatrixTransformationProxy.inverse());
}

static translateProxy(x: number, y: number) {
  Positioning.MatrixTransformationProxy = Positioning.MatrixTransformationProxy.translate(x, y);
}

static scaleUniformProxy(scaleValue: number) {
  Positioning.MatrixTransformationProxy = Positioning.MatrixTransformationProxy.scale(scaleValue);
}

}

我使用调用 Canvas 方法的画布方法的包装器和我的 ProxyMatrix 保持同步我的画布转换和像这样更新 MatrixTransformationProxy 的相对定位方法

export class CanvasMethods {
static getSharedInstance(): CanvasMethods {
  return sharedInstance;
}

private _canvas: HTMLCanvasElement;

getCanvas(): HTMLCanvasElement {
  return this._canvas;
}

getContext(): CanvasRenderingContext2D {
  return this._canvas.getContext('2d');
}

registerCanvas(canvas: HTMLCanvasElement): void {
  this._canvas = canvas;
}

getCanvasBoundingRect(): BoundingRect {
  return new BoundingRect(0, 0, this._canvas.width, this._canvas.height);
}

clear(): void {
  this.getContext().save();
  this.getContext().setTransform(1, 0, 0, 1, 0, 0);
  this.getContext().clearRect(0, 0, this._canvas.width, this._canvas.height);
  this.getContext().restore();
}

scale(direction: ZoomDirection): void {
  let options = { //TODO get this from constructor options
    scaleValueOut: 0.8,
    scaleValueIn: 1.1
  };

  if (direction === ZoomDirection.ZOOM_OUT) {
    Positioning.scaleUniformProxy(options.scaleValueOut);
    this.getContext().scale(options.scaleValueOut, options.scaleValueOut);
  } else if (direction === ZoomDirection.ZOOM_IN) {
    Positioning.scaleUniformProxy(options.scaleValueIn);
    this.getContext().scale(options.scaleValueIn, options.scaleValueIn);
  }
}

translate(x: number, y: number): void {
  Positioning.translateProxy(x, y);
  this.getContext().translate(x, y);
}

}

const sharedInstance = new CanvasMethods(); }

【讨论】:

    猜你喜欢
    • 2014-09-13
    • 2017-03-06
    • 2021-11-18
    • 2016-07-23
    • 2018-05-13
    • 2014-08-27
    • 2017-05-30
    • 2016-01-01
    相关资源
    最近更新 更多