Gestapelde staaf per maand Nieuw
Gestapelde staafgrafiek met de omzet per maand, opgesplitst in winkel, webshop en reparaties. Met de legendaknoppen zet je een reeks aan of uit: de stapels schuiven in elkaar en de as schaalt mee. Hover, focus of pijltjestoetsen op een maand tonen de opbouw en het totaal; een verborgen tabel is het alternatief voor schermlezers. Voor maandrapportages, winkels met meerdere kanalen en jaaroverzichten.
Omzet per maand · Rijwielhandel Spaarne, Haarlem
| Maand | Winkel | Webshop | Reparaties |
|---|---|---|---|
| apr | 18200 | 7400 | 4100 |
| mei | 22600 | 9100 | 4800 |
| jun | 24300 | 10200 | 5300 |
| jul | 21000 | 12800 | 6000 |
| aug | 16400 | 11500 | 5600 |
| sep | 19800 | 9600 | 5200 |
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- Gestapelde staaf per maand · NedDev · eigen werk. -->
<div class="jouw-container">
<figure class="gsb">
<div class="gsb__hd"><p class="gsb__t">Omzet per maand<span> · Rijwielhandel Spaarne, Haarlem</span></p>
<div class="gsb__lg" role="group" aria-label="Reeksen tonen of verbergen"><button type="button" aria-pressed="true" data-s="0"><i style="background:#0a0a0a"></i>Winkel</button><button type="button" aria-pressed="true" data-s="1"><i style="background:#F5480F"></i>Webshop</button><button type="button" aria-pressed="true" data-s="2"><i style="background:#b9b6b0"></i>Reparaties</button></div></div>
<div class="gsb__plot"><div class="gsb__tip" hidden></div></div>
<div class="gsb__sr"><table><caption>Omzet per maand in euro, Rijwielhandel Spaarne, Haarlem</caption><thead><tr><th scope="col">Maand</th><th scope="col">Winkel</th><th scope="col">Webshop</th><th scope="col">Reparaties</th></tr></thead><tbody>
<tr><th scope="row" data-f="april">apr</th><td>18200</td><td>7400</td><td>4100</td></tr>
<tr><th scope="row" data-f="mei">mei</th><td>22600</td><td>9100</td><td>4800</td></tr>
<tr><th scope="row" data-f="juni">jun</th><td>24300</td><td>10200</td><td>5300</td></tr>
<tr><th scope="row" data-f="juli">jul</th><td>21000</td><td>12800</td><td>6000</td></tr>
<tr><th scope="row" data-f="augustus">aug</th><td>16400</td><td>11500</td><td>5600</td></tr>
<tr><th scope="row" data-f="september">sep</th><td>19800</td><td>9600</td><td>5200</td></tr></tbody></table></div>
</figure>
</div>/* Gestapelde staaf per maand · NedDev · eigen werk. */
.gsb{position:absolute;inset:0;margin:0;box-sizing:border-box;padding:12px 14px 8px;background:#fff;color:#0a0a0a;font-family:'Switzer',sans-serif;display:flex;flex-direction:column;gap:6px;container-type:inline-size}
.gsb__hd{display:flex;flex-direction:column;gap:4px}
.gsb__t{margin:0;font-size:13px;font-weight:600}
.gsb__t span{font-weight:400;color:#5f5e5a}
.gsb__lg{display:flex;gap:4px;flex-wrap:wrap}
.gsb__lg button{display:flex;align-items:center;gap:6px;min-height:24px;padding:0 8px;border:1px solid #d6d3ce;border-radius:4px;background:#fff;color:#0a0a0a;font:500 12px 'Switzer',sans-serif;cursor:pointer;transition:opacity .15s,border-color .15s}
.gsb__lg button:hover{border-color:#0a0a0a}
.gsb__lg button[aria-pressed="false"]{color:#8a8883;text-decoration:line-through}
.gsb__lg button[aria-pressed="false"] i{opacity:.3}
.gsb__lg button:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.gsb__lg i{width:10px;height:10px;border-radius:2px}
.gsb__plot{position:relative;flex:1;min-height:0}
.gsb__svg{position:absolute;left:0;top:0;overflow:visible}
.gsb__grid{stroke:#eeece9}.gsb__base{stroke:#8a8883}
.gsb__ax{font:500 12px 'Switzer',sans-serif;fill:#6b6a66}
.gsb__col{outline:none}
.gsb__hit{fill:transparent}
.gsb__col:focus-visible .gsb__hit{fill:#f4f3f1;stroke:#0a0a0a;stroke-width:1.2}
.gsb__r{transition:y .6s cubic-bezier(.2,.7,.2,1),height .6s cubic-bezier(.2,.7,.2,1),opacity .15s}
.gsb.is-hover .gsb__col:not(.is-on) .gsb__r{opacity:.35}
.gsb__tip{position:absolute;z-index:2;pointer-events:none;transform:translate(-50%,-100%);background:#0a0a0a;color:#fff;border-radius:4px;padding:6px 8px;font:500 12px/1.4 'Switzer',sans-serif;white-space:nowrap;font-variant-numeric:tabular-nums}
.gsb__tip b{display:block}
.gsb__tip span{color:#cfcdc9}
.gsb__sr{position:absolute;left:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.gsb__sr table{font-size:12px;border-collapse:collapse}
@container (max-width:380px){.gsb__t span{display:none}}
.gsb.is-static .gsb__r{transition:none}
@media(prefers-reduced-motion:reduce){.gsb__r{transition:none}}// Gestapelde staaf per maand · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.gsb');if(!w)return;var NS='http://www.w3.org/2000/svg';
function el(t,a){var e=document.createElementNS(NS,t);for(var k in a)e.setAttribute(k,a[k]);return e;}
var C=['#0a0a0a','#F5480F','#b9b6b0'],SN=['Winkel','Webshop','Reparaties'],on=[1,1,1];
var M=[].map.call(w.querySelectorAll('tbody tr'),function(tr){var th=tr.querySelector('th');return {s:th.textContent,f:th.dataset.f,v:[].map.call(tr.querySelectorAll('td'),function(td){return +td.textContent;})};});
var plot=w.querySelector('.gsb__plot'),tip=w.querySelector('.gsb__tip'),svg=null,ticks=[],cols=[],W,H,L=46,R=4,T=8,B=20,ph,n=M.length,started=false;
function build(){if(svg)svg.remove();W=Math.max(200,plot.clientWidth);H=Math.max(90,plot.clientHeight);ph=H-T-B;var pw=W-L-R,step=pw/n,bw=Math.min(40,step*.56);
svg=el('svg',{viewBox:'0 0 '+W+' '+H,width:W,height:H,'class':'gsb__svg',role:'group','aria-label':'Gestapelde staafgrafiek, pijltjestoetsen lezen per maand'});
ticks=[0,1,2,3,4].map(function(i){var y=T+ph-ph*i/4;svg.appendChild(el('line',{x1:L,x2:W-R,y1:y,y2:y,'class':i?'gsb__grid':'gsb__base'}));var t=el('text',{x:L-6,y:y+4,'class':'gsb__ax','text-anchor':'end'});svg.appendChild(t);return t;});
cols=M.map(function(m,i){var cx=L+step*i+step/2,g=el('g',{'class':'gsb__col',tabindex:'0',role:'img'});g.appendChild(el('rect',{x:cx-step/2+1,y:T-2,width:step-2,height:ph+2,rx:3,'class':'gsb__hit'}));
var rs=C.map(function(c){var r=el('rect',{x:cx-bw/2,width:bw,'class':'gsb__r',fill:c});r.style.y=(T+ph)+'px';r.style.height='0px';g.appendChild(r);return r;});
var lb=el('text',{x:cx,y:H-5,'class':'gsb__ax','text-anchor':'middle'});lb.textContent=m.s;g.appendChild(lb);svg.appendChild(g);return {g:g,rs:rs,cx:cx,m:m,i:i};});
plot.insertBefore(svg,tip);bind();}
function eur(v){return '€ '+v.toLocaleString('nl-NL');}
function k(v){return v?'€ '+(v/1000).toLocaleString('nl-NL')+'k':'0';}
function tot(m){return m.v.reduce(function(a,v,j){return a+(on[j]?v:0);},0);}
var max=40000;
function render(){var mt=Math.max.apply(null,M.map(tot))||1,st=Math.ceil(mt/4/2500)*2500;max=st*4;ticks.forEach(function(t,i){t.textContent=k(st*i);});
cols.forEach(function(c){var y=T+ph;c.rs.forEach(function(r,j){var h=on[j]?c.m.v[j]/max*ph:0;y-=h;r.style.y=y+'px';r.style.height=h+'px';});
c.g.setAttribute('aria-label',c.m.f+': totaal '+eur(tot(c.m))+'. '+SN.map(function(s,j){return on[j]?s+' '+eur(c.m.v[j]):'';}).filter(Boolean).join(', '));});}
function show(c){w.classList.add('is-hover');cols.forEach(function(x){x.g.classList.toggle('is-on',x===c);});
tip.innerHTML='<b>'+c.m.f+': '+eur(tot(c.m))+'</b>'+SN.map(function(s,j){return on[j]?'<span>'+s+' '+eur(c.m.v[j])+'</span>':'';}).filter(Boolean).join('<br>');tip.hidden=false;
var pt=svg.createSVGPoint();pt.x=c.cx;pt.y=T+ph-tot(c.m)/max*ph;var p=pt.matrixTransform(svg.getScreenCTM()),pr=plot.getBoundingClientRect(),tw=tip.offsetWidth,th=tip.offsetHeight;
tip.style.left=Math.max(tw/2,Math.min(pr.width-tw/2,p.x-pr.left))+'px';tip.style.top=Math.max(th,p.y-pr.top-6)+'px';}
function hide(){w.classList.remove('is-hover');tip.hidden=true;cols.forEach(function(x){x.g.classList.remove('is-on');});}
function bind(){cols.forEach(function(c){c.g.addEventListener('pointerenter',function(){show(c);});c.g.addEventListener('focus',function(){show(c);});c.g.addEventListener('blur',hide);c.g.addEventListener('keydown',function(e){var kk=e.key,j=kk==='ArrowRight'?c.i+1:kk==='ArrowLeft'?c.i-1:kk==='Home'?0:kk==='End'?n-1:-2;if(kk==='Escape'){hide();return;}if(j>-2){e.preventDefault();cols[Math.max(0,Math.min(n-1,j))].g.focus();}});});svg.addEventListener('pointerleave',hide);}
w.querySelectorAll('.gsb__lg button').forEach(function(b){b.addEventListener('click',function(){var s=+b.dataset.s;if(on[s]&&on.filter(Boolean).length===1)return;on[s]=on[s]?0:1;b.setAttribute('aria-pressed',on[s]?'true':'false');hide();render();});});
build();
var reduce=matchMedia('(prefers-reduced-motion:reduce)').matches;
function start(){started=true;render();}
if(reduce||!('IntersectionObserver' in window)){start();}else{ticks.forEach(function(t,i){t.textContent=k(10000*i);});var io=new IntersectionObserver(function(es){if(es[0].isIntersecting){io.disconnect();requestAnimationFrame(start);}},{threshold:.35});io.observe(w);}
if('ResizeObserver' in window){var lw=W,lh=H,rt=0;new ResizeObserver(function(){if(Math.abs(plot.clientWidth-lw)<2&&Math.abs(plot.clientHeight-lh)<2)return;clearTimeout(rt);rt=setTimeout(function(){lw=plot.clientWidth;lh=plot.clientHeight;hide();build();w.classList.add('is-static');if(started)render();else ticks.forEach(function(t,i){t.textContent=k(10000*i);});requestAnimationFrame(function(){requestAnimationFrame(function(){w.classList.remove('is-static');});});},120);}).observe(plot);}
}
init(document.querySelector('.jouw-container'));
Meer uit cijfers & grafieken
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →