Vehicle Speed Calcs
Extra At A Glance ranges
New Driver profile
This commit is contained in:
Fraxle
2026-06-27 06:19:25 +01:00
parent 0675d4987b
commit efcf2d621c
9 changed files with 177 additions and 73 deletions
+33 -8
View File
@@ -26,7 +26,7 @@ import htm from '../vendor/htm.js';
import {
utciCategory, UTCI_BANDS, bandGradient,
SKIN_TYPES, sunburnMinutes, burnLabel,
VEHICLE_TYPES, BUILDING_TYPES,
VEHICLE_TYPES, VEHICLE_SPEEDS, BUILDING_TYPES,
confidenceBand, moonGlyph, skyFillForElev,
} from './utils.js';
import { SkyScope, WindVane, CloudIcon, ScopeReticle, PrecipIcon, CustomSelect, VentPill } from './components.js';
@@ -190,6 +190,7 @@ export function UTCIForecast() {
skinType, setSkinType,
vehicleType, setVehicleType,
vehicleVent, setVehicleVent,
vehicleSpeed, setVehicleSpeed,
outdoorsVariant, setOutdoorsVariantAndSave,
buildingType, setBuildingType,
indoorManaged, setIndoorManaged,
@@ -451,6 +452,7 @@ export function UTCIForecast() {
outdoorsVariant,
skinType,
visibleCols,
vehicleSpeed,
);
// Human-readable date for the "Day at a glance" heading, e.g. "Mon 2nd June 2026".
@@ -875,7 +877,7 @@ export function UTCIForecast() {
/>
</span>`}
${showVehicle && html`
<span class=${'col-toggle-group' + (vehicleOn ? ' col-toggle-group--expanded' : '')}>
<span class=${'col-toggle-group' + (vehicleOn ? ' col-toggle-group--expanded col-toggle-group--triple' : '')}>
<${CustomSelect}
value=${vehicleType} isOn=${vehicleOn} grpClass="grp-felt"
hideLabel="Vehicle" hidingLabel="Vehicle"
@@ -887,9 +889,16 @@ export function UTCIForecast() {
}}
/>
${vehicleOn && html`
<${CustomSelect}
value=${vehicleSpeed} isOn=${true} noHide=${true} grpClass="grp-felt"
buttonLabel=${(VEHICLE_SPEEDS[vehicleSpeed] ?? VEHICLE_SPEEDS.static).name}
groupedLeft=${true} isLastChild=${false}
options=${Object.entries(VEHICLE_SPEEDS).map(([k, v]) => ({ value: k, label: v.name }))}
onChange=${v => setVehicleSpeed(v)}
/>
<${VentPill} checked=${vehicleVent} onChange=${() => setVehicleVent(v => !v)}
grpClass="grp-felt" label="Ventilation"
title="Open windows significantly reduce cabin heat build-up" />`}
title="Open windows significantly reduce cabin heat build-up. Speed sets cabin airflow from forward motion." />`}
</span>`}
${showIndoor && html`
<span class=${'col-toggle-group' + (indoorOn ? ' col-toggle-group--expanded' : '')}>
@@ -941,7 +950,7 @@ export function UTCIForecast() {
/>
</span>`}
${(isPro ? (activeProfile === 'custom' || activeProfile === 'showall' || activeCols['vehicleT']) : activeCols['vehicleT']) && html`
<span class=${'col-toggle-group' + (visibleCols.vehicleT ? ' col-toggle-group--expanded' : '')}>
<span class=${'col-toggle-group' + (visibleCols.vehicleT ? ' col-toggle-group--expanded col-toggle-group--triple' : '')}>
<${CustomSelect}
value=${vehicleType}
isOn=${visibleCols.vehicleT}
@@ -965,12 +974,23 @@ export function UTCIForecast() {
}}
/>
${visibleCols.vehicleT && html`
<${CustomSelect}
value=${vehicleSpeed}
isOn=${true}
noHide=${true}
grpClass="grp-felt"
buttonLabel=${(VEHICLE_SPEEDS[vehicleSpeed] ?? VEHICLE_SPEEDS.static).name}
groupedLeft=${true}
isLastChild=${false}
options=${Object.entries(VEHICLE_SPEEDS).map(([k, v]) => ({ value: k, label: v.name }))}
onChange=${(v) => setVehicleSpeed(v)}
/>
<${VentPill}
checked=${vehicleVent}
onChange=${() => setVehicleVent(v => !v)}
grpClass="grp-felt"
label="Ventilation"
title="Ventilation — open windows significantly reduce cabin heat build-up"
title="Ventilation — open windows significantly reduce cabin heat build-up. Speed sets cabin airflow from forward motion."
/>`}
</span>`}
${(isPro ? (activeProfile === 'custom' || activeProfile === 'showall' || activeCols['indoorT'] || activeCols['managedT']) : (activeCols['indoorT'] || activeCols['managedT'])) && html`
@@ -1562,15 +1582,20 @@ export function UTCIForecast() {
<span class="insight-label">${label}</span>
<span class="insight-value">${value}</span>
</div>`;
const comfortItem = glanceSummary.find(i => i.label === 'Comfortable window');
const restSummary = glanceSummary.filter(i => i.label !== 'Comfortable window');
// Only the outdoors profile reorders items around the heat block
// (it has a 'Peak felt temp' anchor). Other profiles render in order.
const hasFeltAnchor = glanceSummary.some(i => i.label === 'Peak felt temp');
const comfortItem = hasFeltAnchor ? glanceSummary.find(i => i.label === 'Comfortable window') : null;
const drivingItem = hasFeltAnchor ? glanceSummary.find(i => i.label === 'Good driving time') : null;
const restSummary = glanceSummary.filter(i => !(hasFeltAnchor && (i.label === 'Comfortable window' || i.label === 'Good driving time')));
return [
...restSummary.flatMap(item => [
renderRow(item),
// After the peak/heat block, drop in the comfortable window
// After the peak/heat block, drop in good driving time then the comfortable window
...(item.label === 'Peak felt temp'
? [
...heatEvents.map(e => renderRow(e, 'ev-')),
...(drivingItem ? [renderRow(drivingItem)] : []),
...(comfortItem ? [renderRow(comfortItem)] : []),
]
: []),