2015-09-08 2 views
3

У меня есть массив объектов, называемый graphData (размер варьируется). Каждый элемент содержит всю информацию, необходимую для создания графика d3, и я могу успешно рисовать графики, если я получаю доступ к элементам graphData путем жесткого кодирования (то есть graphdata[0], graphdata[1] и т. Д.).Динамическое создание нескольких графиков dv svg

Проблема возникает, когда я пытаюсь использовать цикл 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"); 

ответ

2

Mike Bostock рекомендует implementing charts as reusable closures with methods. Это было бы идеальной реализация в вашем случае, как вы хотите, чтобы иметь

  • нескольких графиков с различными данными
  • потенциалом перезарядки с новыми данными (надеюсь, это то, что вы имеете в виду динамическими?)

В широких штрихах то, что вы хотите сделать, - это превратить ваш код в функцию таким же образом, как описывает Майк в сообщении выше, а затем атрибут вашего закрытия будет 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) { 
//... 

Вот некоторые более good reading on the topic.

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. 

}); 
+0

Что делать, если мы хотим, чтобы пересмотреть данные, используемые для каждого элемента? D3 уже предоставляет инструменты, чтобы избежать хакерских циклов. Это буквально **, что он был построен, чтобы делать! Это даже в [пояснении к объединению] (http://bost.ocks.org/mike/join/): «Вместо того, чтобы сообщать D3, как что-то сделать, скажите D3, что вы хотите». Я бы уклонился от этого - особенно при работе с несколькими графиками. –

+0

Да, я согласен с тобой. но проблема была нарушена для цикла. Я попытался это исправить. Ваш подход намного лучше, чем подход в вопросе. +1 для этого. – Fawzan

+0

Все хорошо. Как только я узнал, как сделать d3 моей грязной работой, я никогда не хотел возвращаться. :) –

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'); 
Смежные вопросы