问题描述
我有一个名为graphData
的对象数组(大小各不相同).每个元素都包含创建d3图所需的所有信息,如果我通过硬编码(即graphdata[0]
,graphdata[1]
等)访问graphData
元素,则能够成功绘制这些图.
I've got an array of objects called graphData
(size varies). Each element contains all the information required to create a d3 graph, and I am able to successfully draw the graphs if I access graphData
elements by hardcoding (i.e. graphdata[0]
, graphdata[1]
etc).
当我尝试使用for循环为每个元素生成一个图形时,问题就来了.环顾了stackoverflow和网络,但是解决方案都是关于生成固定数量的多个图,而不是动态生成多个图.
The problem comes when I attempt to use a for loop to generate one graph for each of the elements. Looked around stackoverflow and the web, but the solutions are all about generating a fixed number of multiple graphs, not generating multiple graphs dynamically.
下面是我的用于生成一个图形的工作代码.自动生成x个图形的推荐方法是什么?
Below is my working code for generating one graph. What is the recommended way to generate x number of graphs automatically?
var graphData = data.graph;
var RADIUS = 15;
var edgeData = graphData[0].edges;
var nodeData = graphData[0].nodes;
var stageNum = graphData[0].stage;
var xScale = d3.scale.linear()
.domain([d3.min(edgeData, function (d) {
return d.start[0];
}),
d3.max(edgeData, function (d) {
return d.start[0];
})])
.range([50, w - 100]);
var yScale = d3.scale.linear()
.domain([d3.min(edgeData, function (d) {
return d.start[1];
}),
d3.max(edgeData, function (d) {
return d.start[1];
})])
.range([50, h - 100]);
var rScale = d3.scale.linear()
.domain([0, d3.max(edgeData, function (d) {
return d.start[1];
})])
.range([14, 17]);
// already have divs with classes stage1, stage2... created.
var svg = d3.select(".stage" + stageNum).append("svg")
.attr({"width": w, "height": h})
.style("border", "1px solid black");
var elemEdge = svg.selectAll("line")
.data(edgeData)
.enter();
var edges = elemEdge.append("line")
.attr("x1", function (d) {
return xScale(d.start[0]);
})
.attr("y1", function (d) {
return yScale(d.start[1]);
})
.attr("x2", function (d) {
return xScale(d.end[0]);
})
.attr("y2", function (d) {
return yScale(d.end[1]);
})
.attr("stroke-width", 2)
.attr("stroke", "black");
var elemNode = svg.selectAll("circle")
.data(nodeData)
.enter();
var nodes = elemNode.append("circle")
.attr("cx", function (d) {
return xScale(parseInt(d.x));
})
.attr("cy", function (d) {
return yScale(parseInt(d.y));
})
.attr({"r": rScale(RADIUS)})
.style("fill", "yellow")
.style("stroke", "black");
推荐答案
Mike Bostock建议将图表实现为可重用使用方法关闭.如果您愿意,这将是您的理想选择
Mike Bostock recommends implementing charts as reusable closures with methods. This would be an ideal implementation in your case as you want to have
- 具有不同数据的多个图
- 可能会重新加载新数据(希望这是动态的意思吗?)
粗略地讲,您想要做的就是将上面的代码包装到一个函数中,就像Mike在上面的帖子中描述的一样,然后将data
作为关闭的属性.因此,这是一些严重被黑的代码:
In broad strokes, what you want to do is wrap your code above into a function in very much the same way Mike describes in the post above, and then have data
be an attribute of your closure. So here is some badly hacked code:
// your implementation here
var chart = function(){...}
var graphData = d3.json('my/graphdata.json', function(error, data){
// now you have your data
});
// let's say you have a div called graphs
var myGraphs = d3.select('.graphs')
.data(graphData)
.enter()
.append('g')
//now you have g elements for each of your datums in the graphData array
//we use the saved selection above and call the chart function on each of the elements in the selection
myGraphs.call(chart);
//note that internally in your `chart` closure, you have to take in a selection
//object and process it(data is already bound to each of your selections from above):
function chart(selection) {
selection.each(function(data) {
//...
这里还有更多有关该主题的好读物.
这篇关于动态生成多个d3 svg图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!