2013-12-10 13 views
8

ho la seguente struttura:d3: Un sotto array di oggetti

[ 
    { 'length': 10, attributes: [1,2,3] }, 
    { 'length': 7, attributes: [1,3,4,5] }, 
    { 'length': 12, attributes: [3,5,7,9,10] }, 
] 

and I am doing the following: 


x = d3.scale.linear().domain([0, maxHeight]).range([50, w]), 
y = d3.scale.linear().domain([0, maxHeight]).range([h, 20]); 
z = d3.scale.linear().domain([0, maxHeight]).range([0, h - 20]); 

var chart = svg.selectAll("g.chart") 
    .data(items) 
    .enter() 
    .append("svg:g") 
    .attr("class", "chart"); 

chart.append("svg:rect") 
    .attr("fill", 'darkblue') 
    .attr("class", 'data') 
    .attr("x", function(d, i) { return x(i+1); }) 
    .attr("y", function(d, i) { return bottom - z(d['length']) + 15 }) 
    .attr("width", 4) 
    .attr("height", function(d, i) { return z(d['length']) - z(d['min']); }) 

Cosa vorrei fare è aggiungere cerchi su ciascuno di questi rettangoli che corrisponde agli attributi nella mia struttura. In sostanza, (per una 'voce'}, dovrei vedere qualcosa di simile:

<g class="chart"> 
    <rect fill="darkblue" class="data" x="626.1538461538462" y="15" width="6" height="530"></rect> 
    <circle cx="626.1538461538462" cy="(y1)" r="5" style="fill: #ffff00; stroke: #808080;"></circle> 
    <circle cx="626.1538461538462" cy="(y2)" r="5" style="fill: #ffff00; stroke: #808080;"></circle> 
    <circle cx="626.1538461538462" cy="(y3)" r="5" style="fill: #ffff00; stroke: #808080;"></circle> 
</g> 

L'unica cosa che posso pensare è looping sugli attributi e aggiungendo loro elemento per elemento:

for (z=0; z< 3; ++z) 
{ 
    chart.append("svg:circle") 
    .data(items[z]['attributes']) 
    .style("fill", 'yellow') 
    .style("stroke", "gray") 
    .attr("cx", function(d, i) { return x(i+1); }) 
    .attr("cy", function(d, i) 
    { 
     console.log(d); 
     return bottom - 15; 
    }) 
    .attr("r", 5); 
} 

c'è un modo migliore per fare questo?

risposta

6

Puoi creato una selezione nidificato invece di looping:

chart.selectAll("svg:circle") 
    .data(function(item) { return item.attributes; }) 
    .enter() 
    .append("svg:circle") 
    .style("fill", 'yellow') 
    .style("stroke", "gray") 
    .attr("cx", function(d, i) { return x(i+1); }) 
    .attr("cy", function(d, i) 
    { 
     console.log(d); 
     return bottom - 15; 
    }) 
    .attr("r", 5); 

Esempio:

Per mantenere la cx lo stesso per ogni parentrect, è possibile passare il parent_idx tramite

chart.selectAll("svg:circle") 
    .data(function(item, parent_idx) { 
     return item.attributes.map(function (attr_val) { 
       return { attr_val: attr_val, parent_idx: parent_idx }; 
      }); 
    }) 
    .enter() 
    .append("svg:circle") 
    .style("fill", 'yellow') 
    .style("stroke", "gray") 
    .attr("cx", function(d, i) { return x(d.parent_idx); }) 
    .attr("cy", function(d, i) 
    { 
     return y(d.attr_val); 
    }) 
    .attr("r", 5); 
+0

L'unico io Ho notato che i cerchi dovrebbero essere sulla stessa linea sull'asse x. Fondamentalmente questi cerchi dovrebbero essere sulla stessa linea (impilati in cima al rettangolo) – Paul

+0

@Paul ha aggiornato la risposta mantenendo 'cx' stesso per' rect'. –

+0

Questo è perfetto, funziona alla grande! Grazie! – Paul

3

è possibile utilizzare le selezioni nidificate. La selezione primaria creerà i gruppi, ogni gruppo avrà un elemento di dati legati ad esso.

var data = [ 
    {name: 'A', items: [1, 2]}, 
    {name: 'B', items: [2, 3, 4]} 
]; 

var cScale = d3.scale.category10() 
    .domain(d3.range(10)); 

var grp = svg.selectAll('g.main') 
    .data(data) 
    .enter() 
    .append('g') 
    .attr('class', 'main') 
    .attr('transform', function(d, i) { 
     return 'translate(0,' + i * 20 + ')'; 
    }); 

Quindi, è possibile creare una selezione nidificata, passando una funzione accessor al metodo dati. Ho un esempio con elementi rect, ma con cerchi è lo stesso:

grp.selectAll('rect') 
    .data(function(d) { return d.items; }) 
    .enter() 
    .append('rect') 
    .attr('x', function(d) { return 10 * d; }) 
    .attr('width', 8) 
    .attr('height', 10) 
    .attr('fill', function(d) { return cScale(d); }); 

Potete trovato l'articolo utile Nested Selections. Ho scritto un piccolo jsfiddle troppo: http://jsfiddle.net/pnavarrc/h2YVd/

Problemi correlati