2015-09-24 3 views
13

Ich arbeite an this plnkr. Ich habe drei Linien in den Winkeln 30, 45 und 60. Ich möchte einen Pinsel auf diese Linien anwenden, so dass beim Zeichnen der Grafik die Linien an der Stelle, an der sie das gebürstete Rechteck kreuzt, mit den Werten auf der Achse neu gezeichnet werden. Jede Hilfe oder ein Hinweis zur Lösung dieses Problems wird sehr geschätzt.Pinsel auf gedrehten Linien mit d3 zum Erstellen von Zoom-Effekt

EDIT: Wenn Sie verschiedene Lösungen haben, um die gedrehten Linien zu zeichnen und darüber zu bürsten, ist es auch willkommen. Bitte helfen Sie.

var ga = d3.select("svg") 
    .append("g") 
    .attr("class", "a axis") 
    .attr("transform", "translate(" + margin.left + "," + (height + margin.top) + ")") 
    .selectAll("g") 
    .data([30, 45, 60]) 
    .enter() 
    .append("g") 
    .attr("class", "rotatedlines") 
    .attr("transform", function(d) { return "rotate(" + -d + ")"; }) 
    .attr("stroke-width", 1) 
    .attr("stroke", "black") 
    .attr("stroke-dasharray", "5,5"); 

Example result

+0

Möchten Sie das vorhandene Diagramm mit der neuen gezoomten Ansicht überschreiben, ähnlich der [SE-Reputationsgrafik] (http://stackexchange.com/users/4536689/d3-gxt-java?tab=reputation)? – approxiblue

+0

ja - Ich möchte genau wie im Beispiel beschrieben überschreiben. – somename

+0

In Ihrem Beispiel haben Sie Zeilen mit der Rotation 30,45,60 erstellt ... ist das der reale Datensatz, oder haben Sie echte x (Datum) und y (Punkte) Werte wie hier http://stackexchange.com/users/4536689/d3-gxt-java? tab = reputation – Cyril

Antwort

5

meine Lösung zu erklären:

Die grundlegenden Schritte sind wie folgt ablaufen:

  • Update, um die Domänen die X- und Y-Skalen zum Pinselumfang
  • die Achsen neu zeichnen
  • berechnen Sie den Skalierungsfaktor und Transl ation für die
  • Skalenlinien und übersetzen die Linie Container entsprechend
  • Zurücksetzen der Bürste

anzumerken, dass 3 und 4 sind nur wenige Schritte erforderlich, da Sie die Waage nicht verwenden, alles zu zeichnen - eine bessere Ansatz wäre, zwei Punkte für jede Zeile als die Daten zu definieren, die an die Elemente gebunden sind, und dann die Maßstäbe zum Neuzeichnen zu verwenden. Dies würde den Code einfacher machen.

Mit Ihrem Ansatz ist es aber immer noch möglich. Um es zu erleichtern, habe ich ein paar Änderungen an Ihrem Code vorgenommen - insbesondere habe ich die verschiedenen verschachtelten g Elemente mit verschiedenen Übersetzungen bereinigt und die Zeilen durch ihre x1, x2, y1, y2 Attribute statt definiert durch Übersetzung der Container. Diese beiden Änderungen machen die gewünschte Funktionalität einfacher zu implementieren, da nur eine einzige Transformation stattfindet, bei der mehrere andere Transformationen nicht berücksichtigt werden müssen. Ich habe auch die Zeilen in mehreren g Elementen verschachtelt, so dass sie leichter skaliert und übersetzt werden können.

Die Bürste Handler-Funktion sieht nun wie folgt aus:

// update scales, redraw axes 
var extent = brush.extent(); 
x.domain(brush.empty() ? x2.domain() : [ extent[0][0], extent[1][0] ]); 
y.domain(brush.empty() ? y2.domain() : [ extent[0][1], extent[1][1] ]); 
xAxisG.call(xAxis); 
yAxisG.call(yAxis); 

Dieser Code sollte selbsterklärend sein - die Domänen der Waage aktualisiert entsprechend den aktuellen Umfang der Bürste und die Achsen neu gezeichnet .

// compute and apply scaling and transformation of the g elements containing the lines 
var sx = (x2.domain()[1] - x2.domain()[0])/(x.domain()[1] - x.domain()[0]), 
    sy = (y2.domain()[1] - y2.domain()[0])/(y.domain()[1] - y.domain()[0]), 
    dx = -x2(x.domain()[0]) - x2.range()[0], 
    dy = -y2(y.domain()[1]) - y2.range()[1]; 
d3.selectAll("g.container") 
    .attr("transform", "translate(" + [sx * dx, sy * dy] + ")scale(" + [sx, sy] + ")"); 

Dies ist der schwierige Teil - auf der Grundlage der neuen Domänen der Waage, müssen wir den Umfang und die Übersetzung für die Linien berechnen. Die Skalierungsfaktoren sind einfach das Verhältnis des alten Ausmaßes zum neuen Ausmaß (beachte, dass ich Kopien der Skalen gemacht habe, die nicht modifiziert wurden), dh eine Zahl größer als 1. Die Übersetzung bestimmt die Verschiebung des (0,0) Koordinate und wird berechnet durch die Differenz der alten (0,0) Koordinate (ich erhalte diese aus dem Bereich der ursprünglichen Skalen) und die Position des neuen Domänenursprungs gemäß den ursprünglichen Skalen.

Wenn Sie die Translation und die Skalierung gleichzeitig anwenden, müssen wir die Offsets mit den Skalierungsfaktoren multiplizieren.

// reset brush 
brush.clear(); 
d3.select(".brush").call(brush); 

Schließlich löschen wir den Pinsel und setzen ihn zurück, um das graue Rechteck loszuwerden.

Vollständige Demo here.

+0

vielen Dank Lars - das ist super! – somename

2

Sie können den Pinsel Umfang über d3.event.target.extent() zugreifen. Die Strömung für die Skala Zeichnung ist dies:

  • Set Maßstab
  • Set Achse
  • Zugachse

Sobald die Bürste getan wird, haben Sie die Skala ändern, und dann wieder Ziehen Sie die Achse gemäß der aktuellen x- und y-Domäne. Ist es das, was du meintest?

reinigte ich den Code ein wenig und machte eine kleine Demonstration: http://plnkr.co/edit/epKbXbcBR2MiwUOMlU5A?p=preview

+0

Vielen Dank für Ihre Antwort. Ich muss auch die gedrehten Linien neu zeichnen - wo es den gebürsteten Bereich durchschnitten hat. Wenn der Pinselbereich keine gedrehten Linien schneidet, sollte er nicht auf dem neu gezeichneten Diagramm erscheinen. Hast du eine Idee, wie das geht? – somename

+0

Das ist der einfache Teil, ich dachte du hättest das vielleicht schon gelöst :-) Siehe diese Version: http://plnkr.co/edit/Aw6Gc1PNGtiVSWXNaJU2?p=preview In Zeile 116. Ich teile die Leinwand und die Linien, dann du kann einfach das 'g' Element mit etwas wie 'transform =" translate (-50, 470) scale (2) "' skalieren. – Rudolf

+0

Btw, d3 hat auch eine Zoom-Bibliothek, von der Sie die Mathematik ausleihen können. – Rudolf

Verwandte Themen