diff --git a/src/components/map/ha-map.ts b/src/components/map/ha-map.ts index d9294bc58c..466fe0a0d1 100644 --- a/src/components/map/ha-map.ts +++ b/src/components/map/ha-map.ts @@ -23,8 +23,12 @@ import "./ha-entity-marker"; const getEntityId = (entity: string | HaMapEntity): string => typeof entity === "string" ? entity : entity.entity_id; +export interface HaMapPathPoint { + point: LatLngTuple; + tooltip: string; +} export interface HaMapPaths { - points: LatLngTuple[]; + points: HaMapPathPoint[]; color?: string; gradualOpacity?: number; } @@ -247,19 +251,21 @@ export class HaMap extends ReactiveElement { // DRAW point this._mapPaths.push( - Leaflet!.circleMarker(path.points[pointIndex], { - radius: 3, - color: path.color || darkPrimaryColor, - opacity, - fillOpacity: opacity, - interactive: false, - }) + Leaflet! + .circleMarker(path.points[pointIndex].point, { + radius: 3, + color: path.color || darkPrimaryColor, + opacity, + fillOpacity: opacity, + interactive: true, + }) + .bindTooltip(path.points[pointIndex].tooltip, { direction: "top" }) ); // DRAW line between this and next point this._mapPaths.push( Leaflet!.polyline( - [path.points[pointIndex], path.points[pointIndex + 1]], + [path.points[pointIndex].point, path.points[pointIndex + 1].point], { color: path.color || darkPrimaryColor, opacity, @@ -275,13 +281,15 @@ export class HaMap extends ReactiveElement { : undefined; // DRAW end path point this._mapPaths.push( - Leaflet!.circleMarker(path.points[pointIndex], { - radius: 3, - color: path.color || darkPrimaryColor, - opacity, - fillOpacity: opacity, - interactive: false, - }) + Leaflet! + .circleMarker(path.points[pointIndex].point, { + radius: 3, + color: path.color || darkPrimaryColor, + opacity, + fillOpacity: opacity, + interactive: true, + }) + .bindTooltip(path.points[pointIndex].tooltip, { direction: "top" }) ); } this._mapPaths.forEach((marker) => map.addLayer(marker)); @@ -491,6 +499,14 @@ export class HaMap extends ReactiveElement { .leaflet-bottom { z-index: 1 !important; } + .leaflet-tooltip { + padding: 8px; + font-size: 90%; + background: rgba(80, 80, 80, 0.9) !important; + color: white !important; + border-radius: 4px; + box-shadow: none !important; + } `; } } diff --git a/src/panels/lovelace/cards/hui-map-card.ts b/src/panels/lovelace/cards/hui-map-card.ts index 59b1e780bf..e5b7951160 100644 --- a/src/panels/lovelace/cards/hui-map-card.ts +++ b/src/panels/lovelace/cards/hui-map-card.ts @@ -11,6 +11,7 @@ import { import { customElement, property, query, state } from "lit/decorators"; import { mdiImageFilterCenterFocus } from "@mdi/js"; import memoizeOne from "memoize-one"; +import { isToday } from "date-fns"; import { computeDomain } from "../../../common/entity/compute_domain"; import parseAspectRatio from "../../../common/util/parse-aspect-ratio"; import "../../../components/ha-card"; @@ -23,8 +24,17 @@ import { EntityConfig } from "../entity-rows/types"; import { LovelaceCard } from "../types"; import { MapCardConfig } from "./types"; import "../../../components/map/ha-map"; -import type { HaMap, HaMapPaths } from "../../../components/map/ha-map"; +import type { + HaMap, + HaMapPaths, + HaMapPathPoint, +} from "../../../components/map/ha-map"; import { getColorByIndex } from "../../../common/color/colors"; +import { formatDateTime } from "../../../common/datetime/format_date_time"; +import { + formatTime, + formatTimeWeekday, +} from "../../../common/datetime/format_time"; const MINUTE = 60000; @@ -274,16 +284,28 @@ class HuiMapCard extends LitElement implements LovelaceCard { } // filter location data from states and remove all invalid locations const points = entityStates.reduce( - (accumulator: LatLngTuple[], entityState) => { + (accumulator: HaMapPathPoint[], entityState) => { const latitude = entityState.attributes.latitude; const longitude = entityState.attributes.longitude; if (latitude && longitude) { - accumulator.push([latitude, longitude] as LatLngTuple); + const p = {} as HaMapPathPoint; + p.point = [latitude, longitude] as LatLngTuple; + const t = new Date(entityState.last_updated); + if (config.hours_to_show! > 144) { + // if showing > 6 days in the history trail, show the full + // date and time + p.tooltip = formatDateTime(t, this.hass.locale); + } else if (isToday(t)) { + p.tooltip = formatTime(t, this.hass.locale); + } else { + p.tooltip = formatTimeWeekday(t, this.hass.locale); + } + accumulator.push(p); } return accumulator; }, [] - ) as LatLngTuple[]; + ) as HaMapPathPoint[]; paths.push({ points,