feat(rover): drive-radius circle resizes live as max-drive-time slider drags

This commit is contained in:
Graham McIntire 2026-04-25 16:42:49 -05:00
parent e2dfc05939
commit 784caa7699
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
2 changed files with 22 additions and 4 deletions

View file

@ -29,6 +29,7 @@ interface RoverMapHook extends ViewHook {
homeLon: number
driveRadiusKm: number
visibilityHandler: (() => void) | null
driveRadiusListener: ((e: Event) => void) | null
renderStations(this: RoverMapHook): void
buildQualityLayer(this: RoverMapHook): L.GridLayer
@ -174,6 +175,12 @@ export const RoverMap: Partial<RoverMapHook> = {
}
document.addEventListener("visibilitychange", this.visibilityHandler)
this.driveRadiusListener = (e: Event) => {
const km = (e as CustomEvent<{ km: number }>).detail?.km
if (typeof km === "number") this.setDriveRadius(km)
}
window.addEventListener("rover:drive-radius", this.driveRadiusListener)
this.handleEvent("stations_updated", ({ stations }: { stations: Station[] }) => {
this.stations = stations
this.renderStations()
@ -229,6 +236,10 @@ export const RoverMap: Partial<RoverMapHook> = {
document.removeEventListener("visibilitychange", this.visibilityHandler)
this.visibilityHandler = null
}
if (this.driveRadiusListener) {
window.removeEventListener("rover:drive-radius", this.driveRadiusListener)
this.driveRadiusListener = null
}
},
setDriveRadius(this: RoverMapHook, km: number) {

View file

@ -3,9 +3,12 @@ import type { ViewHook } from "phoenix_live_view"
interface RoverSliderHook extends ViewHook {
labelEl: HTMLElement | null
formatter: (v: number) => string
format: string
inputHandler: () => void
}
const AVG_SPEED_KMH = 65.0
const formatters: Record<string, (v: number) => string> = {
forecast: (v) => `+${v}h`,
drive: (v) => {
@ -17,14 +20,18 @@ const formatters: Record<string, (v: number) => string> = {
export const RoverSlider: Partial<RoverSliderHook> = {
mounted(this: RoverSliderHook) {
const labelId = this.el.dataset.labelId || ""
const format = this.el.dataset.format || "forecast"
this.format = this.el.dataset.format || "forecast"
this.formatter = formatters[format] || formatters.forecast
this.formatter = formatters[this.format] || formatters.forecast
this.labelEl = document.getElementById(labelId)
this.inputHandler = () => {
if (this.labelEl) {
this.labelEl.textContent = this.formatter(Number((this.el as HTMLInputElement).value))
const value = Number((this.el as HTMLInputElement).value)
if (this.labelEl) this.labelEl.textContent = this.formatter(value)
if (this.format === "drive") {
const km = (value * AVG_SPEED_KMH) / 60.0
window.dispatchEvent(new CustomEvent("rover:drive-radius", { detail: { km } }))
}
}