编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

图形工具的另一种以光标为中心缩放实现

wxchong 2024-10-25 17:55:34 开源技术 9 ℃ 0 评论

大家好,我是前端西瓜哥。

最近有读者咨询我一个缩放问题。

应该是他要给项目做缩放功能,然后看到了 我图形编辑器缩放的文章,想要跟着我文章的思路移植到他的项目上。

但他搞不定,来找我。我给他搞定了,然后就有了这篇文章。


他给了我一个最小实现 demo。

我看了下,他用的是 zrender 渲染器(ECharts 的底层渲染器)。

和我之前写的文章不同的是,他用了 zrender 提供的 group 元素,给它设置了 xy 和 scale。然后绘制的元素都放在这个容器元素下。

我之前写的文章呢,没有这个 group 的概念,是给所有的坐标去乘一个视图矩阵,做坐标系的转换,能够正确落在适口矩形的新的位置。

这个 group 就有点像视口,虽然底层思路是一样的,但实现细节有很大不同。

移动

首先是拖拽移动画布的逻辑,变得简单了,直接 dx dy 加到 goup 的 x y 上就行了,不用除以 scale。

画布坐标转 group 下的坐标

画布坐标是缩放后坐标,转为 group 下的坐标,要先减去 group.x 或 group.y,然后除以 scale,得到缩放前的坐标。

const xInGroup = (x - group.x) / scale;
const yInGroup = (y - group.y) / scale;

光标缩放

然后是重点,缩放逻辑。

和我之前写的文章一样,要点还是:你原来在 group 的哪个相对位置进行缩放的,缩放后也得在那个位置

你要改 group 的 xy。


打个比方,假设这个点原来在相对 group 宽和高的四分之一处,假设 group 的 x y 是 (0, 0),宽高是 12 和 20,那点坐标就是 (3, 5)。

先不改变 group 的 xy,缩放为原来的 2 倍,点跑到了哪里?(6, 10)。

我们要让它表现为是以这个点进行缩放的,那我们就得把这个点移动对上原来的位置,于是让 group 的 x y 分别移动 -3 -5。

上面动图左上角矩形宽高就是要求的相对位移 dx 和 dy。

把图画出来,就好理解了。

我们要求的是这个图中的绿色向量。

列个式子算一下:

const dx 
  = -(scale / prevScale * (cx -group.x) - (cx - group.x))
  = -((cx - group.x) * (scale / prevScale - 1))
  = (cx - group.x) * (1 - scale / prevScale)
   
// dy 同理
const dy 
  = (cy - group.y) * (1 - scale / prevScale)

代码:

zr.on("mousewheel", function (e) {
  const prevScale = scale;
  scale < 0.2 ? (scale = 0.2) : scale;
  scale += e.wheelDelta > 0 ? 0.1 : -0.1;
  const dx = (e.offsetX - group.x) * (1 - scale / prevScale);
  const dy = (e.offsetY - group.y) * (1 - scale / prevScale);
  group.attr({
    scaleX: scale,
    scaleY: scale,
    x: group.x + dx,
    y: group.y + dy
  });
});

演示:

线上示例 demo:

https://codesandbox.io/s/vm8fh4?file=/src/index.ts


这位读者他用了特有的 origin 属性。这个 origin 可以用来指定 group 的缩放中心。

如果用 origin,你还是要改 xy 的,跑不了,别想太多。不仅如此,逻辑还更复杂了,毕竟又引入了新事物。不建议用。


如果你用 svg 方案,也是同理。

这里给一个 svg.js 的缩放在线示例:

https://codesandbox.io/s/vsylk4?file=/src/index.ts

结尾

缩放的要点在于,两个坐标系转换关系,要多画图推导推导。

我是前端西瓜哥,关注我,学习更多前端可视化和图形编辑器知识。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表