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.
Last active
April 11, 2016 04:22
-
-
Save nowherenearithaca/4449376 to your computer and use it in GitHub Desktop.
Making a Heat Map Legend with D3 - a Simple Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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