动态生成多个d3 svg图表

3
我有一个对象数组叫做graphData(大小不固定)。每个元素都包含创建d3图所需的所有信息,如果我通过硬编码访问graphData元素(即graphdata[0]graphdata[1]等),我可以成功绘制出图形。
问题在于,当我尝试使用for循环为每个元素生成一个图表时,出现了问题。查看了stackoverflow和网络,但解决方案都是关于生成固定数量的多个图表,而不是动态生成多个图表。
以下是我用于生成一个图表的工作代码。有没有推荐的方法来自动生成x个图表?
   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");
3个回答

3

Mike Bostock建议使用方法将图表实现为可重用的闭包(implementing charts as reusable closures with methods)。在您的情况下,这将是一种理想的实现,因为您希望拥有:

  • 具有不同数据的多个图表
  • 可能重新加载新数据(希望这就是您所说的动态?)

总体上,您想要做的是将上面的代码封装到一个函数中,就像Mike在上面的帖子中描述的那样,然后让data成为您的闭包属性。因此,以下是一些糟糕的代码:

// 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) {
//...

这里有更多关于该主题的好阅读材料


1
好的,您可以尝试以下方法。
var graphData = data.graph;

//forEach will return each element for the callback, you can then make use  of the e1 to draw the graph.
graphData.forEach(function(e1){


   //graph code goes here.

});

如果我们想要修改每个元素使用的数据怎么办?D3已经提供了避免hacky for循环的工具。这实际上就是它的设计初衷!甚至在连接的解释中都有这样的说明:“不要告诉D3如何做某事,而是告诉D3你想要什么”。我会避免这样做 - 特别是在处理多个图表时。 - Max Alcala
是的,我同意你的观点。但问题在于for循环出现了错误。我试图修复它。你的方法比问题中的方法好得多。给你点赞。 - Fawzan
一切都很好。一旦我学会了如何让d3来完成我的脏活,我就再也不想回去了。 :) - Max Alcala

1
提供这个作为您的源数组。
//it's just a single circle in 3, 4
var stuff = [3, 4];
var source = [ [stuff, stuff], [stuff] ];

一些关于数组的东西。
Array.prototype.max = function() {
    return Math.max.apply(null, this);
};

Array.prototype.min = function() {
    return Math.min.apply(null, this);
};

设置:

var dim = [];

source.forEach(function(elem){
    elem.forEach(function(circle){
        dim.push(circle.min());
        dim.push(circle.max());
    });
});

var min = dim.min();
var max = dim.max();

var x = d3.scale.linear()
        .domain([min, max])
        .scale([yourscale]);
var y = d3.scale.linear()
        .domain([min, max])
        .scale([yourscale]);

d3.select('body').selectAll('div')
    .data(source) //first step: a div with an svg foreach array in your array
    .enter()
    .append('div')
    .append('svg')
    .selectAll('circle') //second step: a circle in the svg for each item in your array
    .data(function(d){
        return d; //returns one of the [stuff] arrays
    }).enter()
    .append('circle')
    .attr('r', 5)
    .attr('cx', function(d){
        return x(d[0]);
    })
    .attr('cy', function(d){
        return y(d[1]);
    })
    .style('fill','blue');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接