Skip to content

Instantly share code, notes, and snippets.

@JulienAssouline
Created February 11, 2018 21:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JulienAssouline/90da0ef574cf9afe2b02aabf07bc3f8f to your computer and use it in GitHub Desktop.
Save JulienAssouline/90da0ef574cf9afe2b02aabf07bc3f8f to your computer and use it in GitHub Desktop.
Canvas grid exercise
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>d3 and canvas</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="http://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<style type="text/css">
body {
font-family: 'Open Sans', sans-serif;
}
canvas {
border: 1px dotted #ccc;
}
#text-explain {
display: inline-block;
font-size: 0.75em;
margin-bottom: 1em;
}
.alert {
color: tomato;
}
</style>
</head>
<body>
<h3>Coloured grids</h3>
<input type="text" id="text-input" value="5000">
<div id="text-explain">...takes numbers between 1 and 10k</div>
<div id="container"></div>
<script>
var data = [];
var value = 5000;
console.log(data)
var width = 750,
height = 400;
var canvas = d3.select("#container")
.append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
d3.range(value).forEach(function(el){
data.push({value: el }) //The push() method adds new items to the end of an array, and returns the new length.
})
var customBase = document.createElement("custom");
var custom = d3.select(customBase); // This is your SVG replacement and the parent of all other elements
var groupSpacing = 4;
var cellSpacing = 2;
var offsetTop = height / 5;
var cellSize = Math.floor((width - 11 * groupSpacing) / 100)- cellSpacing;
databind(data); // ...then update the databind function
var t = d3.timer(function(elapsed) {
draw();
if (elapsed > 300) t.stop();
});
function databind(data) {
// Bind data to custom elements.
// Get a scale for the colours - not essential but nice.
colourScale = d3.scaleSequential(d3.interpolateSpectral)
.domain(d3.extent(data, function(d){ return d.value; }))
var join = custom.selectAll("custom.rect") // join your data to the ‘replacement-SVG’ you called custom
.data(data)
var enterSel = join.enter()
.append("custom")
.attr("class", "rect")
.attr("x", function(d, i){
var x0 = Math.floor(i / 100) % 10
var x1 = Math.floor(i % 10);
return groupSpacing * x0 + (cellSpacing + cellSize) * (x1 + x0 * 10);
})
.attr("y", function(d, i){
var y0 = Math.floor(i / 1000)
var y1 = Math.floor(i % 100 / 10)
return groupSpacing * y0 + (cellSpacing + cellSize) * (y1 + y0 * 10)
})
.attr("width", 0)
.attr("height", 0)
join.merge(enterSel)
.transition()
.attr("width", cellSize)
.attr("height", cellSize)
.attr("fillStyle", function(d){ return colourScale(d.value); });
var exitSel = join.exit()
.transition()
.attr("width", 0)
.attr("height", 0)
.remove();
} // databind
function draw(){
// Draw the elements on the canvas
context.fillStyle = '#fff';
context.fillRect(0, 0, width, height);
var elements = custom.selectAll("custom.rect"); // Grab all elements you bound data to in the databind() function.
elements.each(function(d, i){ // loop through each element
var node = d3.select(this); // This is each individual element in the loop.
context.fillStyle = node.attr("fillStyle"); // Here you retrieve the colour from the individual in-memory node and set the fillStyle for the canvas paint
context.fillRect(node.attr("x"), node.attr("y"), node.attr("width"), node.attr("height"));// Here you retrieve the position of the node and apply it to the fillRect context function which will fill and paint the square.
})
} //draw
d3.select("#text-input").on("keydown", function(){
if(d3.event.keyCode === 13){
// only do something if the user hits return (keycode 13).
if(+this.value < 1 || +this.value > 10000){
// if the user goes lower than 1 or higher than 10k...
d3.select("#text-explain").classed("alert", true);// ... highlight the note about the range and return.
return;
} else {
// If the user types in a sensible number...
d3.select("#text-explain").classed("alert", false);
// ...remove potential alert colours from the note...
value = +this.value; // ...set the value...
databind(d3.range(value));
var t = d3.timer(function(elapsed){
draw()
if(elapsed > 300) t.stop();
})
}
}
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment