ho una struttura di dati di questo tipo (supporre che la struttura dei dati non è negoziabile):Combinando Capogruppo e dati nidificate con d3.js
data = {
segments : [
{x : 20, size : 10, colors : ['#ff0000','#00ff00']},
{x : 40, size : 20, colors : ['#0000ff','#000000']}
]};
Utilizzando la libreria javascript d3.js, mi piacerebbe disegnare quattro rettangoli, uno per ciascun colore in entrambi gli array colors
. Le informazioni da ciascuna voce nell'array segments
vengono utilizzate per disegnare i rettangoli corrispondenti a ciascun colore nella sua matrice color
. Ad esempio, I rettangoli rossi e verdi avrà una larghezza e un'altezza di 10. Il codice HTML risultante dovrebbe essere simile a questo:
<div id="container">
<svg width="200" height="200">
<g>
<rect x="20" y="20" width="10" height="10" fill="#ff0000"></rect>
<rect x="30" y="30" width="10" height="10" fill="#00ff00"></rect>
</g>
<g>
<rect x="40" y="40" width="20" height="20" fill="#0000ff"></rect>
<rect x="60" y="60" width="20" height="20" fill="#000000"></rect>
</g>
</svg>
</div>
mi è venuta in mente un codice che realizza questo, ma ho trovato la parte sull'utilizzo i dati di due diversi livelli di nidificazione in data
sono confusi e ritengo che potrebbe esserci un modo più idiomatico per ottenere lo stesso risultato con d3.js. Ecco il codice (esempio completo in http://jsbin.com/welcome/39650/edit):
function pos(d,i) { return d.x + (i * d.size); } // rect position
function size(d,i) { return d.size; } // rect size
function f(d,i) { return d.color; } // rect color
// add the top-level svg element and size it
vis = d3
.select('#container')
.append('svg')
.attr('width',200)
.attr('height',200);
// add the nested svg elements
var nested = vis
.selectAll('g')
.data(data.segments)
.enter()
.append('g');
// Add a rectangle for each color
nested
.selectAll('rect')
.data(function(d) {
// **** ATTENTION ****
// Is there a more idiomatic, d3-ish way to approach this?
var expanded = [];
for(var i = 0; i < d.colors.length; i++) {
expanded.push({
color : d.colors[i],
x : d.x
size : d.size });
}
return expanded;
})
.enter()
.append('rect')
.attr('x',pos)
.attr('y',pos)
.attr('width',size)
.attr('height',size)
.attr('fill',f);
C'è un modo migliore e/o più idiomatico per accedere ai dati provenienti da due diversi livelli di nidificazione in una struttura dati utilizzando d3.js?
Modifica
Ecco la soluzione mi è venuta, grazie alla meetamit's answer per l'idea di chiusura, e l'utilizzo di più idiomatiche d3.js indentazione grazie a nautat's answer:
$(function() {
var
vis = null,
width = 200,
height = 200,
data = {
segments : [
{x : 20, y : 0, size : 10, colors : ['#ff0000','#00ff00']},
{x : 40, y : 0, size : 20, colors : ['#0000ff','#000000']}
]
};
// set the color
function f(d,i) {return d;}
// set the position
function pos(segment) {
return function(d,i) {
return segment.x + (i * segment.size);
};
}
// set the size
function size(segment) {
return function() {
return segment.size;
};
}
// add the top-level svg element and size it
vis = d3.select('#container').append('svg')
.attr('width',width)
.attr('height',height);
// add the nested svg elements
var nested = vis
.selectAll('g')
.data(data.segments)
.enter().append('g');
// Add a rectangle for each color. Size of rectangles is determined
// by the "parent" data object.
nested
.each(function(segment, i) {
var
ps = pos(segment),
sz = size(segment);
var colors = d3.select(this)
.selectAll('rect')
.data(segment.colors)
.enter().append('rect')
.attr('x', ps)
.attr('y',ps)
.attr('width', sz)
.attr('height',sz)
.attr('fill', f);
});
});
Ecco l'esempio di lavoro completo : http://jsbin.com/welcome/42885/edit
perché hai bisogno di tag svg annidati nel tuo codice html? – btel
Vorrei che tutti i rettangoli corrispondenti a un 'segmento' venissero raggruppati insieme. Se ho capito bene, posso spostare tutti i rettangoli dal primo 'segmento' cambiando le proprietà' x' e 'y' dell'elemento genitore' svg'. Se c'è un modo migliore, mi piacerebbe saperlo. –
Come su un elemento di gruppo con l'attributo transform: ' ... ': http://www.w3.org/TR/SVG/coords.html#TransformAttribute. Se ho capito bene dovresti avere un solo svg per ogni disegno. –
btel