Skip to content

Instantly share code, notes, and snippets.

@mthh
Last active July 31, 2018 22:33
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 mthh/59c50f1776cc3383e547e2e99033c7bc to your computer and use it in GitHub Desktop.
Save mthh/59c50f1776cc3383e547e2e99033c7bc to your computer and use it in GitHub Desktop.
XKCD-style grid chart
license: mit
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<style>
@font-face {
font-family: "xkcd";
src: url('Humor-Sans-1.0.ttf');
}
body {
font-family: "xkcd", sans-serif;
font-size: 16px;
color: #333;
}
.title, #grid {
text-align: center;
margin: auto;
}
.title {
margin-left: 80px;
margin-bottom: 30px;
}
select > * {
font-family: "xkcd", sans-serif;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div class="title">
<h3>How long can you work on making a routine task more<br>efficient before you're spending more time than you save?</h3>
<p>Across <select id="select_years"></select> years</p>
</div>
<div id="grid"></div>
<script>
function convertSeconds(sec) {
let seconds = sec;
let day, hour, minute;
minute = Math.floor(seconds / 60);
seconds = seconds % 60;
hour = Math.floor(minute / 60);
minute = minute % 60;
day = Math.floor(hour / 24);
hour = hour % 24;
return {
day: day,
hour: hour,
minute: minute,
seconds: seconds
};
}
function makeGridTime(years=5, width, height) {
const data = [];
let xpos = 1;
let ypos = 1;
let t;
let t1;
let rows;
for (let row = 0; row < 9; row++) {
rows = [];
if (row === 0) {
// 1 second
t = 1;
} else if (row === 1) {
// 5 seconds
t = 5;
} else if (row === 2) {
// 30 seconds
t = 30;
} else if (row === 3) {
// 1 minute
t = 60;
} else if (row === 4) {
// 5 minutes
t = 60 * 5;
} else if (row === 5) {
// 3O minutes
t = 60 * 30;
} else if (row === 6) {
// 1 hours
t = 3600;
} else if (row === 7) {
// 6 hours
t = 3600 * 6;
} else if (row === 8) {
// 1 day
t = 3600 * 24;
}
for (let column = 0; column < 6; column++) {
if (column === 0) {
// 50 times per day
t1 = t * 50 * 365 * years;
} else if (column === 1) {
// 5 times per day
t1 = t * 5 * 365 * years;
} else if (column === 2) {
// daily
t1 = t * 365 * years;
} else if (column === 3) {
// weekly
t1 = t * 52 * years;
} else if (column === 4) {
// monthly
t1 = t * 12 * years;
} else if (column === 5) {
// yearly
t1 = t * 1 * years;
}
let time = convertSeconds(t1);
let value;
if (time.minute === 0 && time.day === 0 && time.hour == 0){
value = `${time.seconds} seconds`
} else if (time.hour === 0 && time.day === 0) {
value = `${time.minute} minutes`
} else if (time.hour > 21 && time.hour < 30 && time.day === 0) {
value = `1 day`
} else if (time.day === 0) {
value = `${time.hour} hours`;
} else if (time.day > 32) {
value = `${Math.round(time.day / 31)} months`
} else if (time.day > 5 && time.day % 7 <= 3) {
value = `${(time.day - (time.day % 7)) / 7} weeks`
} else {
value = `${time.day} days`;
}
value = value.split(' ');
rows.push({
x: xpos,
y: ypos,
width: width,
height: height,
click: 0,
value: value[0],
unit: value[1],
value_second: t1,
})
xpos += width;
}
data.push(rows);
xpos = 1;
ypos += height;
}
return data;
}
function makeChart(years) {
d3.select("#grid").selectAll('*').remove()
let width_cell = 85;
let height_cell = 45;
let gridData = makeGridTime(years, width_cell, height_cell);
let margin = {
left: 160,
right: 40,
top: 40,
bottom: 40,
};
let width = (width_cell + 1) * 6 + margin.left + margin.right;
let height = (height_cell + 1) * 9 + margin.top + margin.bottom;
let svg = d3.select("#grid")
.append("svg")
.attr("width", width)
.attr("height", height);
let grid = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
let xaxis = svg.append('g')
.attr('transform', `translate(${margin.left}, 0)`);
xaxis.append('text')
.attr('text-anchor', 'middle')
.attr('x', (width - margin.left) / 2)
.attr('y', 10)
.text('HOW OFTEN YOU DO THE TASK');
xaxis.selectAll('.axislabel')
.data(['50/DAY', '5/DAY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'])
.enter()
.append('text')
.attr('x', (_, i) => (width_cell / 2) + (i * width_cell))
.attr('y', 30)
.attr('font-size', 11)
.attr('text-anchor', 'middle')
.text(d => d)
let yaxis = svg.append('g')
.attr('transform', `translate(0, ${margin.top})`);
yaxis.selectAll('.axislabel2')
.data('HOW MUCH TIME YOU SHAVE OFF'.split(' '))
.enter()
.append('text')
.attr('x', 65)
.attr('y', (_, i) => 155 + i * 19)
.attr('text-anchor', 'end')
.text(d => d)
yaxis.selectAll('.axislabel')
.data(['1 SECOND', '5 SECONDS', '30 SECONDS', '1 MINUTE', '5 MINUTES', '30 MINUTES', '1 HOUR', '6 HOURS', '1 DAY'])
.enter()
.append('text')
.attr('x', margin.left - 5)
.attr('y', (_, i) => (height_cell / 2) + (i * height_cell))
.attr('font-size', 11)
.attr('text-anchor', 'end')
.text(d => d);
let row = grid.selectAll(".row")
.data(gridData)
.enter().append("g")
.attr("class", "row");
let column = row.selectAll(".square")
.data(d => d)
.enter().append("rect")
.attr("class","square")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("width", function(d) { return d.width; })
.attr("height", function(d) { return d.height; })
.style("fill", d => +d.value_second >= 31536000 * 0.9 ? 'gray' : 'white' )
.style("stroke", "#222")
.on('click', function(d) {
d.click++;
if ((d.click)%4 == 0 ) { d3.select(this).style("fill","#fff"); }
if ((d.click)%4 == 1 ) { d3.select(this).style("fill","#2C93E8"); }
if ((d.click)%4 == 2 ) { d3.select(this).style("fill","#F56C4E"); }
});
grid.append('g')
.selectAll('.labelvalue')
.data(gridData.reduce((acc, val) => acc.concat(val), []))
.enter()
.append('text')
.attr('class', 'labelvalue')
.attr('x', d => d.x + 15)
.attr('y', d => d.y + 15)
.html(d => +d.value_second < 31536000 * 0.9 ? d.value : null);
grid.append('g')
.selectAll('.labelunit')
.data(gridData.reduce((acc, val) => acc.concat(val), []))
.enter()
.append('text')
.attr('class', 'labelunit')
.attr('x', d => d.x + 15)
.attr('y', d => d.y + 35)
.html(d => +d.value_second < 31536000 * 0.9 ? d.unit : null);
}
const select_years = d3.select('#select_years');
select_years.append('option').attr('value', 2).text('two');
select_years.append('option').attr('value', 3).text('three');
select_years.append('option').attr('value', 4).text('four');
select_years.append('option').attr('value', 5).text('five');
select_years.on('change', function() {
makeChart(+this.value);
});
select_years.node().value = 5;
select_years.node().dispatchEvent(new Event('change'));
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment