Heat calendar
GitHub-style heat calendar cascading in diagonally
Techniques: --sg-i index variables · nth-of-type indexing · fill-opacity levels · css rect geometry
<!--
============================================================
SVGarden — https://www.svgarden.dev
Author : Simon-Pierre Boucher
Contact: contact@spboucher.ai
File : snippets/charts/chart-heat-calendar.html
Desc : GitHub-style heat calendar cascading in diagonally
============================================================
-->
<div class="sg-chart-heat-calendar" style="--sg-color:#7F77DD; --sg-size:260px; --sg-duration:1.4s;">
<svg viewBox="0 0 210 96" role="img" aria-label="Activity heat calendar, 14 weeks by 7 days, busiest midweek">
<title>Contribution heat calendar</title>
<text class="sg-chart-heat-calendar-day" x="18" y="23">M</text>
<text class="sg-chart-heat-calendar-day" x="18" y="49">W</text>
<text class="sg-chart-heat-calendar-day" x="18" y="75">F</text>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
</svg>
</div>
<style>
.sg-chart-heat-calendar {
width: var(--sg-size);
}
.sg-chart-heat-calendar svg {
display: block;
width: 100%;
font-family: inherit;
}
.sg-chart-heat-calendar-day {
font-size: 7px;
fill: currentColor;
opacity: 0.55;
text-anchor: end;
}
.sg-chart-heat-calendar rect {
width: 10px;
height: 10px;
rx: 2px;
fill: var(--sg-color);
transform-box: fill-box;
transform-origin: center;
animation: sg-chart-heat-calendar-pop 0.35s ease-out both;
animation-delay: calc((var(--sg-r) + var(--sg-c)) * var(--sg-duration) / 26);
}
.sg-chart-heat-calendar rect:nth-of-type(1) { --sg-c: 0; }
.sg-chart-heat-calendar rect:nth-of-type(2) { --sg-c: 1; }
.sg-chart-heat-calendar rect:nth-of-type(3) { --sg-c: 2; }
.sg-chart-heat-calendar rect:nth-of-type(4) { --sg-c: 3; }
.sg-chart-heat-calendar rect:nth-of-type(5) { --sg-c: 4; }
.sg-chart-heat-calendar rect:nth-of-type(6) { --sg-c: 5; }
.sg-chart-heat-calendar rect:nth-of-type(7) { --sg-c: 6; }
.sg-chart-heat-calendar rect:nth-of-type(8) { --sg-c: 7; }
.sg-chart-heat-calendar rect:nth-of-type(9) { --sg-c: 8; }
.sg-chart-heat-calendar rect:nth-of-type(10) { --sg-c: 9; }
.sg-chart-heat-calendar rect:nth-of-type(11) { --sg-c: 10; }
.sg-chart-heat-calendar rect:nth-of-type(12) { --sg-c: 11; }
.sg-chart-heat-calendar rect:nth-of-type(13) { --sg-c: 12; }
.sg-chart-heat-calendar rect:nth-of-type(14) { --sg-c: 13; }
.sg-chart-heat-calendar-l0 { fill-opacity: 0.12; }
.sg-chart-heat-calendar-l1 { fill-opacity: 0.35; }
.sg-chart-heat-calendar-l2 { fill-opacity: 0.6; }
.sg-chart-heat-calendar-l3 { fill-opacity: 0.9; }
@keyframes sg-chart-heat-calendar-pop {
from { opacity: 0; transform: scale(0.4); }
to { opacity: 1; transform: scale(1); }
}
</style>