如何使用D3.js的nest()和rollup()控制返回数据的顺序
问题描述
使用D3.js的.nest()和.rollup()处理数据数组时,统计数量正确,但返回顺序无法固定,每次操作都是随机的。期望实现固定倒序(从下到上显示Field-8、Field-7……Field-1)。
示例数据
[{ "num": 65, "value": "Field-1" }, { "num": 64, "value": "Field-8" }, { "num": 63, "value": "Field-7" }, { "num": 62, "value": "Field-7" }, { "num": 61, "value": "Field-8" }, { "num": 60, "value": "Field-6" }, { "num": 59, "value": "Field-6" }, { "num": 58, "value": "Field-7" }, { "num": 57, "value": "Field-8" }, { "num": 56, "value": "Field-5" }, { "num": 55, "value": "Field-4" }, { "num": 54, "value": "Field-4" }, { "num": 53, "value": "Field-4" }, { "num": 52, "value": "Field-5" }, { "num": 51, "value": "Field-3" }, { "num": 50, "value": "Field-5" }, { "num": 49, "value": "Field-5" }, { "num": 48, "value": "Field-1" }, { "num": 47, "value": "Field-5" }, { "num": 46, "value": "Field-4" }, { "num": 45, "value": "Field-4" }, { "num": 44, "value": "Field-1" }, { "num": 43, "value": "Field-5" }, { "num": 42, "value": "Field-5" }, { "num": 41, "value": "Field-3" }, { "num": 40, "value": "Field-1" }, { "num": 39, "value": "Field-5" }, { "num": 38, "value": "Field-5" }, { "num": 37, "value": "Field-5" }, { "num": 36, "value": "Field-5" }, { "num": 35, "value": "Field-4" }, { "num": 34, "value": "Field-1" }, { "num": 33, "value": "Field-3" }, { "num": 32, "value": "Field-2" }, { "num": 31, "value": "Field-5" }, { "num": 30, "value": "Field-1" }, { "num": 29, "value": "Field-1" }, { "num": 28, "value": "Field-1" }, { "num": 25, "value": "Field-1" }, { "num": 24, "value": "Field-2" }, { "num": 22, "value": "Field-2" }, { "num": 21, "value": "Field-1" }, { "num": 19, "value": "Field-4" }, { "num": 17, "value": "Field-3" }, { "num": 16, "value": "Field-3" }, { "num": 15, "value": "Field-1" }, { "num": 11, "value": "Field-2" }, { "num": 10, "value": "Field-3" }]
当前代码
$(function () { var chartData=getListData("ViewsTest"); var data=[]; for(var i=0;i<chartData.length;i++){ data.push({"num":chartData[i].ID, "value":chartData[i].Views});} initChart(data); }); function initChart(chartData){ data = chartData; var baseCount = d3.nest() .key(function(d) { return d.value; }) .rollup(function(v) { return v.length; }) .entries(data); for(var i =1; i<= baseCount.length; i++){ $('.vCount').append($('<div/>', { id: 'r' + i, 'class' : 'ansbox'})) } var mainDiv = d3.select("body") .attr("id", "main"); mainDiv.selectAll(".ansbox") .data(baseCount) .append("div") .attr("class", function(d,i) { return "views"}) .html(function (d) { return d.key + " : " + d.values ; }); }
解决方案
D3的.nest()默认按key的自然顺序排序,但早期版本中nest结果的顺序依赖JS对象遍历顺序(本身不稳定)。要实现固定倒序,只需在生成nest结果后添加自定义排序逻辑:
修改后的核心代码
在baseCount生成后追加排序:
var baseCount = d3.nest() .key(function(d) { return d.value; }) .rollup(function(v) { return v.length; }) .entries(data) // 提取Field后的数字,从大到小排序 .sort(function(a, b) { var numA = parseInt(a.key.split("-")[1]); var numB = parseInt(b.key.split("-")[1]); return numB - numA; });
完整修改后的initChart函数
function initChart(chartData){ data = chartData; var baseCount = d3.nest() .key(function(d) { return d.value; }) .rollup(function(v) { return v.length; }) .entries(data) .sort(function(a, b) { var numA = parseInt(a.key.split("-")[1]); var numB = parseInt(b.key.split("-")[1]); return numB - numA; }); for(var i =1; i<= baseCount.length; i++){ $('.vCount').append($('<div/>', { id: 'r' + i, 'class' : 'ansbox'})) } var mainDiv = d3.select("body") .attr("id", "main"); mainDiv.selectAll(".ansbox") .data(baseCount) .append("div") .attr("class", function(d,i) { return "views"}) .html(function (d) { return d.key + " : " + d.values ; }); }
说明
- 排序逻辑通过拆分
key字符串提取数字部分,转为整数后比较,实现Field-8到Field-1的倒序排列。 - 后续新增Field(如Field-9)时,该逻辑会自动适配,保持数字从大到小的顺序。
内容的提问来源于stack exchange,提问作者TonyT
相关产品推荐
相关产品推荐

