注意: 只有实现思路和代码,无法开箱即用。
1. 使用背景
收到个任务,制作echarts大屏,有个模块需要使用立体环图,在echarts官网找了一圈没有找到如何实现,网上资料甚少,最后只能叫设计改成普通图了。任务完成后自己学习下如何实现。
需求图:
我暂时实现的样子 - label标签还没有想到应该怎么实现,希望各位大佬知道的能分享下经验
2. 学习视频及文档
1: three.js教程-从入门到入门 视频短讲解挺清楚的,开了两倍速大概了解下什么是Three.js
2. Three.js中文网 比较详细
3. Three官网 事例多
3. 实现流程
3.1 创建好THREE基本环境
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
//场景
const scene = new THREE.Scene()
//相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(0, 50, 100);
//渲染器
const renderer = new THREE.WebGLRenderer()
document.querySelector('#app').appendChild(renderer.domElement)
renderer.setSize(window.innerWidth, window.innerHeight)
//控制器让画面可以拖动
const controls = new OrbitControls(camera, renderer.domElement);
//渲染场景
function render() {
renderer.render(scene, camera)
requestAnimationFrame(render)
}
render()
3.2 单一立体扇形实现
使用到
THREE.Shape()
和THREE.ExtrudeGeometry()
创建。(在官方事例中进行修改)
const heartShape = new THREE.Shape();
//通过两个弧形形成一个扇形平面---具体也没明白为啥可以,就是写了之后发现竟然实现了
//外层弧形
heartShape.absarc(0, 0, 20, 0, Math.PI/2)
//内层弧形
heartShape.absarc(0, 0, 10, Math.PI/2, 0, true)
const extrudeSettings = { depth: 8, bevelEnabled: true, bevelSegments: 2, steps: 2, bevelSize: 1, bevelThickness: 1 };
//使用 ExtrudeGeometry 把扇形平面拉伸成立体状
const geometry = new THREE.ExtrudeGeometry( heartShape, extrudeSettings );
const mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
3.3 计算每个数据所占的角度大小。
// 假设数据是这样的
const chartData = [
{ label: '星期一', value: 40 },
{ label: '星期二', value: 80 },
{ label: '星期三', value: 20 },
]
//第一步 获取所有值的和
const max = chartData.reduce((pre, item) => { return pre + item.value }, 0)
//第二步 设置图形初始角度为0
let startdeg = 0
chartData.forEach((item, index) => {
// 每一个图形的开始角度
let start = startdeg
// 每一个图形的结束角度 = 初始角度+所占比例的角度
let end = startdeg + 2*Math.PI*(item.value/max)
... 有开始角度和结束角度了 用3.2方式绘制图形
// 更新 图形初始化角度
startdeg = end
})
至此 立体饼状图就能出来了。
3.4 每个饼状图上的百分比标签。
使用的是CSS2DRenderer
也就是用DOM+CSS方式。
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
const labelDiv = document.createElement('div');∂
labelDiv.innerHTML = `<div style='color: #fff'>50%</div>`
const earthLabel = new CSS2DObject(labelDiv);
earthLabel.position.set(10, 0, 0)
// earthLabel.center.set(0, 0, 0);
scene.add(earthLabel);
// css2d渲染
let labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
document.querySelector('#app').appendChild(labelRenderer.domElement);
//把相机场景放入渲染
labelRenderer.render(scene, camera);
3.5 每个百分比标签位置
下载最后面的代码 参考下吧
4. 代码分享
gitCode仓库 three实现立体环形图
代码总共100多行,后面要是有什么思路继续完善一下。
如本文对你10分帮助,就赏个10分(一毛)吧