2016-06-08 11 views
2

Ich versuche, eine d3-Legendenzeichnungsfunktion zu ersetzen, die die manuelle Erstellung und Platzierung der Legendenelemente mit .data() verwendet.d3.js: Legenden mit dynamischer Elementbreite

Ich war in der Lage, alles funktionierte, bis auf eine Sache: mit dem manuellen Durchlaufen der Daten-Array konnte ich sicherstellen, gleiche Abstände zwischen den Legendenelementen mit einer currentX Tracker-Variable. Mit .data() kann ich jedoch nicht auf die anderen Elemente verweisen und muss Boxen mit fester Breite verwenden, was der Designer hasst (und mich auch).

Mit dem folgenden Code, wie mache ich den neuen Code (obere Zeile) verhalten sich genau wie der alte Code (untere Reihe)?

(Bitte schlagen nicht vor, dass ich eine Legende Bibliothek verwenden, gibt es viele Event-Handling und mehr Material in der „realen“ Code, auf dem diese Testfall extrahiert wurde)

var config = { 
 
    circleYCenter: 170, 
 
    circleXCenter: 150, 
 
    legendMarginTop: 52, 
 
    legendMarginInner: 18, 
 
    legendDotHeight: 8, 
 
    legendDotWidth: 16, 
 
}; 
 
var colors = { 
 
    'lightyellow': '#FEE284', 
 
    'darkblue': '#2872A3', 
 
    'dirtyorange': '#E68406', 
 
}; 
 

 
function drawLegend(container, map) { 
 
    var legendGroup = container.append("g").attr({ 
 
    "transform": "translate(0,50)", 
 
    "class": "legendGroup" 
 
    }); 
 

 
    //New code 
 
    var elGroup = legendGroup.selectAll("g").data(map).enter().append("g").attr({ 
 
    transform: function(d, i) { 
 
     return "translate(" + (i * 100) + ",0)" 
 
    } 
 
    }); 
 

 
    elGroup.append("text").text(function(d) { 
 
    return d.label; 
 
    }).attr({ 
 
    x: config.legendDotWidth + config.legendMarginInner 
 
    }); 
 
    elGroup.append("rect").attr({ 
 
    x: 0, 
 
    width: config.legendDotWidth, 
 
    y: -5, 
 
    height: config.legendDotHeight, 
 
    "fill": function(d) { 
 
     return d.color; 
 
    } 
 
    }); 
 

 

 
    //Old code 
 
    var currentX = 0; 
 
    map.forEach(function(el, key) { 
 
    var elGroup = legendGroup.append("g").attr("transform", "translate(" + currentX + ",100)"); 
 
    elGroup.append("rect").attr({ 
 
     x: 0, 
 
     width: config.legendDotWidth, 
 
     y: -5, 
 
     height: config.legendDotHeight, 
 
     "fill": el.color 
 
    }); 
 
    elGroup.append("text").attr({ 
 
     "x": (config.legendDotWidth + 10), 
 
     "y": 0, 
 
     "alignment-baseline": "middle" 
 
    }).text(el.label); 
 
    currentX += elGroup.node().getBBox().width + config.legendMarginInner; 
 
    }); 
 
} 
 

 
drawLegend(d3.select("svg"), [{ 
 
    label: "foo", 
 
    color: colors.dirtyorange 
 
}, { 
 
    label: "Banana", 
 
    color: colors.darkblue 
 
}, { 
 
    label: "baz", 
 
    color: colors.lightyellow 
 
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 

 
<svg width=600 height=300></svg>

Antwort

1

zuerst die Gruppe machen:

var elGroup = legendGroup.selectAll("g").data(map).enter().append("g"); 

Fügen Sie den text und rect DOM, wie Sie doin sind g:

elGroup.append("text").text(function(d) { 
    return d.label; 
    }).attr({ 
    x: config.legendDotWidth + config.legendMarginInner 
    }); 

    elGroup.append("rect").attr({ 
    x: 0, 
    width: config.legendDotWidth, 
    y: -5, 
    height: config.legendDotHeight, 
    "fill": function(d) { 
     return d.color; 
    } 
    }); 

Nun ist die zu der Gruppe der bbox der Gruppe übersetzen hinzufügen verwenden.

var currentX = 0; 
elGroup.attr({ 
    transform: function(d, i) { 
      var ret = "translate(" + currentX + ",0)" 
      currentX += this.getBBox().width + config.legendMarginInner; 
     return ret; 
    } 
    }); 

Arbeits Code here

+0

Vielen Dank! – Skynet

+0

@Cyril, könntest du bitte in diese Ausgabe schauen https://jsfiddle.net/praveenuics/k1xssj9h/, Seine über die Legenden, werde ich mehrzeiliges Diagramm verwenden, wo es ungefähr 20 Trendlinie gibt, wo ich Legenden zeigen muss (20 In diesem Fall sind alle Legenden nebeneinander gestapelt, bis sie das Ende erreichen, aber ich brauche sie mit der Svg-Box/Scroll wird auch funktionieren, jede Hilfe wird sehr geschätzt. – Praveen