基于 Web 的SVG编辑器画布缩放方案

我的正在开发中的 svg 编辑器个人项目:https://github.com/F-star/svg-editor ,欢迎 star。

本文是系列文章,如果想看懂本文的一些术语,需要先阅读下面文章:

基于Web的svg编辑器(2)——层次结构设计(DOM结构)

svg 的画布缩放方案我目前研究出两个:

  1. 修改 svgContent 和 svgRoot 的属性
  2. 设置 svgContent 下的 g 元素的 transform 属性

修改 svgContent 和 svgRoot 的属性

开源的 svgedit SVG编辑器就是使用这种方式。

修改 svgContent 和 svgRoot 的属性的方案,具体的做法是:

给出一个缩放后的比例和缩放中心点,然后根据它们计算缩放后 svgContent 的宽高(width/height)、位置(x/y)和缩放比(viewBox),svgRoot 的宽高,workarea(编辑器视口) 的滚轮偏移量(scrollLeft/scrollTop)。

这种方案的问题是,首先 DOM操作很多,很耗费性能。另外我们还需要用 scrollLeft,scrollTop 来更新位置,这样可能会出现编辑器视口的 抖动现象,即编辑器视口突然发生移动。内存不足资源紧张的情况下尤为明显。

另外,缩放的时候,请务必阻止滚轮默认事件,因为滚轮默认会微小更新 scrollTop。如果不阻止,是会导致缩放后的正确的 scrollTop 又发生了一些偏移。

另外,可以考虑使用 节流函数,因为 mousewheel 的触发频率非常高,还有有必要降频的。

另外说个题外话,关于 滚轮事件 mousewheel 。mac 用触摸版滚动屏幕时,双手离开触摸板后,滚轮事件仍在触发。

我负责的项目使用的就是这个方案,所以我对它的缺点非常了解。

总的来说,这种方案的问题是:会有一点误差。不停地缩放,中心点就会一点点渐渐发生偏移。(猜测:可能因为每次放大,像素是变多的,缩放前的中点在新的画布上就是一个小圆的范围,就会造成误差。)

使用 transform 属性

这种方案我并没有用过,所以只能大概分析一下。

基于 Web 的 SVG 编辑器 boxy-svginker 使用的就是这种方法。

具体就是在 svgContent 下用一个 <g> 元素作为容器元素,将所有元素包装起来。缩放的时候,使用 transform<g> 设置缩放中心和缩放比例即可。

这种方案的好处是:

  • 不需要显示滚动条;
  • 不需要修改 svgRoot 和 svgCanvas 的宽高和位置;
  • 缩放后几乎没有精度损失。这大概得益于 transform 的特性。

滚轮缩放

滚轮缩放对画布进行缩放,中心点为光标位置。缩放可以有两种操作:

  1. 每一次滚轮事件,可以选择一个缩放比例,在原来的基础上进行缩放。
  2. 也可以像 Adobe Illustrator 一样,指定一系列缩放的比例,如 25%、33.33%、50%、66.7%,滚轮缩放时,会取向上或向下最近的比例。(哦豁,这里可以用 二分查找 提高查找最接近的比例。)

输入缩放

这里的输入缩放,指的是通过拖拽缩放条、下拉选项中选择比例或直接在输入框输入百分比等方式来进行缩放。

输入缩放和滚轮缩放区别在于,输入缩放无法通过光标确定中心点,那么怎么确定中心点呢?这里有两个策略:

  1. 如果没有选中图形,就以视口中心作为缩放中心点。这样缩放后,图形就不会跑出视口。
  2. 如果选中多个图形,就以它们的中心点为缩放中心。这样缩放后,就可以快速地定位正在操作的图形。

后面的话

如果你还有其他方案,请务必留言告诉我,我非常感兴趣。