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
forked from larsvers's block: 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
forked from larsvers's block: Square grid playground
| <!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 · </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> |