Skip to content

Instantly share code, notes, and snippets.

@long1eu
Last active February 22, 2026 08:57
Show Gist options
  • Select an option

  • Save long1eu/7b3003095c422131d8596bf96c1ebed5 to your computer and use it in GitHub Desktop.

Select an option

Save long1eu/7b3003095c422131d8596bf96c1ebed5 to your computer and use it in GitHub Desktop.
Taper daily usage chart
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Taper Chart</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #0f0f13;
color: #e0e0e0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
padding: 32px;
}
h1 { font-size: 1.3rem; font-weight: 500; color: #aaa; margin-bottom: 6px; }
.subtitle { font-size: 0.85rem; color: #555; margin-bottom: 28px; }
canvas { display: block; border-radius: 8px; background: #16161c; }
.legend { display: flex; gap: 20px; margin-top: 14px; font-size: 0.8rem; color: #666; }
.legend-item { display: flex; align-items: center; gap: 6px; }
.swatch { width: 12px; height: 12px; border-radius: 3px; }
</style>
</head>
<body>
<h1>Taper — Daily Usage</h1>
<p class="subtitle">Feb 13 – Feb 23, 2026 · Scheduled window: 10:00–18:00</p>
<canvas id="c"></canvas>
<div class="legend">
<div class="legend-item"><div class="swatch" style="background:#4ade80"></div> Within window (done)</div>
<div class="legend-item"><div class="swatch" style="background:#f87171"></div> Outside window (over)</div>
<div class="legend-item"><div class="swatch" style="background:rgba(250,204,21,0.6)"></div> Daily max</div>
</div>
<script>
var data = [
{label:"Feb 13\n(pre)", max:3000, done:0, over:152.5},
{label:"Feb 14\nD1", max:3000, done:25, over:321},
{label:"Feb 15\nD2", max:3000, done:125, over:178.8},
{label:"Feb 16\nD3", max:3000, done:137.5,over:550},
{label:"Feb 17\nD4", max:2700, done:15.4, over:229},
{label:"Feb 18\nD5", max:2700, done:30.6, over:201.5},
{label:"Feb 19\nD6", max:2700, done:100, over:450},
{label:"Feb 20\nD7", max:2430, done:0, over:700},
{label:"Feb 21\nD8", max:2430, done:100, over:380.1},
{label:"Feb 22\nD9", max:2430, done:0, over:65},
{label:"Feb 23\nD10", max:2187, done:0, over:50},
];
var W = Math.min(window.innerWidth - 64, 900);
var H = 340;
var PAD = {top:24, right:24, bottom:56, left:52};
var c = document.getElementById("c");
c.width = W; c.height = H;
var ctx = c.getContext("2d");
var chartW = W - PAD.left - PAD.right;
var chartH = H - PAD.top - PAD.bottom;
var maxVal = 3200;
var n = data.length;
var barGroup = chartW / n;
var barW = barGroup * 0.6;
var barOff = (barGroup - barW) / 2;
function toY(v) { return PAD.top + chartH - (v / maxVal) * chartH; }
// Grid lines
ctx.strokeStyle = "#1e1e28";
ctx.lineWidth = 1;
[0, 500, 1000, 1500, 2000, 2500, 3000].forEach(function(v) {
var y = toY(v);
ctx.beginPath(); ctx.moveTo(PAD.left, y); ctx.lineTo(PAD.left + chartW, y); ctx.stroke();
ctx.fillStyle = "#444";
ctx.font = "10px system-ui";
ctx.textAlign = "right";
ctx.fillText(v, PAD.left - 6, y + 3);
});
// Bars
data.forEach(function(d, i) {
var x = PAD.left + i * barGroup + barOff;
var doneH = (d.done / maxVal) * chartH;
var overH = (d.over / maxVal) * chartH;
var total = d.done + d.over;
var totalH = (total / maxVal) * chartH;
var baseY = toY(0);
// over (bottom)
ctx.fillStyle = "rgba(248,113,113,0.85)";
ctx.fillRect(x, baseY - overH, barW, overH);
// done (on top)
ctx.fillStyle = "rgba(74,222,128,0.85)";
ctx.fillRect(x, baseY - overH - doneH, barW, doneH);
// total label
if (total > 0) {
ctx.fillStyle = "#888";
ctx.font = "10px system-ui";
ctx.textAlign = "center";
ctx.fillText(Math.round(total), x + barW/2, baseY - totalH - 5);
}
// x labels (two lines)
var parts = d.label.split("\n");
ctx.fillStyle = "#555";
ctx.font = "10px system-ui";
ctx.textAlign = "center";
ctx.fillText(parts[0], x + barW/2, H - PAD.bottom + 14);
ctx.fillStyle = "#3a3a4a";
ctx.fillText(parts[1] || "", x + barW/2, H - PAD.bottom + 26);
});
// Daily max line
ctx.beginPath();
ctx.strokeStyle = "rgba(250,204,21,0.55)";
ctx.lineWidth = 1.5;
ctx.setLineDash([6, 4]);
data.forEach(function(d, i) {
var x = PAD.left + i * barGroup + barOff;
var cx = x + barW/2;
var y = toY(d.max);
if (i === 0) ctx.moveTo(cx, y);
else ctx.lineTo(cx, y);
});
ctx.stroke();
ctx.setLineDash([]);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment