spb/svgarden Public
SVGarden — searchable bank of 74 self-contained SVG+CSS animation snippets (svgarden.dev)
HTML 79.2%
Astro 10.3%
JavaScript 6%
CSS 3.7%
Shell 0.8%
1<!--2 ============================================================3 SVGarden — https://www.svgarden.dev4 Author : Simon-Pierre Boucher5 Contact: contact@spboucher.ai6 File : snippets/charts/chart-heat-calendar.html7 Desc : GitHub-style heat calendar cascading in diagonally8 ============================================================9-->10<!--svgarden11title: Heat calendar12slug: chart-heat-calendar13category: charts14tags: [chart, heatmap, calendar, cascade]15difficulty: intermediate16techniques: ["--sg-i index variables", "nth-of-type indexing", "fill-opacity levels", "css rect geometry"]17how_it_works: >18 Intensity is encoded the cheap way: every cell shares one fill (the accent19 color) and only fill-opacity changes across four level classes, which keeps20 the palette coherent on light and dark pages with zero color math. The21 diagonal cascade is coordinate arithmetic in CSS: each row group carries22 --sg-r, fourteen nth-of-type rules hand each column its --sg-c, and one rule23 computes animation-delay: calc((var(--sg-r) + var(--sg-c)) × step) — cells on24 the same anti-diagonal share r + c, so they pop together and the wave travels25 corner to corner. Cell geometry (width, height, rx) lives in CSS too, which26 is why each rect only needs x, y and a level class.27customizable:28 - { var: "--sg-color", label: "Heat color", type: color, default: "#7F77DD" }29 - { var: "--sg-size", label: "Width", type: range, min: 160, max: 420, default: 260, unit: px }30 - { var: "--sg-duration", label: "Cascade", type: range, min: 0.5, max: 4, step: 0.1, default: 1.4, unit: s }31created: 2026-08-1032-->33<div class="sg-chart-heat-calendar" style="--sg-color:#7F77DD; --sg-size:260px; --sg-duration:1.4s;">34 <svg viewBox="0 0 210 96" role="img" aria-label="Activity heat calendar, 14 weeks by 7 days, busiest midweek">35 <title>Contribution heat calendar</title>36 <text class="sg-chart-heat-calendar-day" x="18" y="23">M</text>37 <text class="sg-chart-heat-calendar-day" x="18" y="49">W</text>38 <text class="sg-chart-heat-calendar-day" x="18" y="75">F</text>39 <g class="sg-chart-heat-calendar-row" style="--sg-r:0"><rect x="22" y="2" class="sg-chart-heat-calendar-l0"/><rect x="35" y="2" class="sg-chart-heat-calendar-l0"/><rect x="48" y="2" class="sg-chart-heat-calendar-l1"/><rect x="61" y="2" class="sg-chart-heat-calendar-l0"/><rect x="74" y="2" class="sg-chart-heat-calendar-l0"/><rect x="87" y="2" class="sg-chart-heat-calendar-l1"/><rect x="100" y="2" class="sg-chart-heat-calendar-l0"/><rect x="113" y="2" class="sg-chart-heat-calendar-l0"/><rect x="126" y="2" class="sg-chart-heat-calendar-l0"/><rect x="139" y="2" class="sg-chart-heat-calendar-l1"/><rect x="152" y="2" class="sg-chart-heat-calendar-l0"/><rect x="165" y="2" class="sg-chart-heat-calendar-l0"/><rect x="178" y="2" class="sg-chart-heat-calendar-l1"/><rect x="191" y="2" class="sg-chart-heat-calendar-l0"/></g>40 <g class="sg-chart-heat-calendar-row" style="--sg-r:1"><rect x="22" y="15" class="sg-chart-heat-calendar-l1"/><rect x="35" y="15" class="sg-chart-heat-calendar-l2"/><rect x="48" y="15" class="sg-chart-heat-calendar-l1"/><rect x="61" y="15" class="sg-chart-heat-calendar-l2"/><rect x="74" y="15" class="sg-chart-heat-calendar-l3"/><rect x="87" y="15" class="sg-chart-heat-calendar-l1"/><rect x="100" y="15" class="sg-chart-heat-calendar-l2"/><rect x="113" y="15" class="sg-chart-heat-calendar-l1"/><rect x="126" y="15" class="sg-chart-heat-calendar-l3"/><rect x="139" y="15" class="sg-chart-heat-calendar-l2"/><rect x="152" y="15" class="sg-chart-heat-calendar-l1"/><rect x="165" y="15" class="sg-chart-heat-calendar-l2"/><rect x="178" y="15" class="sg-chart-heat-calendar-l2"/><rect x="191" y="15" class="sg-chart-heat-calendar-l1"/></g>41 <g class="sg-chart-heat-calendar-row" style="--sg-r:2"><rect x="22" y="28" class="sg-chart-heat-calendar-l2"/><rect x="35" y="28" class="sg-chart-heat-calendar-l1"/><rect x="48" y="28" class="sg-chart-heat-calendar-l3"/><rect x="61" y="28" class="sg-chart-heat-calendar-l2"/><rect x="74" y="28" class="sg-chart-heat-calendar-l1"/><rect x="87" y="28" class="sg-chart-heat-calendar-l2"/><rect x="100" y="28" class="sg-chart-heat-calendar-l3"/><rect x="113" y="28" class="sg-chart-heat-calendar-l2"/><rect x="126" y="28" class="sg-chart-heat-calendar-l1"/><rect x="139" y="28" class="sg-chart-heat-calendar-l3"/><rect x="152" y="28" class="sg-chart-heat-calendar-l2"/><rect x="165" y="28" class="sg-chart-heat-calendar-l1"/><rect x="178" y="28" class="sg-chart-heat-calendar-l3"/><rect x="191" y="28" class="sg-chart-heat-calendar-l2"/></g>42 <g class="sg-chart-heat-calendar-row" style="--sg-r:3"><rect x="22" y="41" class="sg-chart-heat-calendar-l1"/><rect x="35" y="41" class="sg-chart-heat-calendar-l3"/><rect x="48" y="41" class="sg-chart-heat-calendar-l2"/><rect x="61" y="41" class="sg-chart-heat-calendar-l3"/><rect x="74" y="41" class="sg-chart-heat-calendar-l2"/><rect x="87" y="41" class="sg-chart-heat-calendar-l3"/><rect x="100" y="41" class="sg-chart-heat-calendar-l1"/><rect x="113" y="41" class="sg-chart-heat-calendar-l3"/><rect x="126" y="41" class="sg-chart-heat-calendar-l2"/><rect x="139" y="41" class="sg-chart-heat-calendar-l2"/><rect x="152" y="41" class="sg-chart-heat-calendar-l3"/><rect x="165" y="41" class="sg-chart-heat-calendar-l3"/><rect x="178" y="41" class="sg-chart-heat-calendar-l1"/><rect x="191" y="41" class="sg-chart-heat-calendar-l3"/></g>43 <g class="sg-chart-heat-calendar-row" style="--sg-r:4"><rect x="22" y="54" class="sg-chart-heat-calendar-l2"/><rect x="35" y="54" class="sg-chart-heat-calendar-l2"/><rect x="48" y="54" class="sg-chart-heat-calendar-l1"/><rect x="61" y="54" class="sg-chart-heat-calendar-l1"/><rect x="74" y="54" class="sg-chart-heat-calendar-l3"/><rect x="87" y="54" class="sg-chart-heat-calendar-l2"/><rect x="100" y="54" class="sg-chart-heat-calendar-l2"/><rect x="113" y="54" class="sg-chart-heat-calendar-l3"/><rect x="126" y="54" class="sg-chart-heat-calendar-l1"/><rect x="139" y="54" class="sg-chart-heat-calendar-l2"/><rect x="152" y="54" class="sg-chart-heat-calendar-l3"/><rect x="165" y="54" class="sg-chart-heat-calendar-l1"/><rect x="178" y="54" class="sg-chart-heat-calendar-l2"/><rect x="191" y="54" class="sg-chart-heat-calendar-l3"/></g>44 <g class="sg-chart-heat-calendar-row" style="--sg-r:5"><rect x="22" y="67" class="sg-chart-heat-calendar-l3"/><rect x="35" y="67" class="sg-chart-heat-calendar-l1"/><rect x="48" y="67" class="sg-chart-heat-calendar-l2"/><rect x="61" y="67" class="sg-chart-heat-calendar-l2"/><rect x="74" y="67" class="sg-chart-heat-calendar-l2"/><rect x="87" y="67" class="sg-chart-heat-calendar-l1"/><rect x="100" y="67" class="sg-chart-heat-calendar-l3"/><rect x="113" y="67" class="sg-chart-heat-calendar-l1"/><rect x="126" y="67" class="sg-chart-heat-calendar-l2"/><rect x="139" y="67" class="sg-chart-heat-calendar-l1"/><rect x="152" y="67" class="sg-chart-heat-calendar-l1"/><rect x="165" y="67" class="sg-chart-heat-calendar-l2"/><rect x="178" y="67" class="sg-chart-heat-calendar-l3"/><rect x="191" y="67" class="sg-chart-heat-calendar-l1"/></g>45 <g class="sg-chart-heat-calendar-row" style="--sg-r:6"><rect x="22" y="80" class="sg-chart-heat-calendar-l0"/><rect x="35" y="80" class="sg-chart-heat-calendar-l1"/><rect x="48" y="80" class="sg-chart-heat-calendar-l0"/><rect x="61" y="80" class="sg-chart-heat-calendar-l0"/><rect x="74" y="80" class="sg-chart-heat-calendar-l1"/><rect x="87" y="80" class="sg-chart-heat-calendar-l0"/><rect x="100" y="80" class="sg-chart-heat-calendar-l0"/><rect x="113" y="80" class="sg-chart-heat-calendar-l1"/><rect x="126" y="80" class="sg-chart-heat-calendar-l0"/><rect x="139" y="80" class="sg-chart-heat-calendar-l0"/><rect x="152" y="80" class="sg-chart-heat-calendar-l2"/><rect x="165" y="80" class="sg-chart-heat-calendar-l0"/><rect x="178" y="80" class="sg-chart-heat-calendar-l0"/><rect x="191" y="80" class="sg-chart-heat-calendar-l1"/></g>46 </svg>47</div>48<style>49 .sg-chart-heat-calendar {50 width: var(--sg-size);51 }52 .sg-chart-heat-calendar svg {53 display: block;54 width: 100%;55 font-family: inherit;56 }57 .sg-chart-heat-calendar-day {58 font-size: 7px;59 fill: currentColor;60 opacity: 0.55;61 text-anchor: end;62 }63 .sg-chart-heat-calendar rect {64 width: 10px;65 height: 10px;66 rx: 2px;67 fill: var(--sg-color);68 transform-box: fill-box;69 transform-origin: center;70 animation: sg-chart-heat-calendar-pop 0.35s ease-out both;71 animation-delay: calc((var(--sg-r) + var(--sg-c)) * var(--sg-duration) / 26);72 }73 .sg-chart-heat-calendar rect:nth-of-type(1) { --sg-c: 0; }74 .sg-chart-heat-calendar rect:nth-of-type(2) { --sg-c: 1; }75 .sg-chart-heat-calendar rect:nth-of-type(3) { --sg-c: 2; }76 .sg-chart-heat-calendar rect:nth-of-type(4) { --sg-c: 3; }77 .sg-chart-heat-calendar rect:nth-of-type(5) { --sg-c: 4; }78 .sg-chart-heat-calendar rect:nth-of-type(6) { --sg-c: 5; }79 .sg-chart-heat-calendar rect:nth-of-type(7) { --sg-c: 6; }80 .sg-chart-heat-calendar rect:nth-of-type(8) { --sg-c: 7; }81 .sg-chart-heat-calendar rect:nth-of-type(9) { --sg-c: 8; }82 .sg-chart-heat-calendar rect:nth-of-type(10) { --sg-c: 9; }83 .sg-chart-heat-calendar rect:nth-of-type(11) { --sg-c: 10; }84 .sg-chart-heat-calendar rect:nth-of-type(12) { --sg-c: 11; }85 .sg-chart-heat-calendar rect:nth-of-type(13) { --sg-c: 12; }86 .sg-chart-heat-calendar rect:nth-of-type(14) { --sg-c: 13; }87 .sg-chart-heat-calendar-l0 { fill-opacity: 0.12; }88 .sg-chart-heat-calendar-l1 { fill-opacity: 0.35; }89 .sg-chart-heat-calendar-l2 { fill-opacity: 0.6; }90 .sg-chart-heat-calendar-l3 { fill-opacity: 0.9; }91 @keyframes sg-chart-heat-calendar-pop {92 from { opacity: 0; transform: scale(0.4); }93 to { opacity: 1; transform: scale(1); }94 }95</style>96