Skip to content

Instantly share code, notes, and snippets.

@syntagmatic
Last active January 9, 2017 19:03
Show Gist options
  • Save syntagmatic/e8ccca52559796be775553b467593a9f to your computer and use it in GitHub Desktop.
Save syntagmatic/e8ccca52559796be775553b467593a9f to your computer and use it in GitHub Desktop.
Continuous Legend
border: no
height: 260
license: gpl-3.0

Prototype utility for generating continuous legends. Inspired by d3-legend.

Needs a pattern for configuring height, width, tick format, etc.

<!doctype html>
<meta charset="utf-8">
<style>
body {
margin: 30px;
}
</style>
<body>
<div id="legend1" style="display: inline-block"></div>
<div id="legend2" style="display: inline-block"></div>
<div id="legend3" style="display: inline-block"></div>
<div id="legend4" style="display: inline-block"></div>
<div id="legend5" style="display: inline-block"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script>
var colorScale1 = d3.scaleSequential(d3.interpolatePlasma)
.domain([0, 20]);
var colorScale2 = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 1000]);
var colorScale3 = d3.scaleSequential(d3.interpolateRainbow)
.domain([0, 90]);
var colorScale4 = d3.scaleSequential(d3.interpolateGnBu)
.domain([0, 0.2]);
var colorScale5 = d3.scaleSequential(d3.interpolatePRGn)
.domain([-5, 5]);
continuous("#legend1", colorScale1);
continuous("#legend2", colorScale2);
continuous("#legend3", colorScale3);
continuous("#legend4", colorScale4);
continuous("#legend5", colorScale5);
// create continuous color legend
function continuous(selector_id, colorscale) {
var legendheight = 200,
legendwidth = 80,
margin = {top: 10, right: 60, bottom: 10, left: 2};
var canvas = d3.select(selector_id)
.style("height", legendheight + "px")
.style("width", legendwidth + "px")
.style("position", "relative")
.append("canvas")
.attr("height", legendheight - margin.top - margin.bottom)
.attr("width", 1)
.style("height", (legendheight - margin.top - margin.bottom) + "px")
.style("width", (legendwidth - margin.left - margin.right) + "px")
.style("border", "1px solid #000")
.style("position", "absolute")
.style("top", (margin.top) + "px")
.style("left", (margin.left) + "px")
.node();
var ctx = canvas.getContext("2d");
var legendscale = d3.scaleLinear()
.range([1, legendheight - margin.top - margin.bottom])
.domain(colorscale.domain());
// image data hackery based on http://bl.ocks.org/mbostock/048d21cf747371b11884f75ad896e5a5
var image = ctx.createImageData(1, legendheight);
d3.range(legendheight).forEach(function(i) {
var c = d3.rgb(colorscale(legendscale.invert(i)));
image.data[4*i] = c.r;
image.data[4*i + 1] = c.g;
image.data[4*i + 2] = c.b;
image.data[4*i + 3] = 255;
});
ctx.putImageData(image, 0, 0);
// A simpler way to do the above, but possibly slower. keep in mind the legend width is stretched because the width attr of the canvas is 1
// See http://stackoverflow.com/questions/4899799/whats-the-best-way-to-set-a-single-pixel-in-an-html5-canvas
/*
d3.range(legendheight).forEach(function(i) {
ctx.fillStyle = colorscale(legendscale.invert(i));
ctx.fillRect(0,i,1,1);
});
*/
var legendaxis = d3.axisRight()
.scale(legendscale)
.tickSize(6)
.ticks(8);
var svg = d3.select(selector_id)
.append("svg")
.attr("height", (legendheight) + "px")
.attr("width", (legendwidth) + "px")
.style("position", "absolute")
.style("left", "0px")
.style("top", "0px")
svg
.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + (legendwidth - margin.left - margin.right + 3) + "," + (margin.top) + ")")
.call(legendaxis);
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment