现象

有条超长的层位线(20000+ 道)在雷达图上只显示了一截,甚至整段空白;短一点的层位线倒是正常。

原因

原来的渲染是把整段层位线一口气画到一个 Canvas 上,Canvas 的宽度就等于这段的道数。一条 20000 道的层位线,Canvas 宽度起步就是 20000 像素,缩放之后还更高。

而 GPU 纹理是有尺寸上限的,一般在 16384 ~ 32768 像素之间,看显卡。Canvas 宽度一旦超过这个上限,渲染就直接失败——而且是静默失败,表现就是空白或者只画了一截,啥报错都没有,排查起来很费劲。

视口裁剪

办法就是只画当前能看见的那一截,整段别都画。Canvas 宽度始终差不多等于视口宽度(屏幕上能看到的范围),内容跟着滚动、缩放重绘:

  • 根据当前的滚动位置和缩放,算出视口覆盖的道号区间 [from, to]
  • 只把这个区间里的层位线点画到 Canvas 上。
  • Canvas 宽度固定成视口宽度,永远不会越过 GPU 的纹理上限。
  • 用户一滚动或者缩放,就重新算区间、重绘。

附带的优化

视口裁剪顺带把性能问题也解决了:以前不管你看哪,都在画 20000 个点,现在只画视口里那几百个。再配合一个缓存——已经解析过的深度数组缓存起来,免得每次重绘都重新 split 字符串,滚动的时候开销又降了一截。

后来想想,这种超大尺寸的内容渲染,”按视口裁剪”基本是绕不开的办法:既躲开了 GPU 的纹理上限,又顺带把单帧要画的东西限住了。其实地图、图表、编辑器处理那种”无限画布”,套路也都是这一个。