大前端可视化实战:用 ECharts+Three.js 实现 3D 数据看板,从 0 到 1 的开发笔记
·
大前端可视化实战:用 ECharts+Three.js 实现 3D 数据看板
1. 技术选型与核心概念
- ECharts:处理 2D 数据可视化(折线图/柱状图等)
- Three.js:构建 3D 场景和模型
- 融合原理:将 ECharts 的 Canvas 渲染结果作为 Three.js 的纹理贴图,实现 2D/3D 混合渲染
2. 环境搭建
npm install echarts three.js --save # 基础依赖
npm install @tweenjs/tween.js --save # 动画过渡
3. 核心实现步骤
3.1 初始化 Three.js 场景
// 创建场景、相机、渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加光源
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(10, 20, 15);
scene.add(directionalLight);
3.2 创建 ECharts 实例作为纹理
// 创建隐藏的Canvas容器
const chartContainer = document.createElement('div');
chartContainer.style.width = '1024px';
chartContainer.style.height = '768px';
chartContainer.style.position = 'absolute';
chartContainer.style.left = '-9999px';
document.body.appendChild(chartContainer);
// 初始化ECharts
const chart = echarts.init(chartContainer);
chart.setOption({
xAxis: { type: 'category', data: ['Q1', 'Q2', 'Q3', 'Q4'] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [320, 450, 210, 380] }]
});
// 将ECharts Canvas转为Three.js纹理
const texture = new THREE.CanvasTexture(chart.getDom().querySelector('canvas'));
3.3 构建 3D 数据看板
// 创建3D面板几何体
const geometry = new THREE.PlaneGeometry(8, 6);
const material = new THREE.MeshPhongMaterial({
map: texture, // 绑定ECharts纹理
side: THREE.DoubleSide,
transparent: true
});
const panel = new THREE.Mesh(geometry, material);
panel.position.z = -10;
scene.add(panel);
// 添加3D标注点
const dataPoints = [
{ x: -3, y: 2, z: -8, value: 320 },
{ x: -1, y: 1.5, z: -8, value: 450 },
{ x: 1, y: 0.5, z: -8, value: 210 },
{ x: 3, y: 1.8, z: -8, value: 380 }
];
dataPoints.forEach(point => {
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(0.2, 16, 16),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
sphere.position.set(point.x, point.y, point.z);
scene.add(sphere);
});
3.4 实现交互联动
// ECharts点击事件传递到3D场景
chart.on('click', params => {
const index = params.dataIndex;
const point = dataPoints[index];
// 高亮对应3D点
new TWEEN.Tween(camera.position)
.to({ x: point.x * 1.5, y: point.y + 2, z: point.z + 5 }, 1000)
.easing(TWEEN.Easing.Quadratic.Out)
.start();
});
// Three.js射线拾取
renderer.domElement.addEventListener('click', event => {
const mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
const obj = intersects[0].object;
// 触发ECharts数据更新
chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: 1 });
}
});
4. 性能优化技巧
-
纹理更新策略:
// 仅当数据变化时更新纹理 function updateChartTexture() { texture.needsUpdate = true; chart.resize(); // 防止Canvas尺寸失真 } -
GPU 实例化渲染:对相同形态的 3D 标注点使用
THREE.InstancedMesh -
按需渲染:
function animate() { requestAnimationFrame(animate); TWEEN.update(); // 更新补间动画 if (needsRender) renderer.render(scene, camera); }
5. 效果增强方案
- 数据流动画:用 Three.js 的
ShaderMaterial实现流光特效 - 深度混合:通过
THREE.DepthTexture实现 2D/3D 元素层级交互 - 响应式适配:监听窗口大小变化,动态调整相机比例: $$ \text{aspect} = \frac{\text{window.innerWidth}}{\text{window.innerHeight}} $$
6. 部署注意事项
- 使用 Webpack 的
asset/resource处理 GLSL 着色器文件 - 通过
glTF格式导入复杂 3D 模型替代原生几何体 - 在 Vue/React 中封装为可复用组件:
<template> <div ref="container"></div> </template> <script> import { init3DDashboard } from './dashboard'; export default { mounted() { init3DDashboard(this.$refs.container); } } </script>
项目示例:
通过 ECharts 的丰富图表能力与 Three.js 的 3D 渲染结合,可构建出深度交互的沉浸式数据看板,适用于智慧大屏、实时监控等场景。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)