2014-09-17 8 views
11

So habe ich ein Diagramm, das Verkehr vs. Datum und Rate vs. Datum grafisch darstellt. Ich versuche, den Bereich zwischen den beiden Linien zu beschatten. Ich möchte jedoch eine andere Farbe schattieren, je nachdem, welche Zeile höher ist. Die folgenden Arbeiten ohne diese letzte Forderung:Verwenden von d3, um Bereich zwischen zwei Zeilen zu schattieren

var area = d3.svg.area() 
    .x0(function(d) { return x(d3.time.format("%m/%d/%Y").parse(d.original.date)); }) 
    .x1(function(d) { return x(d3.time.format("%m/%d/%Y").parse(d.original.date)); }) 
    .y0(function(d) { return y(parseInt(d.original.traffic)); }) 
    .y1(function(d) { return y(parseInt(d.original.rate)); }) 

jedoch hinzu, dass letzte Forderung, habe ich versucht, definiert() verwenden:

.defined(function(d){ return parseInt(d.original.traffic) >= parseInt(d.original.rate); }) 

Jetzt meist das funktioniert, außer wenn Linien kreuzen. Wie schattiere ich den Bereich unter einer Linie ZWISCHEN Punkten? Es ist Schattierung basierend auf den Punkten und ich möchte, dass es basierend auf der Linie schattiert. Wenn ich nicht zwei aufeinanderfolgende Punkte auf einer Seite der Linie habe, bekomme ich überhaupt keine Schattierung.

Antwort

13

Da an den Schnittpunkten keine Datenpunkte vorhanden sind, besteht die einfachste Lösung wahrscheinlich darin, die Bereiche über und unter jeder Linie zu ermitteln und clipPath s zu verwenden, um die Differenz zu beschneiden.

Ich nehme an, Sie verwenden d3.svg.line, um die Linien zu zeichnen, auf denen die Bereiche basieren. Auf diese Weise werden wir die .x() und .y() Accessorfunktionen auf die Bereiche später wiederverwenden können:

var trafficLine = d3.svg.line() 
    .x(function(d) { return x(d3.time.format("%m/%d/%Y").parse(d.original.date)); }) 
    .y(function(d) { return y(parseInt(d.original.traffic)); }); 

var rateLine = d3.svg.line() 
    .x(trafficLine.x()) // reuse the traffic line's x 
    .y(function(d) { return y(parseInt(d.original.rate)); }) 

Sie können die Bereiche für die Berechnung der oben und unten Ihre beiden Linien separaten Bereich Funktionen erstellen. Der Bereich unter jeder Linie wird zum Zeichnen des tatsächlichen Pfads verwendet, und der darüber liegende Bereich wird als Beschneidungspfad verwendet. Jetzt können wir die Accessoren von den Linien wiederverwenden:

var areaAboveTrafficLine = d3.svg.area() 
    .x(trafficLine.x()) 
    .y0(trafficLine.y()) 
    .y1(0); 
var areaBelowTrafficLine = d3.svg.area() 
    .x(trafficLine.x()) 
    .y0(trafficLine.y()) 
    .y1(height); 
var areaAboveRateLine = d3.svg.area() 
    .x(rateLine.x()) 
    .y0(rateLine.y()) 
    .y1(0); 
var areaBelowRateLine = d3.svg.area() 
    .x(rateLine.x()) 
    .y0(rateLine.y()) 
    .y1(height); 

... wo height die Höhe des Diagramms ist, und unter der Annahme, 0 ist die y-Koordinate der oberen Rand des Diagramms, passen sonst diese Werte entsprechend.

Jetzt können Sie die Flächen oben genannten Funktionen verwenden, um Clipping-Pfade wie folgt zu erstellen:

var defs = svg.append('defs'); 

defs.append('clipPath') 
    .attr('id', 'clip-traffic') 
    .append('path') 
    .datum(YOUR_DATASET) 
    .attr('d', areaAboveTrafficLine); 

defs.append('clipPath') 
    .attr('id', 'clip-rate') 
    .append('path') 
    .datum(YOUR_DATASET) 
    .attr('d', areaAboveRateLine); 

Die id Attribute sind notwendig, weil wir auf diese Definitionen verweisen müssen, wenn tatsächlich die Clipping-Pfade.

Verwenden Sie schließlich die Bereich-unter-Funktionen, um Pfade zu dem Svg zu zeichnen. Die wichtige Sache zu erinnern ist, dass für jeden Bereich-unten, müssen wir die gegenüber flächen oben befestigen, so dass die Rate Bereich basierend auf #clip-traffic und umgekehrt abgeschnitten:

// TRAFFIC IS ABOVE RATE 
svg.append('path') 
    .datum(YOUR_DATASET) 
    .attr('d', areaBelowTrafficLine) 
    .attr('clip-path', 'url(#clip-rate)') 

// RATE IS ABOVE TRAFFIC 
svg.append('path') 
    .datum(YOUR_DATASET) 
    .attr('d', areaBelowRateLine) 
    .attr('clip-path', 'url(#clip-traffic)') 

Danach Sie müssen nur den beiden Regionen unterschiedliche Füllfarben oder was auch immer Sie tun möchten, um sie voneinander zu unterscheiden. Ich hoffe, das hilft!

Verwandte Themen