Ich habe ein Sunburst-Diagramm in D3. Jedes "Blütenblatt" repräsentiert eine Teilmenge von Daten. Wenn ein Benutzer auf einem der ‚Blätter‘ klickt, möchte ich es, den Übergang zeigen Auffächerung nur, dass die Teilmenge (siehe Bild):D3 - Transitionsbögen in Sunburst-Diagramm
Ich habe Probleme mit dem Code immer richtig Übergang.
Bei einem Klick sollten alle "Petalen" (neben dem ausgewählten) verschwinden und die verbleibenden Pfade sollten entlang des Kreises animieren (mit attr Tween, arcTween und interpolieren?). Der primäre Wert, der sich ändern würde, ist die angleSize (var angleSize = (2 * Math.PI)/theData.length;
).
Ich habe versucht mit this, this, this und this als Referenz ohne viel Erfolg. Was ist der beste Weg, um mit der Animation umzugehen?
Danke für Ihre Zeit!
-> Siehe Plunker Here. < -
-Code ist unten:
var colors = {
'Rank1' : '#3FA548',
'Rank2' : '#00B09E',
'Rank3' : '#8971B3',
'Rank4' : '#DFC423',
'Rank5' : '#E74341'
};
var $container = $('.chart'),
m = 40,
width = $container.width() - m,
height = $container.height() - m,
r = Math.min(width, height)/2;
var study = null;
var arc = d3.svg.arc();
d3.csv('text.csv', ready);
function ready(err, data) {
if (err) console.warn('Error', err);
var svg = d3.select('.chart')
.append('svg')
.attr({
'width' : (r + m) * 2,
'height' : (r + m) * 2,
'class' : 'container'
})
.append('g')
.attr('transform', 'translate(' + (width/4) + ', ' + (height/2) + ')');
var slice = svg.selectAll('.slice');
function updateChart(study) {
if (study) {
var theData = data.filter(function(d) {
return d.study_name === study;
});
} else {
var theData = data;
}
slice = slice.data(theData);
slice.enter()
.append('g')
.attr('class', 'slice');
var angleSize = (2 * Math.PI)/theData.length;
var startRadArr = [],
endRadArr = [];
for (var i = 0; i < data.length; i++) {
var startRadius = (width/20),
endRadius = startRadius;
for (var x = 0; x < 4; x++) {
startRadArr.push(startRadius);
if (x == 0) {
endRadius += Number(data[i].group1_score) * (width/500);
} else if (x == 1) {
endRadius += Number(data[i].group2_score) * (width/500);
} else if (x == 2) {
endRadius += Number(data[i].group3_score) * (width/500);
} else {
endRadius += Number(data[i].group4_score) * (width/500);
}
endRadArr.push(endRadius);
startRadius = endRadius + 0.3;
}
}
var startRadGroup = [],
endRadGroup = [];
for (i = 0; i < startRadArr.length; i += 4) {
startRadGroup.push(startRadArr.slice(i, i + 4));
}
for (i = 0; i < endRadArr.length; i += 4) {
endRadGroup.push(endRadArr.slice(i, i + 4));
}
slice.selectAll('path')
.remove();
for (var x = 0; x < 4; x++) {
slice.append('path')
.attr({
'class' : function(d, i) {
if (x == 0) {
return d.group1_class;
} else if (x == 1) {
return d.group2_class;
} else if (x == 2) {
return d.group3_class;
} else {
return d.group4_class;
}
},
'company' : function(d, i) {
return d.brand_name;
},
'cat' : function(d, i) {
if (x == 0) {
return 'Group1';
} else if (x == 1) {
return 'Group2';
} else if (x == 2) {
return 'Group3';
} else {
return 'Group4';
}
},
'study' : function(d, i) {
return d.study_name;
},
'companyid' : function(d, i) {
return d.brand_id;
},
'startradius' : function(d, i) {
return startRadGroup[i][x];
},
'endradius' : function(d, i) {
return endRadGroup[i][x];
},
'startangle' : function(d, i) {
return angleSize * i;
},
'endangle' : function(d, i) {
return angleSize * (i + 1);
}
})
.on('click', selectStudy);
}
slice.exit()
.remove();
slice.selectAll('path')
.attr({
'd' : function(d) {
return arc({
innerRadius : +d3.select(this)[0][0].attributes.startradius.nodeValue,
outerRadius : +d3.select(this)[0][0].attributes.endradius.nodeValue,
startAngle : +d3.select(this)[0][0].attributes.startangle.nodeValue,
endAngle : +d3.select(this)[0][0].attributes.endangle.nodeValue
})
}
});
}
function selectStudy(d) {
study = $(this).attr('study');
updateChart(study);
}
updateChart();
}
EDIT
den Code aktualisiert (basierend auf this) ein ordnungsgemäß funktionierende eingeben zu schließen, zu aktualisieren und Ausgabemuster. Immer noch unsicher über den Übergang. Die meisten der Beispiele, die ich verlinkt habe, verwenden etwas Ähnliches wie d3.interpolate(this._current, a);
, zwischen verschiedenen Daten tweening.
In diesem Diagramm sind this._current und a gleich, angleSize (var angleSize = (2 * Math.PI)/theData.length;
), startAngle und endAngle sind die einzigen Änderungen.
Es gibt ein paar Dinge, die dies komplizieren - vor allem, dass Sie alle Schichten entfernen, bevor Sie versuchen, sie zu überführen, aber Sie müssen sie mit ihrem Startpunkt neu erstellen, um den Übergang zu beginnen. Erwägen Sie auch, die Daten in eine tiefere Struktur umzuformatieren, so dass Sie nicht 4 Mal über jeden Punkt eine Schleife machen müssen. – Owen
@Owen Ja. Die remove() war ein temp-Fix für etwas seltsames Verhalten (neue Daten würden über alte Daten anhängen). Kommentar zum Entfernen -> [LINK] (https://plnkr.co/edit/JwCy84YBVSxDERZOp1z0?p=preview). Was die Daten betrifft, habe ich leider keine Kontrolle über das Format. Wird nach einer JS-Lösung suchen (irgendwelche Vorschläge?). Würde es vorziehen, in Excel nicht manuell zu ändern. – BastionGamma
Auch ein Grund, d3 v3 statt v4 zu verwenden? – Owen