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/e7d3c5c1386abe292d6aba5e9b4fa857 to your computer and use it in GitHub Desktop.
Save eesur/e7d3c5c1386abe292d6aba5e9b4fa857 to your computer and use it in GitHub Desktop.
d3 | time shown as percentage

using a waffle chart to show time in percentage. Updating every second and squares/percentage is rounded down to nearest integer

*{box-sizing:border-box}* body{font-family:-apple-system,BlinkMacSystemFont,Consolas,monaco,monospace;width:800px;margin:0 auto;background:#ccc}* .colon{color:#e0e5db;font-size:72px;right:5px}* .charts .colon{top:60px}* .digits .colon{top:-12px;color:#aaa}* .digit{color:#454545;font-weight:400}
!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: '#2f292b',\n squareBgd: '#e0e5db',\n strokeCol: '#ccc',\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/OWE5NSJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBkMyA9IHdpbmRvdy5kM1xuXG5kMy53YWZmbGUgPSBmdW5jdGlvbiAoYmluZCwgdmFsdWUgPSAxMDAsIGNvbmZpZykge1xuICBjb25maWcgPSB7XG4gICAgc3F1YXJlQ29sOiAnIzJmMjkyYicsXG4gICAgc3F1YXJlQmdkOiAnI2UwZTVkYicsXG4gICAgc3Ryb2tlQ29sOiAnI2NjYycsXG4gICAgc3F1YXJlU2l6ZTogMjAsXG4gICAgc3Ryb2tlV2lkdGg6IDIsXG4gICAgLi4uY29uZmlnLFxuICAgIG1hcmdpbjoge1xuICAgICAgdG9wOiA1LFxuICAgICAgcmlnaHQ6IDUsXG4gICAgICBib3R0b206IDUsXG4gICAgICBsZWZ0OiA1LFxuICAgICAgLi4uKGNvbmZpZyB8fCB7fSkubWFyZ2luXG4gICAgfVxuICB9XG4gIGNvbnN0IHsgbWFyZ2luLCBzcXVhcmVTaXplLCBzcXVhcmVDb2wsIHNxdWFyZUJnZCwgc3Ryb2tlQ29sLCBzdHJva2VXaWR0aCB9ID0gY29uZmlnXG5cbiAgY29uc3Qgc2l6ZSA9IChzcXVhcmVTaXplICsgKHN0cm9rZVdpZHRoICogMikpICogMTBcblxuICBjb25zdCBzZWxlY3Rpb24gPSBkMy5zZWxlY3QoYmluZClcblxuICAvLyBhcHBlbmQgdGhlIHN2ZyBpZiBmaXJzdCByZW5kZXJcbiAgaWYgKHNlbGVjdGlvbi5zZWxlY3QoJ3N2ZycpLmVtcHR5KCkpIHtcbiAgICBzZWxlY3Rpb25cbiAgICAgIC5hcHBlbmQoJ3N2ZycpXG4gICAgICAuYXR0cignd2lkdGgnLCBzaXplICsgbWFyZ2luLmxlZnQgKyBtYXJnaW4ucmlnaHQpXG4gICAgICAuYXR0cignaGVpZ2h0Jywgc2l6ZSArIG1hcmdpbi50b3AgKyBtYXJnaW4uYm90dG9tKVxuICAgICAgLmFwcGVuZCgnZycpXG4gICAgICAuYXR0cigndHJhbnNmb3JtJywgYHRyYW5zbGF0ZSgke21hcmdpbi5sZWZ0fSwgJHttYXJnaW4udG9wfSlgKVxuICAgICAgLmNhbGwoZ3JpZDEwYnkxMClcbiAgfVxuXG4gIGZ1bmN0aW9uIGdyaWQxMGJ5MTAgKHNlbCkge1xuICAgIGNvbnN0IHNjYWxlID0gZDMuc2NhbGVMaW5lYXIoKVxuICAgICAgLmRvbWFpbihbMCwgOV0pXG4gICAgICAucmFuZ2UoWzAsIHNxdWFyZVNpemUgKiAxMF0pXG5cbiAgICBjb25zdCBqb2luID0gc2VsLnNlbGVjdEFsbCgncmVjdCcpXG4gICAgICAuZGF0YShkMy5yYW5nZSgxMDApKVxuXG4gICAgam9pbi5lbnRlcigpLmFwcGVuZCgncmVjdCcpXG4gICAgICAuYXR0cigneCcsIChkLCBpKSA9PiB7XG4gICAgICAgIGNvbnN0IG4gPSBpICUgMTBcbiAgICAgICAgcmV0dXJuIHNjYWxlKG4pXG4gICAgICB9KVxuICAgICAgLmF0dHIoJ3knLCAoZCwgaSkgPT4ge1xuICAgICAgICBjb25zdCBuID0gTWF0aC5mbG9vcihpIC8gMTApXG4gICAgICAgIHJldHVybiBzY2FsZShuKVxuICAgICAgfSlcbiAgICAgIC5hdHRyKCd3aWR0aCcsIHNxdWFyZVNpemUpXG4gICAgICAuYXR0cignaGVpZ2h0Jywgc3F1YXJlU2l6ZSlcbiAgICAgIC5hdHRyKCdzdHJva2Utd2lkdGgnLCBzdHJva2VXaWR0aClcbiAgICAgIC5hdHRyKCdzdHJva2UnLCBzdHJva2VDb2wpXG4gICAgICAubWVyZ2Uoam9pbilcbiAgICAgIC8vIG5vdGUgPCBub3QgPD0gYXMgY291bnRpbmcgZnJvbSAwXG4gICAgICAudHJhbnNpdGlvbigpXG4gICAgICAuYXR0cignZmlsbCcsIChkLCBpKSA9PiAoaSA8IHZhbHVlKSA/IHNxdWFyZUNvbCA6IHNxdWFyZUJnZClcblxuICAgIC8vIGpvaW4uZXhpdCgpLnJlbW92ZSgpXG4gIH1cblxuICByZXR1cm4gc2VsZWN0aW9uLnNlbGVjdCgnc3ZnIGcnKS5jYWxsKGdyaWQxMGJ5MTApXG59XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gc2NyaXB0LmpzIl0sIm1hcHBpbmdzIjoiOzs7O0FBQUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBTEE7QUFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBSkE7QUFQQTtBQURBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQWdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFHQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFNQTtBQWRBO0FBZ0JBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///0\n")}]);
<!DOCTYPE html>
<title>d3 | percentage time</title>
<link href='https://unpkg.com/basscss@8.0.2/css/basscss.min.css' rel='stylesheet'>
<link href='dist.css' rel='stylesheet' />
<body>
<div class='clearfix mt4 charts'>
<section class='col col-4 relative'>
<div class='chart-hours'></div>
<span class='colon absolute'>:</span>
</section>
<section class='col col-4 relative'>
<div class='chart-minutes'></div>
<span class='colon absolute'>:</span>
</section>
<section class='col col-4'>
<div class='chart-seconds'></div>
</section>
</div>
<!-- labels for percent -->
<div class='clearfix mt3 digits'>
<section class='col col-4 relative'>
<h2 class='center digit percent-hour'>%</h2>
<span class='colon absolute'>:</span>
</section>
<section class='col col-4 relative'>
<h2 class='center digit percent-minutes'>%</h2>
<span class='colon absolute'>:</span>
</section>
<section class='col col-4'>
<h2 class='center digit percent-seconds'>%</h2>
</section>
</div>
<!-- label for times -->
<div class='clearfix digits mt4 time'>
<section class='col col-4 relative'>
<h2 class='center digit time-hour'>Hr</h2>
<span class='colon absolute'>:</span>
</section>
<section class='col col-4 relative'>
<h2 class='center digit time-minutes'>Min</h2>
<span class='colon absolute'>:</span>
</section>
<section class='col col-4'>
<h2 class='center digit time-seconds'>Secs</h2>
</section>
</div>
<script src='https://d3js.org/d3.v4.min.js'></script>
<script src='dist.js'></script>
<!-- render code -->
<script>
(function () {
var d3 = window.d3
var hoursChart = d3.waffle
var minutesChart = d3.waffle
var secondsChart = d3.waffle
function render () {
var now = new Date()
// render time labels
var hours = now.getHours()
var minutes = now.getMinutes()
var seconds = now.getSeconds()
d3.select('.time-hour').text(hours + ' hrs')
d3.select('.time-minutes').text(minutes + ' mins')
d3.select('.time-seconds').text(seconds + ' secs')
// render percent labels
var hoursPercent = Math.floor((100 / 24) * hours)
var minutesPercent = Math.floor((100 / 60) * minutes)
var secondsPercent = Math.floor((100 / 60) * seconds)
d3.select('.percent-hour').text(hoursPercent + ' %')
d3.select('.percent-minutes').text(minutesPercent + ' %')
d3.select('.percent-seconds').text(secondsPercent + ' %')
// render charts
hoursChart('.chart-hours', hoursPercent)
minutesChart('.chart-minutes', minutesPercent)
secondsChart('.chart-seconds', secondsPercent)
}
// start with render
render()
d3.interval(function () {
render()
}, 1000)
// change frame height
d3.select(self.frameElement).style('height', '600px')
}())
</script>
</body>
const d3 = window.d3
d3.waffle = function (bind, value = 100, config) {
config = {
squareCol: '#2f292b',
squareBgd: '#e0e5db',
strokeCol: '#ccc',
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: 800px
margin: 0 auto
background: #ccc
.colon
color:#e0e5db
font-size: 72px
right: 5px
.charts .colon
top: 60px
.digits .colon
top: -12px
color:#aaa
.digit
color: #454545
font-weight: normal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment