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_linetime_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_edgeedge_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
