1/* 2 * alterspyramide.js â zeichnet die einseitige Alterspyramide für den 3 * CMS-Tag [ALTERSPYRAMIDE]. First-party, kein externes Lib, kein Consent. 4 * 5 * Erwartet je .alterspyramide-Element ein <script type="application/json" 6 * class="alterspyramide-data"> mit { groups: [...], years: [{jahr, values:[...]}] }. 7 * Zeichnet je Altersgruppe einen zentrierten horizontalen Balken (jüngste unten 8 * â älteste oben). Ein Slider blättert durch die Jahre; die Skala (globales 9 * Maximum über alle Jahre) bleibt konstant, sodass das Wachstum sichtbar wird. 10 */ 11(function () { 12 'use strict'; 13 14 function esc(s) { 15 return String(s).replace(/[&<>"]/g, function (c) { 16 return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; 17 }); 18 } 19 20 function draw(svgEl, groups, values, maxVal, jahr) { 21 var W = 600, rowH = 34, padTop = 10, padBottom = 10; 22 var centerX = W / 2, maxBarW = W * 0.42, labelPad = 8; 23 var n = groups.length; 24 var H = padTop + padBottom + n * rowH; 25 26 var s = '<svg viewBox="0 0 ' + W + ' ' + H + '" preserveAspectRatio="xMidYMid meet" width="100%" xmlns="http://www.w3.org/2000/svg" font-family="inherit">'; 27 // Mittelachse 28 s += '<line x1="' + centerX + '" y1="' + padTop + '" x2="' + centerX + '" y2="' + (H - padBottom) + '" stroke="#d5d5d5" stroke-width="1"/>'; 29 30 for (var i = 0; i < n; i++) { 31 var val = +values[i] || 0; // groups[0] = jüngste 32 var barW = maxVal > 0 ? (val / maxVal) * maxBarW : 0; 33 var yc = H - padBottom - (i + 0.5) * rowH; // i=0 unten, älteste oben 34 var barH = rowH * 0.60; 35 var x = centerX - barW / 2; 36 var y = yc - barH / 2; 37 38 s += '<rect x="' + x.toFixed(1) + '" y="' + y.toFixed(1) + '" width="' + barW.toFixed(1) + '" height="' + barH.toFixed(1) + '" rx="2" fill="var(--color-primary, #047c3c)">'; 39 s += '<title>' + esc(groups[i]) + ' (' + jahr + '): ' + val + '</title></rect>'; 40 // Altersgruppe links, Wert rechts 41 s += '<text x="' + (centerX - maxBarW - labelPad) + '" y="' + (yc + 4) + '" text-anchor="end" font-size="12" fill="#444">' + esc(groups[i]) + '</text>'; 42 s += '<text x="' + (centerX + maxBarW + labelPad) + '" y="' + (yc + 4) + '" text-anchor="start" font-size="12" fill="#444">' + val + '</text>'; 43 } 44 s += '</svg>'; 45 svgEl.innerHTML = s; 46 } 47 48 function init(el) { 49 if (el.__apInit) { return; } 50 el.__apInit = true; 51 52 var dataEl = el.querySelector('.alterspyramide-data'); 53 if (!dataEl) { return; } 54 var data; 55 try { data = JSON.parse(dataEl.textContent); } catch (e) { return; } 56 var groups = data.groups || [], years = data.years || []; 57 if (!years.length || !groups.length) { return; } 58 59 var svgEl = el.querySelector('.alterspyramide-svg'); 60 var slider = el.querySelector('.alterspyramide-slider'); 61 var yearLbl = el.querySelector('.alterspyramide-year'); 62 var playBtn = el.querySelector('.alterspyramide-play'); 63 if (!svgEl) { return; } 64 65 // Globales Maximum über alle Jahre/Gruppen â konstante Skala (Wachstum sichtbar) 66 var maxVal = 0; 67 years.forEach(function (yr) { 68 (yr.values || []).forEach(function (v) { if (+v > maxVal) { maxVal = +v; } }); 69 }); 70 71 function render(idx) { 72 idx = Math.max(0, Math.min(years.length - 1, idx | 0)); 73 var yr = years[idx]; 74 draw(svgEl, groups, yr.values || [], maxVal, yr.jahr); 75 if (yearLbl) { yearLbl.textContent = yr.jahr; } 76 if (svgEl) { svgEl.setAttribute('aria-label', 'Alterspyramide ' + yr.jahr); } 77 if (slider && +slider.value !== idx) { slider.value = idx; } 78 } 79 80 var timer = null; 81 function stop() { 82 if (timer) { clearInterval(timer); timer = null; if (playBtn) { playBtn.textContent = 'â¶'; playBtn.setAttribute('aria-label', 'Jahre abspielen'); } } 83 } 84 function play() { 85 if (timer) { stop(); return; } 86 if (playBtn) { playBtn.textContent = 'â¸'; playBtn.setAttribute('aria-label', 'Pause'); } 87 var idx = +slider.value; 88 if (idx >= years.length - 1) { idx = 0; } 89 render(idx); 90 timer = setInterval(function () { 91 idx++; 92 if (idx >= years.length) { stop(); return; } 93 render(idx); 94 }, 750); 95 } 96 97 if (slider) { slider.addEventListener('input', function () { stop(); render(+slider.value); }); } 98 if (playBtn) { playBtn.addEventListener('click', play); } 99 100 render(years.length - 1); // Start: aktuellstes Jahr 101 } 102 103 function initAll() { 104 var els = document.querySelectorAll('.alterspyramide'); 105 for (var i = 0; i < els.length; i++) { init(els[i]); } 106 } 107 108 if (document.readyState === 'loading') { 109 document.addEventListener('DOMContentLoaded', initAll); 110 } else { 111 initAll(); 112 } 113})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.