Skip to content

Instantly share code, notes, and snippets.

@nowherenearithaca
Last active April 11, 2016 04:22
Show Gist options
  • Save nowherenearithaca/4449376 to your computer and use it in GitHub Desktop.
Save nowherenearithaca/4449376 to your computer and use it in GitHub Desktop.
Making a Heat Map Legend with D3 - a Simple Example

This is an example of creating what could be a legend for a heat map, demonstrating the simple use of a data-driven linear gradient with D3.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
width: 960px;
height: 500px;
position: relative;
background:#D0D0D0;
}
.legendText {
font-size:50px;
font-family:"Arial, sans-serif";
font-weight: bold;
}
</style>
<body>
<div id="theBar"></div>
</body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var svgWidth = 960,
svgHeight = 500,
x1 = 200,
barWidth = 560,
y1 = 150,
barHeight = 200,
numberHues = 35;
var idGradient = "legendGradient";
var svgForLegendStuff = d3.select("#theBar").append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
//create the empty gradient that we're going to populate later
svgForLegendStuff.append("g")
.append("defs")
.append("linearGradient")
.attr("id",idGradient)
.attr("x1","0%")
.attr("x2","100%")
.attr("y1","0%")
.attr("y2","0%"); // x1=0, x2=100%, y1=y2 results in a horizontal gradient
// it would have been vertical if x1=x2, y1=0, y2=100%
// See
// http://www.w3.org/TR/SVG/pservers.html#LinearGradients
// for more details and fancier things you can do
//create the bar for the legend to go into
// the "fill" attribute hooks the gradient up to this rect
svgForLegendStuff.append("rect")
.attr("fill","url(#" + idGradient + ")")
.attr("x",x1)
.attr("y",y1)
.attr("width",barWidth)
.attr("height",barHeight)
.attr("rx",20) //rounded corners, of course!
.attr("ry",20);
//add text on either side of the bar
var textY = y1 + barHeight/2 + 15;
svgForLegendStuff.append("text")
.attr("class","legendText")
.attr("text-anchor", "middle")
.attr("x",x1 - 25)
.attr("y",textY)
.attr("dy",0)
.text("0");
svgForLegendStuff.append("text")
.attr("class","legendText")
.attr("text-anchor", "left")
.attr("x",x1 + barWidth + 15)
.attr("y",textY)
.attr("dy",0)
.text(numberHues + "+");
//we go from a somewhat transparent blue/green (hue = 160º, opacity = 0.3) to a fully opaque reddish (hue = 0º, opacity = 1)
var hueStart = 160, hueEnd = 0;
var opacityStart = 0.3, opacityEnd = 1.0;
var theHue, rgbString, opacity,p;
var deltaPercent = 1/(numberHues-1);
var deltaHue = (hueEnd - hueStart)/(numberHues - 1);
var deltaOpacity = (opacityEnd - opacityStart)/(numberHues - 1);
//kind of out of order, but set up the data here
var theData = [];
for (var i=0;i < numberHues;i++) {
theHue = hueStart + deltaHue*i;
//the second parameter, set to 1 here, is the saturation
// the third parameter is "lightness"
rgbString = d3.hsl(theHue,1,0.6).toString();
opacity = opacityStart + deltaOpacity*i;
p = 0 + deltaPercent*i;
//onsole.log("i, values: " + i + ", " + rgbString + ", " + opacity + ", " + p);
theData.push({"rgb":rgbString, "opacity":opacity, "percent":p});
}
//now the d3 magic (imo) ...
var stops = d3.select('#' + idGradient).selectAll('stop')
.data(theData);
stops.enter().append('stop');
stops.attr('offset',function(d) {
return d.percent;
})
.attr('stop-color',function(d) {
return d.rgb;
})
.attr('stop-opacity',function(d) {
return d.opacity;
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment