我学习D3.js之旅的另一步......
我有一个简单的可重复使用的图表,我称之为“聚类图表”,而我正试图简单地更新一些值而不添加或减去任何元素。
这里有一个小提琴:http://jsfiddle.net/rolfsf/8bXAN/
图表脚本如下所示:
function clusterChart() {
var width = 500,
radiusAll = 90,
maxRadius = radiusAll - 5,
padding = 8,
height = 3 * (radiusAll*2 + padding),
startAngle = Math.PI / 2,
val = function(d) { return d; },
onTotalMouseOver = null,
onTotalClick = null,
onClusterMouseOver = null,
onClusterClick = null;
function chart(selection) {
selection.each(function(data) {
var cx = width / 2,
cy = height / 2,
stepAngle = 2 * Math.PI / data.Clusters.length,
outerRadius = 2*radiusAll + padding;
// Remove svg, if already exist
d3.select(this).select('svg').remove();
//cluster radius range and scale
var r = d3.scale.linear()
.domain([0, d3.max(data.Clusters, function(d){return d[1];})])
.range([50, maxRadius]);
// Add svg element
var svg = d3.select(this).append('svg')
.attr('class', 'cluster-chart')
.attr("viewBox", "0 0 " + width + " " + height )
.attr("preserveAspectRatio", "xMidYMin meet")
.attr('width', width)
.attr('height', height);
// Total group value
var totalCluster = svg.append('g')
.attr('class', 'total-cluster');
totalCluster.append('circle')
.attr('cx', cx)
.attr('cy', cy)
.attr('r', radiusAll)
.on('mouseover', onTotalMouseOver)
.on('click', onTotalClick);
totalCluster.append('text')
.attr('class', 'value')
.attr('x', cx)
.attr('y', cy + 4)
.text(val(data.Value));
totalCluster.append('text')
.attr('class', 'group-name')
.attr('x', cx)
.attr('y', cy + 16)
.text(val(data.Name));
// Clusters values
var cluster = svg.selectAll('g.cluster')
.data(data.Clusters)
.enter().append('g')
.attr('class', function(d, i) {
if(d[1] === 0){ return 'cluster empty'}
else {return 'cluster'}
});
cluster.append('circle')
.attr('cx', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
.attr('cy', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius; })
.attr("r", function (d, i) { return r(d[1]); })
.on('mouseover', function(d, i, j) {
//do something
if (onClusterMouseOver != null) onClusterMouseOver(d, i, j);
})
.on('mouseout', function() {
//do something
})
.on('click', function(d, i){ onClusterClick(d); });
cluster.append('text')
.attr('class', 'value')
.attr('x', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
.attr('y', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius - 4; })
.text(function(d) { return val(d[1]); });
cluster.append('text')
.attr('class', 'group-name')
.attr('x', function(d, i) { return cx + Math.cos(startAngle + stepAngle * i) * outerRadius; })
.attr('y', function(d, i) { return cy + Math.sin(startAngle + stepAngle * i) * outerRadius + 16; })
.text(function(d) { return val(d[0]); });
$(window).resize(function() {
var w = $('.cluster-chart').width(); //make this more generic
svg.attr("width", w);
svg.attr("height", w * height / width);
});
});
}
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.val = function(_) {
if (!arguments.length) return val;
val = _;
return chart;
};
chart.onClusterClick = function(_) {
if (!arguments.length) return onClusterClick;
onClusterClick = _;
return chart;
};
return chart;
}
我将图表称为:
d3.select('#clusters')
.datum({
Name: 'Total Widgets',
Value: 224,
Clusters: [
['Other', 45],
['FooBars', 30],
['Foos', 50],
['Bars', 124],
['BarFoos', 0]
]
})
.call( clusterChart() );
最终,数据将来自json文件,但现在它已经存在于函数中。
假设我想在单击#doSomething按钮时更新值,更新的数据如下所示:
.datum({
Name: 'Total Widgets',
Value: 150,
Clusters: [
['Other', 25],
['FooBars', 25],
['Foos', 25],
['Bars', 75],
['BarFoos', 0]
]
})
如何更新这些数据,并在半径变化时进行了很好的转换?
更新:好的,我意识到一行几乎消除了我“更新”图表的能力。
// Remove svg, if already exist
d3.select(this).select('svg').remove();
相反,我应该做类似的事情:
// Add svg element
var svg = d3.select(this).selectAll('svg')
所以我不会删除整个图表。但即使如此,我也不知道如何使用新数据进行更新。
任何线索?