Skip to content

Instantly share code, notes, and snippets.

@eesur
Last active October 23, 2019 21:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save eesur/d36981a96b8a69865a24e473194194a6 to your computer and use it in GitHub Desktop.
Save eesur/d36981a96b8a69865a24e473194194a6 to your computer and use it in GitHub Desktop.
d3 | modulo operation to create a grid
license: mit
height: 500
border: no

broke this down and wrote about it on medium

*{box-sizing:border-box}* body{font-family:-apple-system,BlinkMacSystemFont,Consolas,monaco,monospace;width:650px;margin:0 auto;position:relative;background:#ccc}* #value{color:#de3d83;letter-spacing:1px;font-size:72px;position:absolute;top:20px;right:20px;text-align:right}
!function(n){function g(e){if(t[e])return t[e].exports;var i=t[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,g),i.l=!0,i.exports}var t={};g.m=n,g.c=t,g.i=function(n){return n},g.d=function(n,t,e){g.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e})},g.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return g.d(t,"a",t),t},g.o=function(n,g){return Object.prototype.hasOwnProperty.call(n,g)},g.p="",g(g.s=0)}([function(module,exports,__webpack_require__){"use strict";eval("\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar d3 = window.d3;\n\nd3.waffle = function (bind) {\n var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100;\n var config = arguments[2];\n\n config = _extends({\n squareCol: '#de3d83',\n squareBgd: '#e0e5db',\n strokeCol: '#fff',\n squareSize: 20,\n strokeWidth: 2\n }, config, {\n margin: _extends({\n top: 5,\n right: 5,\n bottom: 5,\n left: 5\n }, (config || {}).margin)\n });\n var _config = config,\n margin = _config.margin,\n squareSize = _config.squareSize,\n squareCol = _config.squareCol,\n squareBgd = _config.squareBgd,\n strokeCol = _config.strokeCol,\n strokeWidth = _config.strokeWidth;\n\n\n var size = (squareSize + strokeWidth * 2) * 10;\n\n var selection = d3.select(bind);\n\n // append the svg if first render\n if (selection.select('svg').empty()) {\n selection.append('svg').attr('width', size + margin.left + margin.right).attr('height', size + margin.top + margin.bottom).append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')').call(grid10by10);\n }\n\n function grid10by10(sel) {\n var scale = d3.scaleLinear().domain([0, 9]).range([0, squareSize * 10]);\n\n var join = sel.selectAll('rect').data(d3.range(100));\n\n join.enter().append('rect').attr('x', function (d, i) {\n var n = i % 10;\n return scale(n);\n }).attr('y', function (d, i) {\n var n = Math.floor(i / 10);\n return scale(n);\n }).attr('width', squareSize).attr('height', squareSize).attr('stroke-width', strokeWidth).attr('stroke', strokeCol).merge(join)\n // note < not <= as counting from 0\n .transition().attr('fill', function (d, i) {\n return i < value ? squareCol : squareBgd;\n });\n\n // join.exit().remove()\n }\n\n return selection.select('svg g').call(grid10by10);\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMC5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy9zY3JpcHQuanM/OWE5NSJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBkMyA9IHdpbmRvdy5kM1xuXG5kMy53YWZmbGUgPSBmdW5jdGlvbiAoYmluZCwgdmFsdWUgPSAxMDAsIGNvbmZpZykge1xuICBjb25maWcgPSB7XG4gICAgc3F1YXJlQ29sOiAnI2RlM2Q4MycsXG4gICAgc3F1YXJlQmdkOiAnI2UwZTVkYicsXG4gICAgc3Ryb2tlQ29sOiAnI2ZmZicsXG4gICAgc3F1YXJlU2l6ZTogMjAsXG4gICAgc3Ryb2tlV2lkdGg6IDIsXG4gICAgLi4uY29uZmlnLFxuICAgIG1hcmdpbjoge1xuICAgICAgdG9wOiA1LFxuICAgICAgcmlnaHQ6IDUsXG4gICAgICBib3R0b206IDUsXG4gICAgICBsZWZ0OiA1LFxuICAgICAgLi4uKGNvbmZpZyB8fCB7fSkubWFyZ2luXG4gICAgfVxuICB9XG4gIGNvbnN0IHsgbWFyZ2luLCBzcXVhcmVTaXplLCBzcXVhcmVDb2wsIHNxdWFyZUJnZCwgc3Ryb2tlQ29sLCBzdHJva2VXaWR0aCB9ID0gY29uZmlnXG5cbiAgY29uc3Qgc2l6ZSA9IChzcXVhcmVTaXplICsgKHN0cm9rZVdpZHRoICogMikpICogMTBcblxuICBjb25zdCBzZWxlY3Rpb24gPSBkMy5zZWxlY3QoYmluZClcblxuICAvLyBhcHBlbmQgdGhlIHN2ZyBpZiBmaXJzdCByZW5kZXJcbiAgaWYgKHNlbGVjdGlvbi5zZWxlY3QoJ3N2ZycpLmVtcHR5KCkpIHtcbiAgICBzZWxlY3Rpb25cbiAgICAgIC5hcHBlbmQoJ3N2ZycpXG4gICAgICAuYXR0cignd2lkdGgnLCBzaXplICsgbWFyZ2luLmxlZnQgKyBtYXJnaW4ucmlnaHQpXG4gICAgICAuYXR0cignaGVpZ2h0Jywgc2l6ZSArIG1hcmdpbi50b3AgKyBtYXJnaW4uYm90dG9tKVxuICAgICAgLmFwcGVuZCgnZycpXG4gICAgICAuYXR0cigndHJhbnNmb3JtJywgYHRyYW5zbGF0ZSgke21hcmdpbi5sZWZ0fSwgJHttYXJnaW4udG9wfSlgKVxuICAgICAgLmNhbGwoZ3JpZDEwYnkxMClcbiAgfVxuXG4gIGZ1bmN0aW9uIGdyaWQxMGJ5MTAgKHNlbCkge1xuICAgIGNvbnN0IHNjYWxlID0gZDMuc2NhbGVMaW5lYXIoKVxuICAgICAgLmRvbWFpbihbMCwgOV0pXG4gICAgICAucmFuZ2UoWzAsIHNxdWFyZVNpemUgKiAxMF0pXG5cbiAgICBjb25zdCBqb2luID0gc2VsLnNlbGVjdEFsbCgncmVjdCcpXG4gICAgICAuZGF0YShkMy5yYW5nZSgxMDApKVxuXG4gICAgam9pbi5lbnRlcigpLmFwcGVuZCgncmVjdCcpXG4gICAgICAuYXR0cigneCcsIChkLCBpKSA9PiB7XG4gICAgICAgIGNvbnN0IG4gPSBpICUgMTBcbiAgICAgICAgcmV0dXJuIHNjYWxlKG4pXG4gICAgICB9KVxuICAgICAgLmF0dHIoJ3knLCAoZCwgaSkgPT4ge1xuICAgICAgICBjb25zdCBuID0gTWF0aC5mbG9vcihpIC8gMTApXG4gICAgICAgIHJldHVybiBzY2FsZShuKVxuICAgICAgfSlcbiAgICAgIC5hdHRyKCd3aWR0aCcsIHNxdWFyZVNpemUpXG4gICAgICAuYXR0cignaGVpZ2h0Jywgc3F1YXJlU2l6ZSlcbiAgICAgIC5hdHRyKCdzdHJva2Utd2lkdGgnLCBzdHJva2VXaWR0aClcbiAgICAgIC5hdHRyKCdzdHJva2UnLCBzdHJva2VDb2wpXG4gICAgICAubWVyZ2Uoam9pbilcbiAgICAgIC8vIG5vdGUgPCBub3QgPD0gYXMgY291bnRpbmcgZnJvbSAwXG4gICAgICAudHJhbnNpdGlvbigpXG4gICAgICAuYXR0cignZmlsbCcsIChkLCBpKSA9PiAoaSA8IHZhbHVlKSA/IHNxdWFyZUNvbCA6IHNxdWFyZUJnZClcblxuICAgIC8vIGpvaW4uZXhpdCgpLnJlbW92ZSgpXG4gIH1cblxuICByZXR1cm4gc2VsZWN0aW9uLnNlbGVjdCgnc3ZnIGcnKS5jYWxsKGdyaWQxMGJ5MTApXG59XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gc2NyaXB0LmpzIl0sIm1hcHBpbmdzIjoiOzs7O0FBQUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBTEE7QUFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBSkE7QUFQQTtBQURBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQWdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFHQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFNQTtBQWRBO0FBZ0JBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///0\n")}]);
<!DOCTYPE html>
<title>d3 | modulo operation to create a grid</title>
<link href='dist.css' rel='stylesheet' />
<body>
<div>
<div id="waffle"></div>
<span id="value"></span>
</div>
<script src='https://d3js.org/d3.v4.min.js'></script>
<script src='dist.js'></script>
<!-- render code -->
<script>
const d3 = window.d3
// render an update
const chart = d3.waffle
d3.interval(function () {
let n = Math.floor(d3.randomUniform(5, 100)())
chart('#waffle', n, {
strokeCol: '#ccc',
margin: {top: 35},
squareSize: 40,
strokeWidth: 2
})
d3.select('#value').html(n + '%')
}, 1000)
</script>
</body>
const d3 = window.d3
d3.waffle = function (bind, value = 100, config) {
config = {
squareCol: '#de3d83',
squareBgd: '#e0e5db',
strokeCol: '#fff',
squareSize: 20,
strokeWidth: 2,
...config,
margin: {
top: 5,
right: 5,
bottom: 5,
left: 5,
...(config || {}).margin
}
}
const { margin, squareSize, squareCol, squareBgd, strokeCol, strokeWidth } = config
const size = (squareSize + (strokeWidth * 2)) * 10
const selection = d3.select(bind)
// append the svg if first render
if (selection.select('svg').empty()) {
selection
.append('svg')
.attr('width', size + margin.left + margin.right)
.attr('height', size + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
.call(grid10by10)
}
function grid10by10 (sel) {
const scale = d3.scaleLinear()
.domain([0, 9])
.range([0, squareSize * 10])
const join = sel.selectAll('rect')
.data(d3.range(100))
join.enter().append('rect')
.attr('x', (d, i) => {
const n = i % 10
return scale(n)
})
.attr('y', (d, i) => {
const n = Math.floor(i / 10)
return scale(n)
})
.attr('width', squareSize)
.attr('height', squareSize)
.attr('stroke-width', strokeWidth)
.attr('stroke', strokeCol)
.merge(join)
// note < not <= as counting from 0
.transition()
.attr('fill', (d, i) => (i < value) ? squareCol : squareBgd)
// join.exit().remove()
}
return selection.select('svg g').call(grid10by10)
}
*
box-sizing border-box
body
font-family:-apple-system,BlinkMacSystemFont,Consolas,monaco,monospace
width: 650px
margin: 0 auto
position: relative
background: #ccc
#value
color: #de3d83
letter-spacing: 1px
font-size: 72px
position: absolute
top: 20px
right: 20px
text-align: right
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment