更新具有交互性的酒窝多系列图表中的系列顺序
update series order in dimple multi-series chart with interactivity
我创建了一个版本的 dimple 交互式图表(参见 dimplejs.org/advanced_examples_viewer.html?id=advanced_interactive_legends)
有两个系列:一个饼图系列和一个基于同一数据集的线系列。
jsfiddle: http://jsfiddle.net/jose_jimenez/1fvjvyvh/3/
var svg = dimple.newSvg("#chartContainer", 700, 500);
var mainSlicer = "classification";
var pies;
var lines;
//data here look for ------END OF DATA --------
var data = [{
"classification": "Undergraduate",
"residency": "Resident",
"year": 2006,
"head count": 14011
}, {
"classification": "Undergraduate",
"residency": "Domestic",
"year": 2006,
"head count": 6347
}, {
"classification": "Undergraduate",
"residency": "International",
"year": 2006,
"head count": 380
}, {
"classification": "Graduate",
"residency": "Resident",
"year": 2006,
"head count": 2693
}, {
"classification": "Graduate",
"residency": "Domestic",
"year": 2006,
"head count": 2075
}, {
"classification": "Graduate",
"residency": "International",
"year": 2006,
"head count": 1309
}, {
"classification": "Professional",
"residency": "Resident",
"year": 2006,
"head count": 1374
}, {
"classification": "Professional",
"residency": "Domestic",
"year": 2006,
"head count": 612
}, {
"classification": "Professional",
"residency": "International",
"year": 2006,
"head count": 14
}, {
"classification": "Postgraduate",
"residency": "Resident",
"year": 2006,
"head count": 825
}, {
"classification": "Postgraduate",
"residency": "Domestic",
"year": 2006,
"head count": 38
}, {
"classification": "Postgraduate",
"residency": "International",
"year": 2006,
"head count": 301
}, {
"classification": "Undergraduate",
"residency": "Resident",
"year": 2007,
"head count": 13808
}, {
"classification": "Undergraduate",
"residency": "Domestic",
"year": 2007,
"head count": 6695
}, {
"classification": "Undergraduate",
"residency": "International",
"year": 2007,
"head count": 404
}, {
"classification": "Graduate",
"residency": "Resident",
"year": 2007,
"head count": 2848
}, {
"classification": "Graduate",
"residency": "Domestic",
"year": 2007,
"head count": 2127
}, {
"classification": "Graduate",
"residency": "International",
"year": 2007,
"head count": 1246
}, {
"classification": "Professional",
"residency": "Resident",
"year": 2007,
"head count": 1338
}, {
"classification": "Professional",
"residency": "Domestic",
"year": 2007,
"head count": 642
}, {
"classification": "Professional",
"residency": "International",
"year": 2007,
"head count": 16
}, {
"classification": "Postgraduate",
"residency": "Resident",
"year": 2007,
"head count": 930
}, {
"classification": "Postgraduate",
"residency": "Domestic",
"year": 2007,
"head count": 53
}, {
"classification": "Postgraduate",
"residency": "International",
"year": 2007,
"head count": 302
}, {
"classification": "Undergraduate",
"residency": "Resident",
"year": 2008,
"head count": 13192
}, {
"classification": "Undergraduate",
"residency": "Domestic",
"year": 2008,
"head count": 7055
}, {
"classification": "Undergraduate",
"residency": "International",
"year": 2008,
"head count": 576
}, {
"classification": "Graduate",
"residency": "Resident",
"year": 2008,
"head count": 2932
}, {
"classification": "Graduate",
"residency": "Domestic",
"year": 2008,
"head count": 2164
}, {
"classification": "Graduate",
"residency": "International",
"year": 2008,
"head count": 1247
}, {
"classification": "Professional",
"residency": "Resident",
"year": 2008,
"head count": 1288
}, {
"classification": "Professional",
"residency": "Domestic",
"year": 2008,
"head count": 687
}, {
"classification": "Professional",
"residency": "International",
"year": 2008,
"head count": 22
}, {
"classification": "Postgraduate",
"residency": "Resident",
"year": 2008,
"head count": 994
}, {
"classification": "Postgraduate",
"residency": "Domestic",
"year": 2008,
"head count": 58
}, {
"classification": "Postgraduate",
"residency": "International",
"year": 2008,
"head count": 346
}];
// ------END OF DATA --------
function addSeries(chart) {
pies = chart.addSeries(slicer, dimple.plot.pie);
lines = chart.addSeries("classification", dimple.plot.line);
lines.lineMarkers = true;
lines.lineWeight = 5;
pies.radius = 20;
}
function createChart() {
data_attributes = Object.getOwnPropertyNames(data[0]);
['year', 'head count', mainSlicer].forEach(function(f) {
data_attributes.splice(data_attributes.indexOf(f), 1);
});
slicer = data_attributes[0];
var myChart = new dimple.chart(svg, data);
myChart.setBounds(60, 30, 500, 400)
var x = myChart.addCategoryAxis("x", ["year", mainSlicer]);
x.addOrderRule("year");
myChart.addMeasureAxis("y", "head count");
myChart.addMeasureAxis("p", "head count");
addSeries(myChart);
var myClassificationLegend = myChart.addLegend(550, 200, 150, 400, "left", lines);
var mySlicerLegend = myChart.addLegend(550, 300, 150, 400, "left", pies);
myChart.draw();
myChart.legends = [];
svg.selectAll("title_text")
.data(["Click legend to", "show/hide segments:"])
.enter()
.append("text")
.attr("x", 550)
.attr("y", function(d, i) {
return 160 + i * 14;
})
.style("font-family", "sans-serif")
.style("font-size", "10px")
.style('font-weight', 'bold')
.style("color", "Black")
.text(function(d) {
return d;
});
var classFilterValues = dimple.getUniqueValues(data, mainSlicer);
var slicerFilterValues = dimple.getUniqueValues(data, slicer);
var hiddenValues = [];
legendBits = myClassificationLegend.shapes;
legendBits[0] = legendBits[0]
.concat(mySlicerLegend.shapes[0]);
legendBits.selectAll('rect')
// Add a click event to each rectangle
.on("click", function(e) {
// This indicates whether the item is already visible or not
var hide = false;
var newClassificationFilters = [];
var newSlicerFilters = [];
var currentValue = e.aggField.slice(-1)[0];
// If the filters contain the clicked shape hide it
var whereIsIt = hiddenValues.indexOf(currentValue);
if (whereIsIt > -1) {
//it is hidden and needs to be shown.
hide = false;
hiddenValues.splice(whereIsIt, 1);
} else {
//it needs to be hidden
hide = true;
hiddenValues.push(currentValue);
}
classFilterValues.forEach(function(f) {
if (hiddenValues.indexOf(f) < 0) {
newClassificationFilters.push(f);
}
});
slicerFilterValues.forEach(function(f) {
if (hiddenValues.indexOf(f) < 0) {
newSlicerFilters.push(f);
}
});
// Hide the shape or show it
if (hide) {
d3.select(this).style("opacity", 0.2);
} else {
d3.select(this).style("opacity", 0.8);
}
// Filter the data
myChart.data = dimple.filterData(dimple.filterData(data, 'classification', newClassificationFilters), slicer, newSlicerFilters);
// Passing a duration parameter makes the chart animate. Without
// it there is no transition
myChart.draw(800, false);
});
}
function moveLegend(legend, offset) {
$(legend).find('text,rect').attr('y', parseInt($(f).find('text').attr('y')) + offset);
}
createChart();
我在饼图之后渲染了线条系列,因此线条最终位于饼图段的顶部。这允许访问线系列的鼠标悬停交互性。
当饼图段关闭然后打开时,它们返回时最终会在线段的顶部呈现。这可能是因为路径被添加到图表对象的末尾,而不是在线系列之前插入。最终他们阻止了线系列交互。
我尝试了几种解决方案,包括:
- 正在尝试将 pie.shapes.selectAll('path') 移回使用
d3.prototype.moveToBack 代码(参见 bl.ocks.org/eesur/4e0a69d57d3bfc8a82c2)
- 路径没有父节点或父节点没有子节点
- 尝试删除系列并使用 chart.series.slice 将其重新添加回来,或者使用 chart.series = [] 将两者都删除
- 后来的图表很乱,因为对象没有全部删除。
- 删除 pie.shapes 和/或 line.shapes 并没有多大帮助。
我可以通过隐藏所有行并将它们带回来(添加顺序使行回到顶部)。
我想跳入路径并使用 jquery 删除它们并重新添加它们,这感觉就像一个完全的 hack。谁有更优雅的方法来处理这个问题?
您需要在 chart.addSeries 中做的是将每个系列添加到 svg 中单独的 'g' 元素。目前,您的圆圈和线条都混合在同一个 g 元素中,因此最后添加的元素始终绘制在顶部。
例如
所以
<g>
<path>
<circle>
<path>
<newly appended circle>
</g>
变成
<g>
<circle>
<newly appended circle>
</g>
<g>
<path>
<path>
</g>
所有路径总是在所有圆之后绘制,因为 svg 只是按上面的顺序绘制元素
所以,事实证明,dimple 2.1.6 将任意数量系列的所有系列元素添加到相同的 <g>
元素,如@mgraham 指出的那样。值得称赞的是。 AlignAnalytics dimple repo 上的 Issue #203 显示其他人也有同样的问题。我分叉它并为每个系列添加了组。请参阅同一回购协议中的拉取请求#207。希望他们能把它拉进来。
我创建了一个版本的 dimple 交互式图表(参见 dimplejs.org/advanced_examples_viewer.html?id=advanced_interactive_legends) 有两个系列:一个饼图系列和一个基于同一数据集的线系列。
jsfiddle: http://jsfiddle.net/jose_jimenez/1fvjvyvh/3/
var svg = dimple.newSvg("#chartContainer", 700, 500);
var mainSlicer = "classification";
var pies;
var lines;
//data here look for ------END OF DATA --------
var data = [{
"classification": "Undergraduate",
"residency": "Resident",
"year": 2006,
"head count": 14011
}, {
"classification": "Undergraduate",
"residency": "Domestic",
"year": 2006,
"head count": 6347
}, {
"classification": "Undergraduate",
"residency": "International",
"year": 2006,
"head count": 380
}, {
"classification": "Graduate",
"residency": "Resident",
"year": 2006,
"head count": 2693
}, {
"classification": "Graduate",
"residency": "Domestic",
"year": 2006,
"head count": 2075
}, {
"classification": "Graduate",
"residency": "International",
"year": 2006,
"head count": 1309
}, {
"classification": "Professional",
"residency": "Resident",
"year": 2006,
"head count": 1374
}, {
"classification": "Professional",
"residency": "Domestic",
"year": 2006,
"head count": 612
}, {
"classification": "Professional",
"residency": "International",
"year": 2006,
"head count": 14
}, {
"classification": "Postgraduate",
"residency": "Resident",
"year": 2006,
"head count": 825
}, {
"classification": "Postgraduate",
"residency": "Domestic",
"year": 2006,
"head count": 38
}, {
"classification": "Postgraduate",
"residency": "International",
"year": 2006,
"head count": 301
}, {
"classification": "Undergraduate",
"residency": "Resident",
"year": 2007,
"head count": 13808
}, {
"classification": "Undergraduate",
"residency": "Domestic",
"year": 2007,
"head count": 6695
}, {
"classification": "Undergraduate",
"residency": "International",
"year": 2007,
"head count": 404
}, {
"classification": "Graduate",
"residency": "Resident",
"year": 2007,
"head count": 2848
}, {
"classification": "Graduate",
"residency": "Domestic",
"year": 2007,
"head count": 2127
}, {
"classification": "Graduate",
"residency": "International",
"year": 2007,
"head count": 1246
}, {
"classification": "Professional",
"residency": "Resident",
"year": 2007,
"head count": 1338
}, {
"classification": "Professional",
"residency": "Domestic",
"year": 2007,
"head count": 642
}, {
"classification": "Professional",
"residency": "International",
"year": 2007,
"head count": 16
}, {
"classification": "Postgraduate",
"residency": "Resident",
"year": 2007,
"head count": 930
}, {
"classification": "Postgraduate",
"residency": "Domestic",
"year": 2007,
"head count": 53
}, {
"classification": "Postgraduate",
"residency": "International",
"year": 2007,
"head count": 302
}, {
"classification": "Undergraduate",
"residency": "Resident",
"year": 2008,
"head count": 13192
}, {
"classification": "Undergraduate",
"residency": "Domestic",
"year": 2008,
"head count": 7055
}, {
"classification": "Undergraduate",
"residency": "International",
"year": 2008,
"head count": 576
}, {
"classification": "Graduate",
"residency": "Resident",
"year": 2008,
"head count": 2932
}, {
"classification": "Graduate",
"residency": "Domestic",
"year": 2008,
"head count": 2164
}, {
"classification": "Graduate",
"residency": "International",
"year": 2008,
"head count": 1247
}, {
"classification": "Professional",
"residency": "Resident",
"year": 2008,
"head count": 1288
}, {
"classification": "Professional",
"residency": "Domestic",
"year": 2008,
"head count": 687
}, {
"classification": "Professional",
"residency": "International",
"year": 2008,
"head count": 22
}, {
"classification": "Postgraduate",
"residency": "Resident",
"year": 2008,
"head count": 994
}, {
"classification": "Postgraduate",
"residency": "Domestic",
"year": 2008,
"head count": 58
}, {
"classification": "Postgraduate",
"residency": "International",
"year": 2008,
"head count": 346
}];
// ------END OF DATA --------
function addSeries(chart) {
pies = chart.addSeries(slicer, dimple.plot.pie);
lines = chart.addSeries("classification", dimple.plot.line);
lines.lineMarkers = true;
lines.lineWeight = 5;
pies.radius = 20;
}
function createChart() {
data_attributes = Object.getOwnPropertyNames(data[0]);
['year', 'head count', mainSlicer].forEach(function(f) {
data_attributes.splice(data_attributes.indexOf(f), 1);
});
slicer = data_attributes[0];
var myChart = new dimple.chart(svg, data);
myChart.setBounds(60, 30, 500, 400)
var x = myChart.addCategoryAxis("x", ["year", mainSlicer]);
x.addOrderRule("year");
myChart.addMeasureAxis("y", "head count");
myChart.addMeasureAxis("p", "head count");
addSeries(myChart);
var myClassificationLegend = myChart.addLegend(550, 200, 150, 400, "left", lines);
var mySlicerLegend = myChart.addLegend(550, 300, 150, 400, "left", pies);
myChart.draw();
myChart.legends = [];
svg.selectAll("title_text")
.data(["Click legend to", "show/hide segments:"])
.enter()
.append("text")
.attr("x", 550)
.attr("y", function(d, i) {
return 160 + i * 14;
})
.style("font-family", "sans-serif")
.style("font-size", "10px")
.style('font-weight', 'bold')
.style("color", "Black")
.text(function(d) {
return d;
});
var classFilterValues = dimple.getUniqueValues(data, mainSlicer);
var slicerFilterValues = dimple.getUniqueValues(data, slicer);
var hiddenValues = [];
legendBits = myClassificationLegend.shapes;
legendBits[0] = legendBits[0]
.concat(mySlicerLegend.shapes[0]);
legendBits.selectAll('rect')
// Add a click event to each rectangle
.on("click", function(e) {
// This indicates whether the item is already visible or not
var hide = false;
var newClassificationFilters = [];
var newSlicerFilters = [];
var currentValue = e.aggField.slice(-1)[0];
// If the filters contain the clicked shape hide it
var whereIsIt = hiddenValues.indexOf(currentValue);
if (whereIsIt > -1) {
//it is hidden and needs to be shown.
hide = false;
hiddenValues.splice(whereIsIt, 1);
} else {
//it needs to be hidden
hide = true;
hiddenValues.push(currentValue);
}
classFilterValues.forEach(function(f) {
if (hiddenValues.indexOf(f) < 0) {
newClassificationFilters.push(f);
}
});
slicerFilterValues.forEach(function(f) {
if (hiddenValues.indexOf(f) < 0) {
newSlicerFilters.push(f);
}
});
// Hide the shape or show it
if (hide) {
d3.select(this).style("opacity", 0.2);
} else {
d3.select(this).style("opacity", 0.8);
}
// Filter the data
myChart.data = dimple.filterData(dimple.filterData(data, 'classification', newClassificationFilters), slicer, newSlicerFilters);
// Passing a duration parameter makes the chart animate. Without
// it there is no transition
myChart.draw(800, false);
});
}
function moveLegend(legend, offset) {
$(legend).find('text,rect').attr('y', parseInt($(f).find('text').attr('y')) + offset);
}
createChart();
我在饼图之后渲染了线条系列,因此线条最终位于饼图段的顶部。这允许访问线系列的鼠标悬停交互性。
当饼图段关闭然后打开时,它们返回时最终会在线段的顶部呈现。这可能是因为路径被添加到图表对象的末尾,而不是在线系列之前插入。最终他们阻止了线系列交互。
我尝试了几种解决方案,包括:
- 正在尝试将 pie.shapes.selectAll('path') 移回使用
d3.prototype.moveToBack 代码(参见 bl.ocks.org/eesur/4e0a69d57d3bfc8a82c2)
- 路径没有父节点或父节点没有子节点
- 尝试删除系列并使用 chart.series.slice 将其重新添加回来,或者使用 chart.series = [] 将两者都删除
- 后来的图表很乱,因为对象没有全部删除。
- 删除 pie.shapes 和/或 line.shapes 并没有多大帮助。
我可以通过隐藏所有行并将它们带回来(添加顺序使行回到顶部)。
我想跳入路径并使用 jquery 删除它们并重新添加它们,这感觉就像一个完全的 hack。谁有更优雅的方法来处理这个问题?
您需要在 chart.addSeries 中做的是将每个系列添加到 svg 中单独的 'g' 元素。目前,您的圆圈和线条都混合在同一个 g 元素中,因此最后添加的元素始终绘制在顶部。
例如 所以
<g>
<path>
<circle>
<path>
<newly appended circle>
</g>
变成
<g>
<circle>
<newly appended circle>
</g>
<g>
<path>
<path>
</g>
所有路径总是在所有圆之后绘制,因为 svg 只是按上面的顺序绘制元素
所以,事实证明,dimple 2.1.6 将任意数量系列的所有系列元素添加到相同的 <g>
元素,如@mgraham 指出的那样。值得称赞的是。 AlignAnalytics dimple repo 上的 Issue #203 显示其他人也有同样的问题。我分叉它并为每个系列添加了组。请参阅同一回购协议中的拉取请求#207。希望他们能把它拉进来。