D3.js中Stream graph详解
2017-12-15 10:02
190 查看
Stream graph
聊一聊Stream graph,流图。流图是围绕中心轴线进行布局的一种堆叠面积图。——维基百科
由于流图可绕中心轴流动,从而呈现出像河流一样的形状。
见图如下:
接下来详细解释D3.js官网中是怎么实现这张图的。
index.html——源码
<!DOCTYPE html> <meta charset="utf-8"> <title>Streamgraph</title> <style> button { position: absolute; left: 10px; top: 10px; } </style> <button onclick="transition()">Update</button> <svg width="960" height="500"></svg> <script src="https://d3js.org/d3.v4.min.js"></script> <script> var n = 20, // number of layers 层的总数 m = 200, // number of samples per layer 每层的样本数目 k = 10; // number of bumps per layer 每层的颠簸总数 // d3.stack()用来生成一个新的堆栈生成器 // stack.keys(d3.range(n))用来生成一个以0到n-1为主键的堆栈生成器 // stack.offset(),默认情况下stacked series的baseline为0, // 然而我们也可以配置stack generator的offset来达到不同的baseline效果。这里设置的offset为 // d3.stackOffsetWiggle 是专门用于流图,设置流图堆栈的offset,通过移动基线来减少层的加权摆动 var stack = d3.stack().keys(d3.range(n)).offset(d3.stackOffsetWiggle), // bumps(m, k)用来返回颠簸k次的长度为m的数组 // d3.range(n).map(function() { return bumps(m, k); })用来生成n*m的矩阵 // d3.transpose()用来对生成的n*m的矩阵进行转置 // 因此layers0用来存储堆栈布局后的数据,其中有n个系列,每个系列有m个数据点,每个数据点 // 有一个最低点和顶点值,形如[lower,upper]这样的形式,lower和upper分别用来定义基线和顶线 layers0 = stack(d3.transpose(d3.range(n).map(function() { return bumps(m, k); }))), //layers1和layers0的计算方法一样,但是值由于随机函数的影响,会有所不同,这里计算layers1 // 主要是用来显示左上角“update”按钮对应的切换效果 layers1 = stack(d3.transpose(d3.range(n).map(function() { return bumps(m, k); }))), // 将layers1和layers0两个矩阵连接起来 layers = layers0.concat(layers1); // 获取svg元素 var svg = d3.select("svg"), // 获取svg元素的宽度 width = +svg.attr("width"), // 获取svg元素的高度 height = +svg.attr("height"); // 定义x轴比例尺 var x = d3.scaleLinear() // 定义定义域 .domain([0, m - 1]) // 定义值域 .range([0, width]); // 定义y轴比例尺 var y = d3.scaleLinear() // 定义定义域 .domain([d3.min(layers, stackMin), d3.max(layers, stackMax)]) // 定义值域 .range([height, 0]); // 定义一个感知彩虹颜色函数z() var z = d3.interpolateCool; // d3.area()是一个区域生成器,区域通过两条线来界定 // d3.area().y0()定义了base line; // d3.area().y1()定义了top line; // d3.area().x()定义了x坐标,其中base line和top line使用的是相同的x坐标 var area = d3.area() .x(function(d, i) { return x(i); }) .y0(function(d) { return y(d[0]); }) .y1(function(d) { return y(d[1]); }); // 绘制面积区域,通过path元素来绘制 svg.selectAll("path") // 绑定数据 .data(layers0) .enter().append("path") // 通过area()函数来为path元素生成绘制所需的数据 .attr("d", area) // 设置填充色,通过z()颜色函数来获取 .attr("fill", function() { return z(Math.random()); }); // 获取堆栈数据矩阵的最大值 function stackMax(layer) { // 这里取d[1],是因为对于每个点d来说,d[1]大于d[0],因为d[0]是低点、d[1]是高点 return d3.max(layer, function(d) { return d[1]; }); } // 获取堆栈数据矩阵的最小值 function stackMin(layer) { // 这里取d[0],是因为对于每个点d来说,d[0]小于d[1],因为d[0]是低点、d[1]是高点 return d3.min(layer, function(d) { return d[0]; }); } // 定义左上角 “update”按钮的动作动画 function transition() { var t; // 获取path元素,并在一定的持续时间内重新绘制 d3.selectAll("path") // 这里绑定的数据t,是layers1和layers0之间相互切换 .data((t = layers1, layers1 = layers0, layers0 = t)) .transition() // 动画过渡持续时间 .duration(2500) // 动画最终到达的状态,这里的area是切换后的数据所计算的新的值 .attr("d", area); } // Inspired by Lee Byron’s test data generator. // 该方法用于生成长度为n的数组,其中通过m次颠簸,即调用dump(a,n)方法来变换a数组,最终返回变换后的a数组 function bumps(n, m) { var a = [], i; for (i = 0; i < n; ++i) a[i] = 0; for (i = 0; i < m; ++i) bump(a, n); return a; } // 该方法通过一定的随机数的运算来变换数组a的值 function bump(a, n) { var x = 1 / (0.1 + Math.random()), y = 2 * Math.random() - 0.5, z = 10 / (0.1 + Math.random()); for (var i = 0; i < n; i++) { var w = (i / n - y) * z; a[i] += x * Math.exp(-w * w); } } </script>
至此,流图的详解完毕。其中比较难的就是堆栈数据的计算比较绕,但是,幸好d3有现成的强大的数据处理方法,比如方便的二维矩阵的转置d3.transpose方法等。
相关文章推荐
- Js动态创建div
- 对“价格”数字的一段JS控制
- JS中number数据类型
- Js 定时器
- 通过js判断打开页面的手机浏览器类型
- 用JS来获取地址栏的属性值;
- AJAX解析XML(JS代码)
- js提交表单到后台,中文乱码问题。
- JS生成某个范围的随机数【四种情况详解】
- js设置请求头格式
- wxapp后台表单js简略总结示例(点击下拉框的一些改变)
- js向上无缝滚动,网站公告效果 具体代码
- js 日期,时间函数 及相关运算大全
- js事件监听器用法实例详解
- JS组件Bootstrap实现弹出框和提示框效果代码
- js在asp页面上实现定时输出变量a的值的方法
- JS HTML DOM
- JS中void(0)的含义
- js实现密码强度检测
- JS 倒计时