如何实现一个 3D 图表 #5375
xiaoiver posted onGitHub
伪 3D 和真 3D
Canvas2D / SVG 都可以实现伪 3D 效果。例如 zdog 和 vchart。下图为 vchart 的 3D Scatter Plot,使用 Canvas2D 渲染:
个人认为问题主要出在交互上,如果不考虑相机交互,伪 3D 通过投影变换实现相对简单。而以真 3D 的 plot.ly 和 echarts-gl 为例:
自底向上涉及渲染器(g-webgl)、组件库(GUI)、G2
渲染器及其插件
- g 提供相机能力
- g-webgl 提供基于 WebGL 的渲染能力,内置支持 2D 图形
- g-plugin-3d 提供 3D 图形扩展,包括 Geometry、Material 和光照
- g-plugin-control 提供 3D 场景下的相机交互
GUI Axis
特定组件使用到的 Line、Text(这个最重要)、Path 需要支持公告牌效果(永远面朝相机)
https://github.com/antvis/GUI/pull/304
@antv/coord
需要支持 Cartesian3D,在 Cartesian 基础上扩展 z 和 depth:
const coord = new Coordinate3D({
x: 0,
y: 0,
z: 0,
width: 100,
height: 50,
depth: 100,
transformations: [['cartesian3D']],
});
https://github.com/antvis/coord/pull/44
G2
在 G2 中 3D Scatter Plot 期望的用法(Spec)如下:
{
type: 'point3D', // 散点图
padding: 'auto',
data: {
type: 'fetch',
value: 'data/cars2.csv',
},
encode: {
x: 'Horsepower',
y: 'Miles_per_Gallon',
z: 'Weight_in_lbs', // z 通道
size: 'Origin',
color: 'Cylinders',
shape: 'sphere', // 使用 Sphere
},
scale: {
x: { nice: true },
y: { nice: true },
z: { nice: true },
},
coordinate: { type: 'cartesian3D', depth: 300 }, // 使用 Cartesian3D
axis: {
x: { gridLineWidth: 3 },
y: { gridLineWidth: 3 },
z: { gridLineWidth: 3 },
},
}
Mark
交互
Tooltip 天然支持
<img width="471" alt="截屏2023-08-03 上午10 28 07" src="https://github.com/antvis/G2/assets/3608471/222f4905-d46d-4138-a000-6ae8eb2d323a">
主要通过相机交互实现 Orbit 模式,固定视点旋转
可以支持 hover 时展示辅助线
<img width="376" alt="截屏2023-08-03 上午11 23 30" src="https://github.com/antvis/G2/assets/3608471/995a2124-6a8c-4865-b1ce-245e77dd198f">
支持渲染到多个画布
同一个画布中的图形都会受相机影响,例如下面的 legend 展示效果也随相机旋转发生了改变:
在 plot.ly 的实现中,图表主题使用 WebGL 渲染,而 legend 使用 SVG 渲染。