threejs+d3js 绘制3D动态数据图
效果图如下:
很早之前就想研究echart图表如何在threejs中呈现,在研究threejs形状Shape代码的时候终于弄明白了几何体中形状的绘制,再结合D3js这个强大的数据处理库,终于可以做出类似澎湃数据新闻这种效果了(http://h5.thepaper.cn/html/zt/2020/09/ybw/index.html)。
首先我们在拿到数据的时候,根据数据的特征,绘制3D坐标轴。
代码如下:
var time_line_points = []
var time_line_geometry;
time_line_points.push(vector(-scene_size / 2 + scene_size / 268 * 105, 2, -scene_size / 2))
time_line_points.push(vector(-scene_size / 2 + scene_size / 268 * 105, 2, scene_size / 2))
//time_line
time_line_material = new THREE.LineBasicMaterial({
color: "#F86E64",
linewidth: 6
})
time_line_geometry = new THREE.BufferGeometry().setFromPoints(time_line_points);
time_line = new THREE.Line(time_line_geometry, time_line_material)
time_line.name = "tg";
time_line.visible = false;
//line_edge
edge_points.push(vector(-plane_size / 2, 0, plane_size / 2));
edge_points.push(vector(plane_size / 2, 0, plane_size / 2));
edge_points.push(vector(plane_size / 2, 0, -plane_size / 2));
edge_points.push(vector(plane_size / 2, plane_size / 2, -plane_size / 2));
line_edge_material = new THREE.LineBasicMaterial({
color: "#fff",
linewidth: 2
});
line_edge_geometry = new THREE.BufferGeometry().setFromPoints(edge_points);
line_edge = new THREE.Line(line_edge_geometry, line_edge_material);
然后我们用D3处理数据:
d3.csv("./assets/data.csv").then(function(values) {
oversea = values;
oversea_data = oversea.filter(function(d) {
return d.stats_type == "test"
}).map(function(d) {
return {
"name": d.name,
"new": d3.values(d).map(function(dd) {
return Number(dd);
}).reverse(),
"date": d3.keys(d).filter(function(dd) {
return dd != "name" && dd != "area" && dd != "stats_type";
}),
"test_total": d3.sum(d3.values(d).map(function(dd) {
return Number(dd);
})),
"data": [],
"daily": []
}
})
date_seq = oversea_data[0].date.reverse();
date_seq.splice(date_seq.indexOf(stop_time), date_seq.length);
for (let i = 0; i < oversea_data.length; i++) {
for (let index = 0; index < date_seq.length; index++) {
oversea_data[i].data[index] = {
"date": date_seq[index],
"test": Number(oversea_data[i].new[index]),
};
}
}
oversea_data.sort(function(a, b) {
return d3.descending(a.death_total, b.death_total)
})
下面是绘制数据图的关键代码:
shape = new THREE.Shape();
shape.moveTo(-scene_size / 2 + scene_size / date_seq.length, 0);
for (var i = 1; i < subset.data.length; i++) {
shape.lineTo(-scene_size / 2 + scene_size / date_seq.length * i, scale(subset.data[i].death));
}
shape.lineTo(scene_size / 2, 0);
shape_geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
shape_geometry.computeBoundingBox()
const color = 0xff0000;
const material2 = new THREE.MeshPhongMaterial({color});
shape = new THREE.Mesh(shape_geometry, material2);
scene.add(shape);
希望有一天可以做出下面这种效果来。http://www.georgeandjonathan.com/#5