我们需要的效果
画布缩放,就是用滚轮放大或缩小整个画布,会导致画布中的图形变大会变小,虽然我们没有改图形的属性值。
实现上是 修改图形树根节点的 matrix 矩阵,这个其实就是视图矩阵,作用是把场景坐标转换为视口坐标。
画布缩放,会让图形的线宽在渲染上也发生变化。
比如图形的线宽为 1px,如果画布放大为 2 倍,线宽也会渲染为原来的两倍。如果画布缩小为原来的一半,线宽也会跟随变成 0.5px(抗锯齿,变成颜色比较浅的线)。
我们希望无论怎么缩放画布,线宽永远保持不变,为 1px。
为什么需要这个效果?
-
绘制选中图形的高亮轮廓线。做法通常是复制一份图形,fill 丢掉,stroke 的颜色改成高亮色,然后线宽不能随画布缩放改变
-
可用于类 CAD 的绘制线框图形的编辑器。这类编辑器注重的是图形的形状,图形是基于线条,也希望画布缩放前后线宽不变。
SVG 下的做法
SVG 就非常方便,我们只要给图形节点的样式设置为:
arduino
代码解读
复制代码
vector-effect: non-scaling-stroke;
就可以了。
我给矩形添加属性 vector-effect="non-scaling-stroke"
,圆形保持不变,对比看看效果。
也可以写成全局的。
arduino
代码解读
复制代码
svg * { vector-effect: non-scaling-stroke; }
strokeWidth 不强制要求为 1px,可以设置为任意你希望的像素值。
图形库
SVG 在图形很多的时候性能不太好,我们选择基于 Canvas 实现的图形库。
有些图形库是支持类似效果的。
比如性能非常强的图形库 Pixijs7,可以这样写:
javascript
代码解读
复制代码
const rect = new Graphics() .lineStyle(1, 0xffffff, undefined, undefined, true) .drawRect(20, 20, 200, 100);
lineStyle 方法的最后一个参数 native 如果为 true,就会使用 LINES 模式而不是 TRIANGLE_STRIP 模式。
同样给矩形应用效果,和没有应用效果的圆形对比,效果如下:
遗憾的是,strokeWidth 不管设置为多少,渲染的都是 1px,这是 WebGL 特性带来的效果。
另外,Pixi.js 8 目前不支持这个特性,因为还没把 pixi.js 7 的全部功能都迁移完成。大概是因为要兼容 WebGPU 的原因。
paperjs 可以这样设置:
ini
代码解读
复制代码
paper.project.currentStyle.strokeScaling = false;
其它都就不知道了,读者可自行查阅官方文档。
数据层修改
上面是从渲染器层面着手的,SVG 支持这种特性,所以我们才能做到线宽不变。
如果你的渲染器不支持这个特性,只能从数据层修改了。
当画布缩放值 zoom 发生改变时,要修改图形的 strokeWidth 为真实值的 1 / zoom 倍。
假设图形 strokeWidth 为 1,zoom 为 2,strokeWidth 就会渲染为 2。你说,诶,我把图形 stokeWidth值设置为 0.5,那放大 2 倍,渲染出来的线宽还是 1,这样也实现了渲染 strokeWidth 不变的效果。
这样就保持 strokeWidth 不变了,缺点是会破坏图形的缓存,需要重新做三角化。
不适用于有大量图形的场景。
还有一种就是计算图形的所有场景坐标系点,转换为视口坐标系的点,然后放到在视口坐标容器上,因为 zoom 永远为 1,此时 strokeWidth 设置为 1px 即可。
原文链接:https://juejin.cn/post/7419248237733445684