D3.js v5.0 主题河流
emmm其实写到这里的话也差不多写完了基本的图形实现。因为先接触的v3.0+版的D3,现在是v5.0+的,写法上差别比较大,加上全是英文的API真的是硬伤。但是实现思路还是差不多的。有写错的请指正。有写的不好的地方请忽略。
对于这个主题河流图,应该这么叫?
我最开始的想法
是和堆栈图联系起来的,想法是使用区域转换器d3.area()
所以有大佬写出来的话,希望可以指导一下。
老规矩,先看图。
import * as d3 from 'd3';export default function stackRect(id) {(() => {d3.select(id).selectAll('svg').remove();})();const height = 800;const width = 800;const padding = {left: 100,right: 100,top: 100,bottom: 100,};const axisHeight = height - padding.top - padding.bottom;const axisWidth = width - padding.left - padding.right;const z = d3.interpolateCool;// 画布const svg = d3.select(id).append('svg').attr('width', width).attr('height', height);const n = 10; // 层的总数const m = 50; // 每层的样本数目const k = 50; // 每层的颠簸总数const stack = d3.stack().keys(d3.range(n)).offset(d3.stackOffsetWiggle);const layers0 = stack(d3.transpose(d3.range(n).map(function() {return bumps(m, k);})));const layers1 = stack(d3.transpose(d3.range(n).map(function() {return bumps(m, k);})));// 将layers1和layers0两个矩阵连接起来const layers = layers0.concat(layers1);// 定义x轴比例尺const x = d3.scaleLinear().domain([0, m - 1]).range([0, axisWidth]);// 定义y轴比例尺const y = d3.scaleLinear()// 定义定义域.domain([d3.min(layers, stackMin), d3.max(layers, stackMax)])// 定义值域.range([axisHeight, 0]);const area = d3.area().x(function(d, i) {return x(i);}).y0(function(d) {return y(d[0]);}).y1(function(d) {return y(d[1]);});svg.selectAll('path').data(layers0).enter().append('path').attr('d', area).attr('fill', function() {return z(Math.random());});// 获取堆栈数据矩阵的最大值function stackMax(layer) {return d3.max(layer, function(d) {return d[1];});}// 获取堆栈数据矩阵的最小值function stackMin(layer) {return d3.min(layer, function(d) {return d[0];});}
}
// 该方法用于生成长度为n的数组,其中通过m次颠簸,即调用dump(a,n)方法来变换a数组,最终返回变换后的a数组
function bumps(n, m) {const a = [];let i;for (i = 0; i < n; i += 1) a[i] = 0;for (i = 0; i < m; i += 1) bump(a, n);return a;
}// 该方法通过一定的随机数的运算来变换数组a的值
function bump(a, n) {const x = 1 / (0.1 + Math.random());const y = 2 * Math.random() - 0.5;const z = 10 / (0.1 + Math.random());for (let i = 0; i < n; i += 1) {const w = (i / n - y) * z;// eslint-disable-next-line no-param-reassigna[i] += x * Math.exp(-w * w);}
}