fabric 坐标系

38 阅读2分钟

Fabric 采用屏幕坐标系,相对传统笛卡尔(原点在左下、y 向上), 其原点在画布左上角,x 向右为正、y 向下为正。对于标注工具而言, 最佳坐标系是以「底图左上角」为原点, x 向右为正,y 向下为正。

核心概念

  • 视口

    • canvas, 放置 fabric 实例的容器,可以理解为「窗口」, 我们通过视口去观察 fabric 实例里绘制的一切
  • 场景

    • fabric实例,默认情况下, 原点与视口原点重合, 但可以通过 setViewportTranform 去控制场景的位置
  • 底图

    • 场景中的元素之一(要以底图左上角为原点重建坐标系)

目标

  • 将场景坐标系原点从「视口左上角」切换为「底图左上角」。
  • 兼容场景旋转(0/90/180/270),无论如何旋转,坐标系始终以底图(正视)左上角为原点。
  • 将底图居中贴合至视口

场景控制

底图居中贴合

1.png

const imgWidth = 1
const imgHeight = 1
const canvasWidth = 4 
const canvasHeight = 2
const scaleX = canvasWidth / width
const scaleY = canvasHeight / height
const scale = Math.min(scaleX, scaleY) // 计算出缩放因子
const deltaX = (canvasWidth - imgWidth * scale) / 2
const deltaY = (canvasHeight - imgHeight * scale) / 2
// 缩放
const transform = [scale, 0, 0, scale, 0, 0]
// 平移
const transform = [scale, 0, 0, scale, deltaX, deltaY]
fabricCanvas.setViewportTransform(transform)
// 这里的 deltaX 和 deltaY 的计坐标系其实是屏幕坐标系, 可以理解为将「场景坐标系」平移「deltaX, deltaY」」

视口旋转

2.png

const imgWidth = 1
const imgHeight = 1
const canvasWidth = 4 
const canvasHeight = 2
const scaleX = canvasWidth / width
const scaleY = canvasHeight / height
const scale = Math.min(scaleX, scaleY) // 计算出缩放因子
const deltaX =
  this.angle === 0
    ? (canvasWidth - width * scale) / 2
    : this.angle === 90
      ? scale * height + (canvasWidth - height * scale) / 2
      : this.angle === 180
        ? width * scale + (canvasWidth - width * scale) / 2
        : this.angle === 270
          ? (canvasWidth - height * scale) / 2
          : 0Ï
const deltaY =
  this.angle === 0
    ? (canvasHeight - height * scale) / 2
    : this.angle === 90
      ? (canvasHeight - width * scale) / 2
      : this.angle === 180
        ? height * scale + (canvasHeight - scale * height) / 2
        : this.angle === 270
          ? width * scale + (canvasHeight - width * scale) / 2
          : 0
    const cos = Math.cos(this.angle * (Math.PI / 180))
    const sin = Math.sin(this.angle * (Math.PI / 180))
    console.log(deltaX, deltaY, cos, sin)
    const transform = [scale * cos, scale * sin, -scale * sin, scale * cos, deltaX, deltaY]
// 遵循旋转 => 缩放 => 平移
const transformRotate = [cos,  sin,  -sin,  cos,  0,  0]
// 缩放
const transformScale = [scale, 0, 0, scale, 0, 0]
// 平移
const transformMove = [1, 0, 0, 1, deltaX, deltaY]
// 三个矩阵依次左乘 => [scale * cos, scale * sin, -scale * sin, scale * cos, deltaX, deltaY]
fabricCanvas.setViewportTransform([scale * cos, scale * sin, -scale * sin, scale * cos, deltaX, deltaY])
// 这里的 deltaX 和 deltaY 的计坐标系其实是屏幕坐标系, 可以理解为将「场景坐标系」平移「deltaX, deltaY」」