Updated scope temperature arc to gradient
Fix banner scaling
Add Pulldown to scope
This commit is contained in:
Fraxle
2026-05-27 00:52:24 +01:00
parent d2952cddd2
commit 0c8cb1ba37
5 changed files with 211 additions and 51 deletions
+44 -33
View File
@@ -10,7 +10,7 @@
// SkyScope({ elev, dt, glob, size }) small porthole per hour
// WindVane({ bearing, size }) compass-arrow widget
// CloudIcon({ category, size, elev, dt }) cloud/sun glyph
// ScopeReticle({ value, cat, loading, elev, dt, glob, activeEvent })
// ScopeReticle({ value, cat, loading, elev, dt, glob, activeEvent, utciEnvShort })
// large UTCI dial
// PrecipIcon({ precip, snow, size }) rain/snow icon
// ------------------------------------------------------------------------
@@ -92,6 +92,7 @@ export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel,
onClick=${(e) => { e.stopPropagation(); setOpen(o => !o); }}
type="button"
>
<span class="cs-btn-overlay"></span>
<span class="cs-btn-label">${btnLabel}</span>
<span class="cs-arrow"></span>
</button>
@@ -454,32 +455,39 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g
major, medium,
};
});
const stressBands = [
{ min: -40, max: -27, color: '#5a9bdc' },
{ min: -27, max: -13, color: '#5a9bdc' },
{ min: -13, max: 0, color: '#6ca9e1' },
{ min: 0, max: 9, color: '#93ccd9' },
{ min: 9, max: 18, color: '#92d4a3' },
{ min: 18, max: 26, color: '#dae15f' },
{ min: 26, max: 32, color: '#f8a13f' },
{ min: 32, max: 38, color: '#e15333' },
{ min: 38, max: 46, color: '#ae181c' },
{ min: 46, max: 50, color: '#8d0616' },
];
function fracToXY(frac, r) {
const deg = 135 + frac * 270;
const rad = (deg * Math.PI) / 180;
return [cx + r * Math.cos(rad), cy + r * Math.sin(rad)];
}
function bandArcPath(band) {
const f1 = Math.min(1, Math.max(0, (band.min + 10) / 60));
const f2 = Math.min(1, Math.max(0, (band.max + 10) / 60));
const arcR = R - 18;
// Gradient colour stops: frac 0 = 10 °C, frac 1 = 50 °C
const ARC_GRAD = [
[0, [106, 169, 225]],
[0.167, [147, 204, 217]],
[0.317, [146, 212, 163]],
[0.467, [218, 225, 95]],
[0.600, [248, 161, 63]],
[0.700, [225, 83, 51]],
[0.800, [174, 24, 28]],
[1.000, [141, 6, 22]],
];
function arcColorAt(f) {
for (let i = 0; i < ARC_GRAD.length - 1; i++) {
const [f1, c1] = ARC_GRAD[i], [f2, c2] = ARC_GRAD[i + 1];
if (f <= f2) {
const t = (f - f1) / (f2 - f1);
return `rgb(${Math.round(c1[0]+(c2[0]-c1[0])*t)},${Math.round(c1[1]+(c2[1]-c1[1])*t)},${Math.round(c1[2]+(c2[2]-c1[2])*t)})`;
}
}
return 'rgb(141,6,22)';
}
const arcR = R - 18;
const gradArc = Array.from({ length: 90 }, (_, i) => {
const f1 = i / 90, f2 = (i + 1) / 90;
const [x1, y1] = fracToXY(f1, arcR);
const [x2, y2] = fracToXY(f2, arcR);
const large = (f2 - f1) * 270 > 180 ? 1 : 0;
return `M ${x1} ${y1} A ${arcR} ${arcR} 0 ${large} 1 ${x2} ${y2}`;
}
return { d: `M ${x1} ${y1} A ${arcR} ${arcR} 0 0 1 ${x2} ${y2}`, color: arcColorAt((f1+f2)/2) };
});
let needleX = cx, needleY = cy + 54;
if (value != null) {
const frac = Math.min(1, Math.max(0, (value + 10) / 60));
@@ -569,9 +577,9 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g
if (!overlaySVG) return null;
return html`<g dangerouslySetInnerHTML=${{ __html: overlaySVG }} />`;
})()}
${stressBands.map((b, i) => html`
<path key=${i} d=${bandArcPath(b)} fill="none"
stroke=${b.color} stroke-width="4" stroke-linecap="butt" />`)}
${gradArc.map((seg, i) => html`
<path key=${i} d=${seg.d} fill="none"
stroke=${seg.color} stroke-width="4" stroke-linecap="butt" />`)}
<circle cx=${cx} cy=${cy} r=${R} fill="none" stroke="#c9b08a" stroke-width="1.5" />
${ticks.map((t, i) => html`
<line key=${i} x1=${t.x1} y1=${t.y1} x2=${t.x2} y2=${t.y2}
@@ -621,23 +629,26 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), g
font-family="Fraunces, serif" font-weight="700">
${value.toFixed(1)}°
</text>
<text x=${cx} y=${cy + 15} text-anchor="middle"
fill=${readoutMutedColor} font-size="6.5"
<text x=${cx} y=${cy + 14} text-anchor="middle"
fill=${readoutColor} font-size="8"
font-family="Manrope, sans-serif" font-weight="700" letter-spacing="1.2">
UTCI NOW
SUNSOAK INDEX
</text>
<text x=${cx} y=${cy + 23} text-anchor="middle"
fill=${glowColor} font-size="7"
fill=${glowColor} font-size="9"
font-family="Manrope, sans-serif" font-weight="700" letter-spacing="0.5">
${cat.label.toUpperCase()}
</text>
${utciEnvShort && html`
<text x=${cx} y="163" text-anchor="middle"
fill=${readoutMutedColor} font-size="5.5"
font-family="Manrope, sans-serif" font-weight="700" letter-spacing="0.8"
opacity="0.85">
${utciEnvShort.toUpperCase()} EST.
</text>`}
<${Fragment}>
<rect x=${cx - 34} y="158" width="68" height="11" rx="3"
fill=${glowColor} opacity="0.22" />
<text x=${cx} y="166" text-anchor="middle"
fill=${readoutColor} font-size="7"
font-family="Manrope, sans-serif" font-weight="700" letter-spacing="0.6">
${utciEnvShort.toUpperCase()}
</text>
</>`}
</>`
: html`<text x=${cx} y=${cy + 5} text-anchor="middle"
fill=${readoutMutedColor} font-size="8"