Skip to content

Instantly share code, notes, and snippets.

@emeeks
Last active December 17, 2022 14:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save emeeks/8855733967174fe4b1b4 to your computer and use it in GitHub Desktop.
Save emeeks/8855733967174fe4b1b4 to your computer and use it in GitHub Desktop.
d3.svg.legend example

d3.svg.legend provides for a simple legend that can be displayed horizontally or vertically and accepts a few different d3 scale types.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>D3 Legend</title>
<meta charset="utf-8" />
</head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/colorbrewer.v1.min.js"></script>
<script src="legend.js"></script>
<style>
body, html {
width:100%;
height:100%;
}
#vizcontainer {
width:100%;
height:100%;
}
svg {
width: 100%;
height: 100%;
}
</style>
<body onload="legendDemo()">
<div id="vizcontainer">
<svg></svg>
</div>
<footer>
<script>
function legendDemo() {
sampleNumerical = [1,2.5,5,10,20];
sampleThreshold=d3.scale.threshold().domain(sampleNumerical).range(colorbrewer.Reds[5]);
horizontalLegend = d3.svg.legend().units("Miles").cellWidth(80).cellHeight(25).inputScale(sampleThreshold).cellStepping(100);
d3.select("svg").append("g").attr("transform", "translate(50,70)").attr("class", "legend").call(horizontalLegend);
sampleCategoricalData = ["Something","Something Else", "Another", "This", "That", "Etc"]
sampleOrdinal = d3.scale.category20().domain(sampleCategoricalData);
verticalLegend = d3.svg.legend().labelFormat("none").cellPadding(5).orientation("vertical").units("Things in a List").cellWidth(25).cellHeight(18).inputScale(sampleOrdinal).cellStepping(10);
d3.select("svg").append("g").attr("transform", "translate(50,140)").attr("class", "legend").call(verticalLegend);
}
</script>
</footer>
</body>
</html>
d3.svg.legend = function() {
var legendValues=[{color: "red", stop: [0,1]},{color: "blue", stop: [1,2]},{color: "purple", stop: [2,3]},{color: "yellow", stop: [3,4]},{color: "Aquamarine", stop: [4,5]}];
var legendScale;
var cellWidth = 30;
var cellHeight = 20;
var adjustable = false;
var labelFormat = d3.format(".01f");
var labelUnits = "units";
var lastValue = 6;
var changeValue = 1;
var orientation = "horizontal";
var cellPadding = 0;
function legend(g) {
function cellRange(valuePosition, changeVal) {
legendValues[valuePosition].stop[0] += changeVal;
legendValues[valuePosition - 1].stop[1] += changeVal;
redraw();
}
function redraw() {
g.selectAll("g.legendCells").data(legendValues).exit().remove();
g.selectAll("g.legendCells").select("rect").style("fill", function(d) {return d.color});
if (orientation == "vertical") {
g.selectAll("g.legendCells").select("text.breakLabels").style("display", "block").style("text-anchor", "start").attr("x", cellWidth + cellPadding).attr("y", 5 + (cellHeight / 2)).text(function(d) {return labelFormat(d.stop[0]) + (d.stop[1].length > 0 ? " - " + labelFormat(d.stop[1]) : "")})
g.selectAll("g.legendCells").attr("transform", function(d,i) {return "translate(0," + (i * (cellHeight + cellPadding)) + ")" });
}
else {
g.selectAll("g.legendCells").attr("transform", function(d,i) {return "translate(" + (i * cellWidth) + ",0)" });
g.selectAll("text.breakLabels").style("text-anchor", "middle").attr("x", 0).attr("y", -7).style("display", function(d,i) {return i == 0 ? "none" : "block"}).text(function(d) {return labelFormat(d.stop[0])});
}
}
g.selectAll("g.legendCells")
.data(legendValues)
.enter()
.append("g")
.attr("class", "legendCells")
.attr("transform", function(d,i) {return "translate(" + (i * (cellWidth + cellPadding)) + ",0)" })
g.selectAll("g.legendCells")
.append("rect")
.attr("height", cellHeight)
.attr("width", cellWidth)
.style("fill", function(d) {return d.color})
.style("stroke", "black")
.style("stroke-width", "2px");
g.selectAll("g.legendCells")
.append("text")
.attr("class", "breakLabels")
.style("pointer-events", "none");
g.append("text")
.text(labelUnits)
.attr("y", -7);
redraw();
}
legend.inputScale = function(newScale) {
if (!arguments.length) return scale;
scale = newScale;
legendValues = [];
if (scale.invertExtent) {
//Is a quantile scale
scale.range().forEach(function(el) {
var cellObject = {color: el, stop: scale.invertExtent(el)}
legendValues.push(cellObject)
})
}
else {
scale.domain().forEach(function (el) {
var cellObject = {color: scale(el), stop: [el,""]}
legendValues.push(cellObject)
})
}
return this;
}
legend.scale = function(testValue) {
var foundColor = legendValues[legendValues.length - 1].color;
for (el in legendValues) {
if(testValue < legendValues[el].stop[1]) {
foundColor = legendValues[el].color;
break;
}
}
return foundColor;
}
legend.cellWidth = function(newCellSize) {
if (!arguments.length) return cellWidth;
cellWidth = newCellSize;
return this;
}
legend.cellHeight = function(newCellSize) {
if (!arguments.length) return cellHeight;
cellHeight = newCellSize;
return this;
}
legend.cellPadding = function(newCellPadding) {
if (!arguments.length) return cellPadding;
cellPadding = newCellPadding;
return this;
}
legend.cellExtent = function(incColor,newExtent) {
var selectedStop = legendValues.filter(function(el) {return el.color == incColor})[0].stop;
if (arguments.length == 1) return selectedStop;
legendValues.filter(function(el) {return el.color == incColor})[0].stop = newExtent;
return this;
}
legend.cellStepping = function(incStep) {
if (!arguments.length) return changeValue;
changeValue = incStep;
return this;
}
legend.units = function(incUnits) {
if (!arguments.length) return labelUnits;
labelUnits = incUnits;
return this;
}
legend.orientation = function(incOrient) {
if (!arguments.length) return orientation;
orientation = incOrient;
return this;
}
legend.labelFormat = function(incFormat) {
if (!arguments.length) return labelFormat;
labelFormat = incFormat;
if (incFormat == "none") {
labelFormat = function(inc) {return inc};
}
return this;
}
return legend;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment