417 lines
23 KiB
HTML
417 lines
23 KiB
HTML
<!doctype html>
|
||
<html lang="nl">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Weerscherm: drie layoutvoorstellen</title>
|
||
<style>
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { font-family: -apple-system, system-ui, "Segoe UI", Roboto, sans-serif; background: #D8DDE1; color: #1B2A35; padding: 24px 16px 40px; }
|
||
.wrap { max-width: 1161px; margin: 0 auto; }
|
||
.intro h1 { font-size: 22px; font-weight: 600; }
|
||
.intro p { font-size: 15px; color: #4F5F6B; margin-top: 4px; max-width: 72ch; line-height: 1.45; }
|
||
.tabs { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0 14px; }
|
||
.tabs button { font: inherit; font-size: 15px; padding: 9px 16px; border-radius: 999px; border: 1px solid #A9B5BE; background: transparent; color: #1B2A35; cursor: pointer; }
|
||
.tabs button[aria-selected="true"] { background: #1B2A35; color: #fff; border-color: #1B2A35; }
|
||
.tabs button:focus-visible { outline: 3px solid #3A75A3; outline-offset: 2px; }
|
||
.scaler { position: relative; }
|
||
.device { position: absolute; top: 0; left: 0; width: 1161px; height: 772px; padding: 14px; background: #23272B; border-radius: 34px; transform-origin: top left; }
|
||
.screen { width: 1133px; height: 744px; border-radius: 20px; overflow: hidden; position: relative; }
|
||
.design { position: absolute; inset: 0; display: none; }
|
||
.design.active { display: grid; }
|
||
.caption { font-size: 15px; color: #4F5F6B; margin-top: 14px; max-width: 72ch; line-height: 1.45; }
|
||
.num { font-variant-numeric: tabular-nums; }
|
||
.ic, .icn { fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
|
||
.ic { width: 100%; height: 100%; display: block; }
|
||
.i-sun { stroke: var(--sun); }
|
||
.i-drop { stroke: var(--rain); }
|
||
.i-cloud { fill: var(--iconfill); }
|
||
.cold { color: var(--cold); }
|
||
.warm { color: var(--warm); }
|
||
|
||
/* ---------- Ontwerp A: buiten centraal ---------- */
|
||
.da { --bg:#E8EDF1; --ink:#1B2A35; --muted:#5F707C; --line:#C6D0D8; --warm:#B8761C; --cold:#3A75A3; --rain:#2E6A99; --sun:#D39A2C; --iconfill:#E8EDF1;
|
||
background: var(--bg); color: var(--ink); font-family: -apple-system, "SF Pro Display", system-ui, "Segoe UI", Roboto, sans-serif;
|
||
padding: 30px 44px; grid-template-columns: 1fr 330px; grid-template-rows: 40px 1fr 232px; column-gap: 56px; }
|
||
.a-top { grid-column: 1 / -1; display: flex; justify-content: space-between; align-items: baseline; }
|
||
.a-date { font-size: 22px; font-weight: 500; }
|
||
.a-right { display: flex; gap: 18px; align-items: baseline; }
|
||
.a-upd { font-size: 15px; color: var(--muted); }
|
||
.a-clock { font-size: 26px; font-weight: 300; }
|
||
.a-hero { align-self: center; }
|
||
.a-label { font-size: 22px; color: var(--muted); font-weight: 500; display: flex; gap: 14px; align-items: baseline; }
|
||
.a-trend { font-size: 17px; font-weight: 400; }
|
||
.a-temp { font-size: 200px; font-weight: 200; letter-spacing: -.045em; line-height: .95; margin: 4px 0 24px -8px; }
|
||
.a-range { width: 560px; }
|
||
.a-track { position: relative; height: 12px; border-radius: 6px; background: linear-gradient(90deg, var(--cold), var(--warm)); }
|
||
.a-mark { position: absolute; top: 50%; width: 28px; height: 28px; border-radius: 50%; background: var(--bg); border: 5px solid var(--ink); transform: translate(-50%, -50%); }
|
||
.a-ends { display: flex; justify-content: space-between; margin-top: 14px; font-size: 17px; color: var(--muted); }
|
||
.a-ends b { font-size: 24px; font-weight: 600; margin-right: 6px; }
|
||
.a-inside { align-self: center; }
|
||
.a-room { padding: 12px 0; border-top: 1px solid var(--line); }
|
||
.a-room:first-child { border-top: 0; }
|
||
.a-rname { font-size: 19px; color: var(--muted); }
|
||
.a-rtemp { font-size: 50px; font-weight: 300; line-height: 1.05; }
|
||
.a-rmm { font-size: 17px; display: flex; gap: 18px; }
|
||
.a-bottom { grid-column: 1 / -1; border-top: 1px solid var(--line); padding-top: 22px; display: grid; grid-template-columns: 390px 1fr; column-gap: 36px; }
|
||
.a-sub { font-size: 19px; color: var(--muted); font-weight: 500; margin-bottom: 10px; }
|
||
.a-rainrow { display: flex; justify-content: space-between; align-items: flex-end; }
|
||
.a-rbig { font-size: 22px; color: var(--rain); }
|
||
.a-rbig span { font-size: 60px; font-weight: 300; line-height: 1; }
|
||
.a-rsm { font-size: 17px; color: var(--muted); }
|
||
.a-month { font-size: 17px; margin-top: 18px; color: var(--muted); white-space: nowrap; }
|
||
.a-month b { color: var(--ink); font-weight: 600; font-size: 20px; margin-left: 4px; }
|
||
.a-bars { display: flex; gap: 6px; align-items: flex-end; }
|
||
.a-bar { display: flex; flex-direction: column; align-items: center; gap: 5px; font-size: 14px; color: var(--muted); min-width: 38px; }
|
||
.a-bar i { display: block; width: 24px; border-radius: 4px 4px 0 0; background: var(--rain); opacity: .4; }
|
||
.a-bar.now i { opacity: 1; }
|
||
.a-bar.now span { color: var(--ink); font-weight: 600; }
|
||
.a-fc { display: grid; grid-template-columns: repeat(5, 1fr); text-align: center; }
|
||
.a-day { display: flex; flex-direction: column; align-items: center; gap: 6px; border-left: 1px solid var(--line); }
|
||
.a-day:first-child { border-left: 0; }
|
||
.a-dname { font-size: 19px; font-weight: 600; }
|
||
.a-icon { width: 58px; height: 58px; }
|
||
.a-hl { font-size: 28px; font-weight: 500; }
|
||
.a-hl span { font-size: 22px; color: var(--muted); font-weight: 400; margin-left: 6px; }
|
||
.a-fr { font-size: 16px; color: var(--rain); }
|
||
.a-fr span { color: var(--muted); margin-left: 6px; }
|
||
|
||
/* ---------- Ontwerp B: grafisch ---------- */
|
||
.db { --bg:#EFF1EC; --panel:#FFFFFF; --ink:#1E2B24; --muted:#66726A; --line:#DCE0D7; --warm:#C47A22; --cold:#44799F; --rain:#386CA4; --rainsoft:#BFD0E3; --sun:#D2952A; --iconfill:#FFFFFF;
|
||
background: var(--bg); color: var(--ink); font-family: ui-rounded, "SF Pro Rounded", -apple-system, system-ui, sans-serif;
|
||
padding: 26px 32px; grid-template-columns: 1.35fr 1fr 1fr 1fr; grid-template-rows: 34px 232px 1fr; gap: 18px; }
|
||
.b-top { grid-column: 1 / -1; display: flex; justify-content: space-between; align-items: center; font-size: 20px; }
|
||
.b-top span:first-child { font-weight: 600; }
|
||
.b-top span:last-child { color: var(--muted); font-size: 17px; }
|
||
.b-name { font-size: 18px; color: var(--muted); font-weight: 500; }
|
||
.b-out { background: var(--ink); color: #F1F3EE; border-radius: 26px; padding: 22px 26px; display: flex; flex-direction: column; justify-content: space-between; }
|
||
.b-out .b-name { color: #B9C4BC; }
|
||
.b-out .b-t { font-size: 104px; font-weight: 600; line-height: 1; letter-spacing: -.03em; }
|
||
.b-out .cold { color: #9EC4E3; }
|
||
.b-out .warm { color: #F1BC6C; }
|
||
.b-mm { font-size: 16px; display: flex; flex-direction: column; gap: 2px; }
|
||
.b-in { background: var(--panel); border: 1px solid var(--line); border-radius: 18px; padding: 20px 22px; display: flex; flex-direction: column; justify-content: space-between; }
|
||
.b-in .b-t { font-size: 62px; font-weight: 600; line-height: 1; letter-spacing: -.02em; }
|
||
.b-in .b-mm { flex-direction: row; gap: 14px; }
|
||
.b-panel { background: var(--panel); border: 1px solid var(--line); border-radius: 18px; padding: 18px 24px; }
|
||
.b-fc { grid-column: 1 / span 2; }
|
||
.b-rain { grid-column: 3 / span 2; }
|
||
.b-h { font-size: 17px; color: var(--muted); font-weight: 500; margin-bottom: 6px; }
|
||
.b-fc > svg, .b-rain > svg { width: 100%; height: auto; display: block; }
|
||
.b-dn { font-size: 17px; font-weight: 600; fill: var(--ink); }
|
||
.b-hi { font-size: 19px; font-weight: 600; fill: var(--ink); }
|
||
.b-lo { font-size: 16px; fill: var(--muted); }
|
||
.b-mmt { font-size: 14px; font-weight: 600; fill: var(--rain); }
|
||
.b-pct { font-size: 13px; fill: var(--muted); }
|
||
.b-total { font-size: 46px; font-weight: 600; line-height: 1.1; }
|
||
.b-total span { font-size: 20px; color: var(--muted); font-weight: 500; margin-left: 6px; }
|
||
.b-rain > svg { margin: 10px 0 14px; }
|
||
.b-dl { font-size: 12px; fill: var(--muted); }
|
||
.b-dl.now { fill: var(--ink); font-weight: 700; }
|
||
.b-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
|
||
.b-stats p { font-size: 14px; color: var(--muted); }
|
||
.b-stats b { display: block; font-size: 22px; color: var(--ink); font-weight: 600; }
|
||
.b-stats .now b { color: var(--rain); }
|
||
|
||
/* ---------- Ontwerp C: avondscherm ---------- */
|
||
.dc { --bg:#15212F; --ink:#ECE5D8; --muted:#8D9AA9; --line:#2B3B4E; --warm:#E2B46F; --cold:#95B9DB; --rain:#88AFDC; --sun:#E2B46F; --iconfill:#15212F;
|
||
background: var(--bg); color: var(--ink); font-family: -apple-system, system-ui, "Segoe UI", sans-serif;
|
||
padding: 34px 48px; grid-template-columns: 1fr 410px; grid-template-rows: 40px 1fr auto; column-gap: 72px; }
|
||
.serif { font-family: ui-serif, "New York", "Iowan Old Style", Georgia, serif; }
|
||
.c-date { font-size: 20px; color: var(--muted); align-self: center; }
|
||
.c-clock { font-size: 30px; text-align: right; align-self: center; }
|
||
.c-hero { align-self: center; }
|
||
.c-label { font-size: 20px; color: var(--muted); }
|
||
.c-temp { font-size: 196px; line-height: 1; font-weight: 400; letter-spacing: -.02em; margin: 2px 0 10px -6px; }
|
||
.c-mm { font-size: 26px; display: flex; gap: 32px; }
|
||
.c-mm small { font-family: -apple-system, system-ui, sans-serif; font-size: 15px; color: var(--muted); margin-left: 6px; }
|
||
.c-inside { grid-column: 1; grid-row: 3; display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px solid var(--line); padding-top: 20px; }
|
||
.c-rname { font-size: 17px; color: var(--muted); }
|
||
.c-rt { font-size: 46px; line-height: 1.15; }
|
||
.c-rmm { font-size: 15px; color: var(--muted); }
|
||
.c-right { grid-column: 2; grid-row: 2 / 4; margin-top: 22px; display: flex; flex-direction: column; justify-content: space-between; }
|
||
.c-row { display: grid; grid-template-columns: 104px 40px 1fr auto; align-items: center; gap: 14px; padding: 16px 0; border-bottom: 1px solid var(--line); }
|
||
.c-row:first-child { border-top: 1px solid var(--line); }
|
||
.c-dn { font-size: 19px; }
|
||
.c-ic { width: 40px; height: 40px; }
|
||
.c-hl { font-size: 26px; }
|
||
.c-hl span { color: var(--muted); font-size: 22px; margin-left: 8px; }
|
||
.c-fr { font-size: 15px; color: var(--rain); text-align: right; line-height: 1.3; }
|
||
.c-fr span { display: block; color: var(--muted); }
|
||
.c-rain { border-top: 1px solid var(--line); padding-top: 18px; }
|
||
.c-rl { font-size: 17px; color: var(--muted); }
|
||
.c-rbig { font-size: 17px; color: var(--muted); margin: 2px 0 10px; }
|
||
.c-rbig b { font-size: 44px; font-weight: 400; color: var(--rain); margin-right: 6px; }
|
||
.c-past { display: flex; gap: 24px; font-size: 16px; color: var(--muted); }
|
||
.c-past b { color: var(--ink); font-weight: 400; margin-left: 4px; }
|
||
.c-month { font-size: 16px; color: var(--muted); margin-top: 8px; }
|
||
.c-month b { color: var(--ink); font-weight: 400; margin-left: 4px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<div class="intro">
|
||
<h1>Weerscherm voor de iPad mini: drie layouts</h1>
|
||
<p>Liggend formaat, op ware grootte van een iPad mini (1133 × 744 punten). Alle waarden zijn voorbeelddata; de namen van de binnenruimtes zijn placeholders.</p>
|
||
</div>
|
||
<div class="tabs" role="tablist" aria-label="Kies een ontwerp">
|
||
<button role="tab" aria-selected="true" data-d="a">A: Buiten centraal</button>
|
||
<button role="tab" aria-selected="false" data-d="b">B: Grafisch</button>
|
||
<button role="tab" aria-selected="false" data-d="c">C: Avondscherm</button>
|
||
</div>
|
||
<div class="scaler"><div class="device"><div class="screen" id="screen"></div></div></div>
|
||
<p class="caption" id="caption"></p>
|
||
</div>
|
||
|
||
<script>
|
||
const D = {
|
||
datum: 'Vrijdag 11 september', tijd: '14:32', meting: '14:30',
|
||
buiten: { t: 16.4, min: 9.2, minT: '06:10', max: 19.8, maxT: '13:05', trend: '↘ dalend' },
|
||
binnen: [
|
||
{ naam: 'Woonkamer', t: 21.3, min: 20.4, max: 22.1 },
|
||
{ naam: 'Slaapkamer', t: 18.9, min: 18.1, max: 19.6 },
|
||
{ naam: 'Kantoor', t: 20.2, min: 19.0, max: 21.0 }
|
||
],
|
||
regen: {
|
||
vandaag: 2.4,
|
||
dagen: [ { d: 'di', mm: 1.2 }, { d: 'wo', mm: 6.8 }, { d: 'do', mm: 0.0 } ],
|
||
maand: 38.5, maandNaam: 'september',
|
||
perDag: [4.3, 0, 3.2, 5.1, 0, 0, 15.5, 1.2, 6.8, 0, 2.4],
|
||
vandaagNr: 11, dagenInMaand: 30
|
||
},
|
||
verwachting: [
|
||
{ d: 'za', dl: 'zaterdag', icon: 'partly', hi: 18, lo: 10, mm: 0.4, kans: 20 },
|
||
{ d: 'zo', dl: 'zondag', icon: 'sun', hi: 20, lo: 11, mm: 0, kans: 5 },
|
||
{ d: 'ma', dl: 'maandag', icon: 'rain', hi: 17, lo: 12, mm: 8.2, kans: 80 },
|
||
{ d: 'di', dl: 'dinsdag', icon: 'showers', hi: 15, lo: 9, mm: 3.1, kans: 60 },
|
||
{ d: 'wo', dl: 'woensdag', icon: 'partly', hi: 16, lo: 8, mm: 0.2, kans: 15 }
|
||
]
|
||
};
|
||
|
||
const f1 = v => v.toFixed(1).replace('.', ',');
|
||
const fmm = v => v === 0 ? '0 mm' : f1(v) + ' mm';
|
||
const cap = s => s.charAt(0).toUpperCase() + s.slice(1);
|
||
|
||
function iconInner(name) {
|
||
return {
|
||
sun: '<g class="i-sun"><circle cx="24" cy="24" r="8"/><path d="M24 6v5M24 37v5M6 24h5M37 24h5M11.3 11.3l3.5 3.5M33.2 33.2l3.5 3.5M11.3 36.7l3.5-3.5M33.2 14.8l3.5-3.5"/></g>',
|
||
partly: '<g class="i-sun"><circle cx="18" cy="17" r="6"/><path d="M18 5v3M6 17h3M9.5 8.5l2 2M26.5 8.5l-2 2"/></g><path class="i-cloud" d="M17 40h18a7 7 0 0 0 .8-13.96A10 10 0 0 0 17.3 28 6 6 0 0 0 17 40z"/>',
|
||
rain: '<path class="i-cloud" d="M15 30h19a7 7 0 0 0 .8-13.96A10 10 0 0 0 15.3 18 6 6 0 0 0 15 30z"/><path class="i-drop" d="M18 35l-2 5M26 35l-2 5M34 35l-2 5"/>',
|
||
showers: '<g class="i-sun"><circle cx="16" cy="14" r="5"/><path d="M16 4v2.5M6 14h2.5M9 7l1.8 1.8M23 7l-1.8 1.8"/></g><path class="i-cloud" d="M17 32h17a6.5 6.5 0 0 0 .7-12.96A9.5 9.5 0 0 0 17.3 21 5.5 5.5 0 0 0 17 32z"/><path class="i-drop" d="M22 37l-2 5M30 37l-2 5"/>'
|
||
}[name];
|
||
}
|
||
const icon = name => `<svg class="ic" viewBox="0 0 48 48" aria-hidden="true">${iconInner(name)}</svg>`;
|
||
|
||
/* ---------- A ---------- */
|
||
function designA() {
|
||
const b = D.buiten;
|
||
const pos = ((b.t - b.min) / (b.max - b.min) * 100).toFixed(1);
|
||
const bars = [...D.regen.dagen.map(x => ({ l: cap(x.d), mm: x.mm })), { l: 'Vandaag', mm: D.regen.vandaag, now: true }];
|
||
const maxR = Math.max(...bars.map(x => x.mm));
|
||
return `
|
||
<header class="a-top">
|
||
<span class="a-date">${D.datum}</span>
|
||
<span class="a-right"><span class="a-upd">meting ${D.meting}</span><span class="a-clock num">${D.tijd}</span></span>
|
||
</header>
|
||
<section class="a-hero">
|
||
<p class="a-label">Buiten <span class="a-trend">${b.trend}</span></p>
|
||
<p class="a-temp num">${f1(b.t)}°</p>
|
||
<div class="a-range">
|
||
<div class="a-track"><span class="a-mark" style="left:${pos}%"></span></div>
|
||
<div class="a-ends num">
|
||
<span><b class="cold">${f1(b.min)}°</b>laagst om ${b.minT}</span>
|
||
<span><b class="warm">${f1(b.max)}°</b>hoogst om ${b.maxT}</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="a-inside">
|
||
${D.binnen.map(r => `
|
||
<div class="a-room">
|
||
<p class="a-rname">${r.naam}</p>
|
||
<p class="a-rtemp num">${f1(r.t)}°</p>
|
||
<p class="a-rmm num"><span class="cold">↓ ${f1(r.min)}°</span><span class="warm">↑ ${f1(r.max)}°</span></p>
|
||
</div>`).join('')}
|
||
</section>
|
||
<section class="a-bottom">
|
||
<div>
|
||
<p class="a-sub">Regen</p>
|
||
<div class="a-rainrow">
|
||
<div>
|
||
<p class="a-rbig"><span class="num">${f1(D.regen.vandaag)}</span> mm</p>
|
||
<p class="a-rsm">vandaag</p>
|
||
<p class="a-month">${cap(D.regen.maandNaam)}<b class="num">${f1(D.regen.maand)} mm</b></p>
|
||
</div>
|
||
<div class="a-bars">
|
||
${bars.map(x => `<div class="a-bar${x.now ? ' now' : ''}"><span class="num">${f1(x.mm)}</span><i style="height:${Math.max(2, x.mm / maxR * 70)}px"></i><span>${x.l}</span></div>`).join('')}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="a-fc">
|
||
${D.verwachting.map(d => `
|
||
<div class="a-day">
|
||
<p class="a-dname">${cap(d.d)}</p>
|
||
<div class="a-icon">${icon(d.icon)}</div>
|
||
<p class="a-hl num">${d.hi}°<span>${d.lo}°</span></p>
|
||
<p class="a-fr num">${fmm(d.mm)}<span>${d.kans}%</span></p>
|
||
</div>`).join('')}
|
||
</div>
|
||
</section>`;
|
||
}
|
||
|
||
/* ---------- B ---------- */
|
||
function forecastChart() {
|
||
const W = 518, cw = W / 5;
|
||
const y = t => 210 - (t - 6) / 16 * 110;
|
||
let s = `<svg viewBox="0 0 518 310" role="img" aria-label="Verwachting komende vijf dagen">
|
||
<defs><linearGradient id="tg" gradientUnits="userSpaceOnUse" x1="0" y1="100" x2="0" y2="210">
|
||
<stop offset="0" style="stop-color:var(--warm)"/><stop offset="1" style="stop-color:var(--cold)"/>
|
||
</linearGradient></defs>
|
||
<line x1="8" x2="510" y1="285.5" y2="285.5" style="stroke:var(--line)"/>`;
|
||
D.verwachting.forEach((d, i) => {
|
||
const cx = cw * i + cw / 2, yh = y(d.hi), yl = y(d.lo);
|
||
const rh = d.mm > 0 ? Math.max(2, d.mm / 10 * 40) : 0;
|
||
s += `
|
||
<text x="${cx}" y="20" text-anchor="middle" class="b-dn">${cap(d.d)}</text>
|
||
<svg x="${cx - 22}" y="30" width="44" height="44" viewBox="0 0 48 48" class="icn">${iconInner(d.icon)}</svg>
|
||
<text x="${cx}" y="${yh - 10}" text-anchor="middle" class="b-hi">${d.hi}°</text>
|
||
<rect x="${cx - 9}" y="${yh}" width="18" height="${yl - yh}" rx="9" style="fill:url(#tg)"/>
|
||
<text x="${cx}" y="${yl + 22}" text-anchor="middle" class="b-lo">${d.lo}°</text>
|
||
${rh ? `<rect x="${cx - 16}" y="${285 - rh}" width="32" height="${rh}" rx="3" style="fill:var(--rain)"/>` : ''}
|
||
<text x="${cx}" y="${285 - rh - 7}" text-anchor="middle" class="b-mmt">${fmm(d.mm)}</text>
|
||
<text x="${cx}" y="304" text-anchor="middle" class="b-pct">${d.kans}% kans</text>`;
|
||
});
|
||
return s + '</svg>';
|
||
}
|
||
|
||
function monthStrip() {
|
||
const R = D.regen, W = 436, cw = W / R.dagenInMaand, base = 112;
|
||
const maxMM = Math.max(...R.perDag);
|
||
let s = `<svg viewBox="0 0 436 140" role="img" aria-label="Regen per dag in ${R.maandNaam}">
|
||
<line x1="0" x2="436" y1="${base + .5}" y2="${base + .5}" style="stroke:var(--line)"/>`;
|
||
for (let i = 0; i < R.dagenInMaand; i++) {
|
||
const day = i + 1, cx = cw * i + cw / 2;
|
||
if (day <= R.vandaagNr) {
|
||
const mm = R.perDag[i];
|
||
const color = day === R.vandaagNr ? 'var(--rain)' : day >= R.vandaagNr - 3 ? 'var(--rain)' : 'var(--rainsoft)';
|
||
const op = day === R.vandaagNr ? 1 : day >= R.vandaagNr - 3 ? .55 : 1;
|
||
if (mm > 0) {
|
||
const h = Math.max(3, mm / maxMM * 90);
|
||
s += `<rect x="${cx - 4.5}" y="${base - h}" width="9" height="${h}" rx="2" style="fill:${color};opacity:${op}"/>`;
|
||
} else {
|
||
s += `<rect x="${cx - 4.5}" y="${base - 2}" width="9" height="2" style="fill:var(--muted);opacity:.4"/>`;
|
||
}
|
||
} else {
|
||
s += `<circle cx="${cx}" cy="${base - 3}" r="1.8" style="fill:var(--line)"/>`;
|
||
}
|
||
if ([1, 5, 11, 15, 20, 25, 30].includes(day)) {
|
||
s += `<text x="${cx}" y="${base + 20}" text-anchor="middle" class="b-dl${day === R.vandaagNr ? ' now' : ''}">${day}</text>`;
|
||
}
|
||
}
|
||
return s + '</svg>';
|
||
}
|
||
|
||
function designB() {
|
||
const b = D.buiten, R = D.regen;
|
||
return `
|
||
<header class="b-top"><span>${D.datum}</span><span class="num">${D.tijd}, meting ${D.meting}</span></header>
|
||
<section class="b-out">
|
||
<p class="b-name">Buiten</p>
|
||
<p class="b-t num">${f1(b.t)}°</p>
|
||
<p class="b-mm num"><span class="cold">↓ ${f1(b.min)}° om ${b.minT}</span><span class="warm">↑ ${f1(b.max)}° om ${b.maxT}</span></p>
|
||
</section>
|
||
${D.binnen.map(r => `
|
||
<section class="b-in">
|
||
<p class="b-name">${r.naam}</p>
|
||
<p class="b-t num">${f1(r.t)}°</p>
|
||
<p class="b-mm num"><span class="cold">↓ ${f1(r.min)}°</span><span class="warm">↑ ${f1(r.max)}°</span></p>
|
||
</section>`).join('')}
|
||
<section class="b-panel b-fc">
|
||
<p class="b-h">Komende 5 dagen</p>
|
||
${forecastChart()}
|
||
</section>
|
||
<section class="b-panel b-rain">
|
||
<p class="b-h">Regen in ${R.maandNaam}</p>
|
||
<p class="b-total num">${f1(R.maand)}<span>mm deze maand</span></p>
|
||
${monthStrip()}
|
||
<div class="b-stats num">
|
||
<p class="now">Vandaag<b>${fmm(R.vandaag)}</b></p>
|
||
${[...R.dagen].reverse().map(x => `<p>${cap(x.d)}<b>${fmm(x.mm)}</b></p>`).join('')}
|
||
</div>
|
||
</section>`;
|
||
}
|
||
|
||
/* ---------- C ---------- */
|
||
function designC() {
|
||
const b = D.buiten, R = D.regen;
|
||
return `
|
||
<p class="c-date">${D.datum}</p>
|
||
<p class="c-clock serif num">${D.tijd}</p>
|
||
<section class="c-hero">
|
||
<p class="c-label">Buiten</p>
|
||
<p class="c-temp serif num">${f1(b.t)}°</p>
|
||
<p class="c-mm serif num">
|
||
<span class="cold">↓ ${f1(b.min)}°<small>${b.minT}</small></span>
|
||
<span class="warm">↑ ${f1(b.max)}°<small>${b.maxT}</small></span>
|
||
</p>
|
||
</section>
|
||
<section class="c-inside">
|
||
${D.binnen.map(r => `
|
||
<div>
|
||
<p class="c-rname">${r.naam}</p>
|
||
<p class="c-rt serif num">${f1(r.t)}°</p>
|
||
<p class="c-rmm num">↓ ${f1(r.min)}° ↑ ${f1(r.max)}°</p>
|
||
</div>`).join('')}
|
||
</section>
|
||
<section class="c-right">
|
||
<div>
|
||
${D.verwachting.map(d => `
|
||
<div class="c-row">
|
||
<span class="c-dn">${cap(d.dl)}</span>
|
||
<span class="c-ic">${icon(d.icon)}</span>
|
||
<span class="c-hl serif num">${d.hi}°<span>${d.lo}°</span></span>
|
||
<span class="c-fr num">${fmm(d.mm)}<span>${d.kans}%</span></span>
|
||
</div>`).join('')}
|
||
</div>
|
||
<div class="c-rain">
|
||
<p class="c-rl">Regen</p>
|
||
<p class="c-rbig"><b class="serif num">${f1(R.vandaag)}</b>mm vandaag</p>
|
||
<p class="c-past num">${[...R.dagen].reverse().map(x => `<span>${x.d}<b>${f1(x.mm)}</b></span>`).join('')}</p>
|
||
<p class="c-month num">${cap(R.maandNaam)}<b>${f1(R.maand)} mm</b></p>
|
||
</div>
|
||
</section>`;
|
||
}
|
||
|
||
/* ---------- render, tabs, schaal ---------- */
|
||
const captions = {
|
||
a: 'A: Buiten centraal. De buitentemperatuur is het grootst en vanaf de bank leesbaar. De balk eronder laat zien waar de huidige temperatuur zit tussen het minimum en maximum van vandaag. Binnenruimtes rechts, regen en verwachting in een rustige strook onderaan.',
|
||
b: 'B: Grafisch. Buiten en de drie ruimtes als vier gelijkwaardige tegels bovenaan. De verwachting staat als temperatuurbalken op één schaal, zodat je de trend ziet zonder cijfers te lezen. Regen als maandoverzicht per dag, met vandaag en de afgelopen drie dagen uitgelicht.',
|
||
c: 'C: Avondscherm. Donker en rustig, bedoeld om \u2019s avonds gedimd aan te laten staan in de woonkamer. Alleen cijfers en een lijst, geen grafieken. Kan ook als automatische nachtmodus naast A of B.'
|
||
};
|
||
|
||
const screen = document.getElementById('screen');
|
||
screen.innerHTML = `
|
||
<div class="design da active" data-d="a">${designA()}</div>
|
||
<div class="design db" data-d="b">${designB()}</div>
|
||
<div class="design dc" data-d="c">${designC()}</div>`;
|
||
|
||
const caption = document.getElementById('caption');
|
||
function show(key) {
|
||
document.querySelectorAll('.design').forEach(el => el.classList.toggle('active', el.dataset.d === key));
|
||
document.querySelectorAll('.tabs button').forEach(b => b.setAttribute('aria-selected', b.dataset.d === key));
|
||
caption.textContent = captions[key];
|
||
}
|
||
document.querySelectorAll('.tabs button').forEach(b => b.addEventListener('click', () => show(b.dataset.d)));
|
||
show('a');
|
||
|
||
const device = document.querySelector('.device'), scaler = document.querySelector('.scaler');
|
||
function fit() {
|
||
const s = Math.min(1, scaler.clientWidth / 1161);
|
||
device.style.transform = `scale(${s})`;
|
||
scaler.style.height = (772 * s) + 'px';
|
||
}
|
||
window.addEventListener('resize', fit);
|
||
fit();
|
||
</script>
|
||
</body>
|
||
</html>
|