vlambda博客
学习文章列表

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 * 1052, -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