技术拆解-3D饼图
数据结构
图元结构

绘图
获取图元相关的数据
因为一些线条、标注,都是和具体图元位置相关联的。
如何修改饼图的高度
琦哥:之前我 3D 关系图用的是 BufferGeometry,可以通过 geometry.getAttribute 获取 position 属性然后更新的,但是你那个图形我好像没用过,不太清楚怎么改变属性的厚度,,,,,或许可能可以尝试一下 geometry.dispose()然后再重新给一个新的 geometry
标注线
https://threejs.org/docs/index.html?q=line#manual/en/introduction/Drawing-lines
规则得看下 2 维饼图的规则,不然太丑了。。。
标注的文字
动画
饼的动画:
线条的动画:
每一块都需要标注么?
文本标签的动画:
需要开放的配置项
动画时长
各种颜色
迁移到 component 项目
1、package.json 添加依赖:
1 | |
2、绘图类必须提供如下方法:
play、seek、pause、ready、setData
resize 不知道是否必须
3、x、y、z 轴的旋转角度,单位是 deg;还有旋转的中心点;我这边是把 scene 开放出去
自定义配置项写在组件下面的 configView 目录中,别写在通用目录里面;然后在 viewConfig.js 中引入进来使用
目前是封装了 ElementUI
4、文本的配置项开放出来
待解决的问题
- 饼图为什么是透明的?因为 MeshPhongMaterial 用了混合模式:blending: AdditiveBlending,
- Canvas 画的文字为什么是放大模糊的?因为按照整个 canvas 的大小拉伸了
- 标注线需要是折线,且定位需要修改:拐点规则是什么?
- 为什么饼图中又变得很小很小?通过镜头缩放解决了
- (Hard)改为短视频组件的模式,接入平台
- 背景改为透明的:renderer.setClearColor
- 动画可以按帧数控制,使其匹配短视频平台的操控模式
- 需要支持自适应,因为页面宽度会变小(右侧有卡片挤压)
- (Hard)为什么初始 plane 的 x 不 rotate 就会出现锯齿?
- camera 的 z 和文本标签的位置关联关系是什么?现在一调整 camera 的 z,就对不齐了
- UI 还原度问题,比较严重
- 模糊的问题:是否是 DPR 相关?
- (Bug)饼图流入流出的顺序显示反了:扇形的绘制是和角度反向的
- 线条的动画效果:完成一半
- 文本标签的动画效果:完成一半
- 文本和标签的对齐问题
- 升上来的动画,可能有问题
- (Bug)缩放后,文本标签的位置不对的问题:应该是有镜头缩放的缘故,乘以这个比例即可;算了,问郑浩琦吧,别浪费时间了
- (Hard)去掉透视效果,不然看不出是 3D 立体的;是不是可以通过光照效果处理下?
- (Bug)标签位置不对的问题
- 数据改为二维数组
- 开放 label 的自定义格式化功能
- 顺序调整下,小单买入后面接特大单卖出
- 标签只显示 4 个
- 标签和文字的渐隐动画
- (Hard)相邻元素颜色重叠问题
- 还原 UI 样式效果
- 程序优化,去掉冗余代码,改为配置项暴露出来
- (Bug)饼图透视问题
- (Bug)黄线和饼图相互遮盖的问题
- (Bug)连线的宽度 lineWidth 不生效
- 动画加入线性变化:得搞个轻量的动画机制吧
- (Hard)线条支持生长效果
- 导出功能
相邻图形渲染异常的问题
我单独画了个 ExtrudeGeometry,没问题,说明是其他因素导致的。
逐个删除试试。
× 光源
是不是 ExtrudeGeometry 没闭合的缘故?
最终发现是 Material 的这个配置导致的:
1 | |
Canvas 文字拉伸问题
- Canvas 高度有用
Too many active WebGL contexts. Oldest context will be lost.
重用 renderer
(TODO)黑屏和卡顿:THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false
动画画着画着,页面突然一黑,然后就会出现这个报错,图像也没了,感觉整个渲染器都崩了。
这种情况出现在我不绘制饼图,只绘制文本标签和线条的情况下。
而且也会卡顿,似乎只要绘制 3D就会卡顿。线条、饼图都不绘制,居然也会卡,也会黑屏。
通过 WebGLRenderer.info 查看到 textures 的数量一直在增加,但是我程序中并没有明确使用某个 Texture;且内存观察到也没增加:
1 | |
经过调试,发现是这几行导致的:
1 | |
把 scene 和 camera 置为 null 的这 2 行删除后,就恢复正常了,打印 renderer.info 查看,textrures 也没有增长了,稳定在 2.
注意:单独注释掉 this.scene = null;会报错;单独注释掉 this.camera = null;卡顿的现象仍然会出现。这里还没弄清楚。
性能优化
15-30 帧,看起来不流畅,播着播着还卡住不动了。
缓存了 renderer,并递归销毁了 scene 及其子元素,帧数上升到接近 60,但是有时候会出现黑屏的问题
通过 WebGLRenderer.info 查看到 textures 的数量一直在增加,但是我程序中并没有明确使用某个 Texture;且内存观察到也没增加,估计这个不影响
内存泄漏问题
预览帧数过低的问题
Vue 的问题也说不过去,因为我本地也是 Vue 项目,但是很顺畅,至少崩掉之前很流畅。
播放着是不是卡顿的问题
不绘制饼图元素也会卡顿
服务端录制模糊的问题
我们服务端录制的时候,会将页面放大后进行录制,会出现 Canvas 模糊的问题。
这种情况,需要给渲染器设置下 devicePixelRatio。
我们会在 url 中通过 scale 参数对页面进行缩放,这个 scale 参数会传递到组价内部,我们获取该参数后,直接将这个放大值设置到 renderer 中即可。
WebGLRenderer 渲染器这样设置:
1 | |
注意,这个值设置得过大也是没有用的,因为当前渲染设备的 DPR 是有上限的。比如 iphone 一个像素的大小实际上是用 2 个像素点渲染的,那么这个值即使设置为 10,也和设置为 2 的效果是一样的。
CSS2DRenderer 因为是 DIV 绘图,直接根据 DPR 缩放即可,按理说不用设置。但是网上也有一种说法:
CSS2DRenderer 计算对象位置是默认设备像素比为 1 的情况,如果想要适配不同机型,需要做一次转换.
1 | |
https://www.cnblogs.com/minnong/p/11726023.html
经验教训
数据和绘图没有分离开
这会导致很难模块化,比如 line 中进行了线条终点的坐标计算,而这个坐标 label 又会用到,这样就很难将 line 和 label 独立为不关联的 2 个模块了。
而 line 和 label 的实现方式不一样,这导致我不能直接将他们放入一个 group,否则后面的显示隐藏就不好处理了。
UI 组件的使用注意事项
文本用我们自定义的组件(ths-input)
数字用 InputNumber 计数器(el-input-number)
只有绑定到 enstyle 的属性,才能被补间动画应用到
以渲染管线的思路来设计程序流程
其实渲染管线也是数据驱动的理念,都是先计算好数据,然后输出渲染。
那么我们的程序就应该有这几个 API:
1 | |
不变的初始化方法
会变的绘图方法
属性分类
再结合流程图编码,这样就很顺利了
初始化元素应该放在 init 方法中
(MIT)下一次的开发流程
下次开发组件,不能像这次这样乱来了,必须得有一个流程和设计。
需求分析
有经验的开发人员,针对需求内容,进行技术方案的初步设计,特别要注意动画部分,这是最难确定清楚、耗费工作量最多的。
最好能等设计师动画制作完成,能看到实际效果,再去评估,否则估算出来的时间极不准确,可能得乘以 π。
方案设计
提供组件开发的基类和常用工具库,将每一个组件进行图元拆分,画出组合图,以小模块为单位评估工作量。
同时整理需要开放出来的配置项,明确写下来,包括具体要开放哪些属性、每个属性的范围、针对属性变更要实现什么代码逻辑等。
还有组件的数据格式,必须是二维数组,这个前期一定要传递到位,不然后期修改很麻烦。
另外要明确我们需要编写哪些工具,来提升开发和调试的效率。
编码阶段
一定要每日集成,产品和设计师只有看到效果,才能提出反馈意见。
其他资料
别人画的饼图:
https://3dpie.peterbeshai.com/?x0=true&x3=false&x2=true&x1=true
带有动画,很不错,数字也很动感。
这是 github:
https://github.com/pbeshai/3dpie
牛逼的思路,居然是用 D3 计算出 pie 的数据,然后根据 path 的 d 标签来画的。