我的正在开发中的 svg 编辑器个人项目:https://github.com/F-star/svg-editor ,欢迎 star。
本文是系列文章,如果想看懂本文的一些术语,需要先阅读下面文章:
基于Web的svg编辑器(2)——层次结构设计(DOM结构)
svg 的画布缩放方案我目前研究出两个:
- 修改 svgContent 和 svgRoot 的属性
- 设置 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-svg 和 inker 使用的就是这种方法。
具体就是在 svgContent 下用一个 <g> 元素作为容器元素,将所有元素包装起来。缩放的时候,使用 transform 对 <g> 设置缩放中心和缩放比例即可。
这种方案的好处是:
- 不需要显示滚动条;
- 不需要修改 svgRoot 和 svgCanvas 的宽高和位置;
- 缩放后几乎没有精度损失。这大概得益于 transform 的特性。
滚轮缩放
滚轮缩放对画布进行缩放,中心点为光标位置。缩放可以有两种操作:
- 每一次滚轮事件,可以选择一个缩放比例,在原来的基础上进行缩放。
- 也可以像 Adobe Illustrator 一样,指定一系列缩放的比例,如 25%、33.33%、50%、66.7%,滚轮缩放时,会取向上或向下最近的比例。(哦豁,这里可以用 二分查找 提高查找最接近的比例。)
输入缩放
这里的输入缩放,指的是通过拖拽缩放条、下拉选项中选择比例或直接在输入框输入百分比等方式来进行缩放。
输入缩放和滚轮缩放区别在于,输入缩放无法通过光标确定中心点,那么怎么确定中心点呢?这里有两个策略:
- 如果没有选中图形,就以视口中心作为缩放中心点。这样缩放后,图形就不会跑出视口。
- 如果选中多个图形,就以它们的中心点为缩放中心。这样缩放后,就可以快速地定位正在操作的图形。
后面的话
如果你还有其他方案,请务必留言告诉我,我非常感兴趣。