Skip to content

Instantly share code, notes, and snippets.

@larsvers
Last active November 25, 2016 23:43
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save larsvers/63927f8910028b2c090b9fc82b9f077d to your computer and use it in GitHub Desktop.
Square grid playground
license: mit

Built on top of this example yet transferred to canvas and v4. Also added some colours and an option to change them as the little grey squares looked a little sad.

Built with blockbuilder.org

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>grid 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;
}
.explain, #select {
display: inline-block;
font-size: 0.75em;
margin-bottom: 1em;
}
.alert {
color: tomato;
}
</style>
</head>
<body>
<h3>Coloured grids on canvas</h3>
<input type="text" id="textinput" value="10000">
<div class="explain" id="text-explain">...takes numbers between 1 and 10k &nbsp;&nbsp;&nbsp;&middot;&nbsp;&nbsp;&nbsp;</div>
<div id="select"></div>
<div class="explain">...from <a href="https://github.com/d3/d3-scale-chromatic">d3-scale-chromatic</a></div>
<div id="container"></div>
<script>
var log = console.log.bind(console);
var dir = console.dir.bind(console);
var replace = function(string) { return string.replace(/[^a-z0-9]/gi,""); };
// === Set up canvas === //
var width = 750,
height = 750;
var data;
var value = 10000;
var colours = ['interpolateBrBG', 'interpolatePRGn', 'interpolatePiYG', 'interpolatePuOr', 'interpolateRdBu', 'interpolateRdGy', 'interpolateRdYlBu', 'interpolateRdYlGn', 'interpolateSpectral', 'interpolateBlues', 'interpolateGreens', 'interpolateGreys', 'interpolateOranges', 'interpolatePurples', 'interpolateReds', 'interpolateBuGn', 'interpolateBuPu', 'interpolateGnBu', 'interpolateOrRd', 'interpolatePuBuGn', 'interpolatePuBu', 'interpolatePuRd', 'interpolateRdPu', 'interpolateYlGnBu', 'interpolateYlGn', 'interpolateYlOrBr', 'interpolateYlOrRd']
var numberScale;
var colourId = 8;
var canvas = d3.select('#container')
.append('canvas')
.attr('width', width)
.attr('height', height);
var context = canvas.node().getContext('2d');
// === Load and prepare the data === //
data = d3.range(value);
makeDropdown(colours)
function makeDropdown(colours) {
var select = d3.select('#select')
.append('select');
var options = select.selectAll('option.options')
.data(colours)
.enter()
.append('option')
.attr('class', 'options')
.attr('value', function(d) { return d; })
.html(function(d) { return d; });
document.querySelectorAll('.options')[colourId].selected = true;
makeChart(data);
}
function makeChart(data) {
// === Bind data to custom elements === //
var customBase = document.createElement('custom');
var custom = d3.select(customBase); // this is our svg replacement
// settings for a grid with 40 cells in a row and 2x5 cells in a group
var groupSpacing = 4;
var cellSpacing = 2;
var offsetTop = height / 5;
// var cellSize = (width - 20 * cellSpacing - 3 * groupSpacing) / 20;
var cellSize = Math.floor((width - 11 * groupSpacing) / 100) - cellSpacing;
// === First call === //
databind(d3.range(value), colourId); // ...then update the databind function
var t = d3.timer(function(elapsed) {
draw();
if (elapsed > 500) t.stop();
}); // start a timer that runs the draw function for 500 ms (this needs to be higher than the transition in the databind function)
// === Bind and draw functions === //
function databind(data, colourId) {
numberScale = d3.scaleSequential(d3[colours[colourId]]).domain(d3.extent(data, function(d) { return d; }));
var join = custom.selectAll('custom.rect')
.data(data);
var enterSel = join.enter()
.append('custom')
.attr('class', 'rect')
.attr("x", function(i) {
var x0 = Math.floor(i / 100) % 10, x1 = Math.floor(i % 10);
return groupSpacing * x0 + (cellSpacing + cellSize) * (x1 + x0 * 10);
})
.attr("y", function(i) {
var y0 = Math.floor(i / 1000), 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 numberScale(d); });
var exitSel = join.exit()
.transition()
.attr('width', 0)
.attr('height', 0)
.remove();
} // databind()
// === Draw canvas === //
function draw() {
// clear canvas
context.fillStyle = '#fff';
context.fillRect(0, 0, width, height);
// draw each individual custom element with their properties
var elements = custom.selectAll('custom.rect') // this is the same as the join variable, but used here to draw
elements.each(function(d,i) {
// for each virtual/custom element...
var node = d3.select(this);
context.fillStyle = node.attr('fillStyle');
context.fillRect(node.attr('x'), node.attr('y'), node.attr('width'), node.attr('height'))
});
} // draw()
// === Listeners/handlers === //
d3.select('#textinput').on('keydown', function() {
if (d3.event.keyCode === 13) {
d3.select('#alert').html('');
if (+this.value < 1 || +this.value > 10000) {
d3.select('#text-explain').classed('alert', true);
return;
} else {
d3.select('#text-explain').classed('alert', false);
value = +this.value;
databind(d3.range(value), colourId);
var t = d3.timer(function(elapsed) {
draw();
if (elapsed > 500) t.stop();
}); // start a timer that runs the draw function for 500 ms (this needs to be higher than the transition in the databind function)
}
} // keyCode 13 === return
}); // text input listener/handler
d3.select('select').on('change', function() {
log('fire');
log(this.value);
colourId = colours.indexOf(this.value);
log('colourId', colourId);
log('value', value);
databind(d3.range(value), colourId); // ...then update the databind function
var t = d3.timer(function(elapsed) {
draw();
if (elapsed > 500) t.stop();
}); // start a timer that runs the draw function for 500 ms (this needs to be higher than the transition in the databind function)
}); // select handler/listener
} // makeChart()
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment