Skip to content

Commit

Permalink
Location selector: Move location on map click (#22198)
Browse files Browse the repository at this point in the history
* Add button to location-selector to move marker to current view

* move on click

* double-click handling
  • Loading branch information
karwosts authored Dec 5, 2024
1 parent a7406b3 commit a3ca889
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/components/ha-selector/ha-selector-location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export class HaLocationSelector extends LitElement {
.locations=${this._location(this.selector, this.value)}
@location-updated=${this._locationChanged}
@radius-updated=${this._radiusChanged}
pin-on-click
></ha-locations-editor>
<ha-form
.hass=${this.hass}
Expand Down
39 changes: 33 additions & 6 deletions src/components/map/ha-locations-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export class HaLocationsEditor extends LitElement {
@property({ attribute: "theme-mode", type: String })
public themeMode: ThemeMode = "auto";

@property({ type: Boolean, attribute: "pin-on-click" })
public pinOnClick = false;

@state() private _locationMarkers?: Record<string, Marker | Circle>;

@state() private _circles: Record<string, Circle> = {};
Expand Down Expand Up @@ -129,6 +132,8 @@ export class HaLocationsEditor extends LitElement {
.zoom=${this.zoom}
.autoFit=${this.autoFit}
.themeMode=${this.themeMode}
.clickable=${this.pinOnClick}
@map-clicked=${this._mapClicked}
></ha-map>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
Expand Down Expand Up @@ -193,15 +198,21 @@ export class HaLocationsEditor extends LitElement {
}
}

private _updateLocation(ev: DragEndEvent) {
const marker = ev.target;
const latlng: LatLng = marker.getLatLng();
let longitude: number = latlng.lng;
private _normalizeLongitude(longitude: number): number {
if (Math.abs(longitude) > 180.0) {
// Normalize longitude if map provides values beyond -180 to +180 degrees.
longitude = (((longitude % 360.0) + 540.0) % 360.0) - 180.0;
return (((longitude % 360.0) + 540.0) % 360.0) - 180.0;
}
const location: [number, number] = [latlng.lat, longitude];
return longitude;
}

private _updateLocation(ev: DragEndEvent) {
const marker = ev.target;
const latlng: LatLng = marker.getLatLng();
const location: [number, number] = [
latlng.lat,
this._normalizeLongitude(latlng.lng),
];
fireEvent(
this,
"location-updated",
Expand All @@ -226,6 +237,22 @@ export class HaLocationsEditor extends LitElement {
fireEvent(this, "marker-clicked", { id: marker.id }, { bubbles: false });
}

private _mapClicked(ev) {
if (this.pinOnClick && this._locationMarkers) {
const id = Object.keys(this._locationMarkers)[0];
const location: [number, number] = [
ev.detail.location[0],
this._normalizeLongitude(ev.detail.location[1]),
];
fireEvent(this, "location-updated", { id, location }, { bubbles: false });

// If the normalized longitude wraps around the globe, pan to the new location.
if (location[1] !== ev.detail.location[1]) {
this.map.leafletMap?.panTo({ lat: location[0], lng: location[1] });
}
}
}

private _updateMarkers(): void {
if (!this.locations || !this.locations.length) {
this._circles = {};
Expand Down
30 changes: 30 additions & 0 deletions src/components/map/ha-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
import type { CSSResultGroup, PropertyValues } from "lit";
import { ReactiveElement, css } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { formatDateTime } from "../../common/datetime/format_date_time";
import {
formatTimeWeekday,
Expand All @@ -26,6 +27,13 @@ import { isTouch } from "../../util/is_touch";
import "../ha-icon-button";
import "./ha-entity-marker";

declare global {
// for fire event
interface HASSDomEvents {
"map-clicked": { location: [number, number] };
}
}

const getEntityId = (entity: string | HaMapEntity): string =>
typeof entity === "string" ? entity : entity.entity_id;

Expand Down Expand Up @@ -59,6 +67,8 @@ export class HaMap extends ReactiveElement {

@property({ attribute: false }) public layers?: Layer[];

@property({ type: Boolean }) public clickable = false;

@property({ type: Boolean }) public autoFit = false;

@property({ type: Boolean }) public renderPassive = false;
Expand Down Expand Up @@ -90,6 +100,8 @@ export class HaMap extends ReactiveElement {

private _mapPaths: Array<Polyline | CircleMarker> = [];

private _clickCount = 0;

public connectedCallback(): void {
super.connectedCallback();
this._loadMap();
Expand Down Expand Up @@ -173,6 +185,7 @@ export class HaMap extends ReactiveElement {

private _updateMapStyle(): void {
const map = this.renderRoot.querySelector("#map");
map!.classList.toggle("clickable", this.clickable);
map!.classList.toggle("dark", this._darkMode);
map!.classList.toggle("forced-dark", this.themeMode === "dark");
map!.classList.toggle("forced-light", this.themeMode === "light");
Expand All @@ -192,6 +205,19 @@ export class HaMap extends ReactiveElement {
try {
[this.leafletMap, this.Leaflet] = await setupLeafletMap(map);
this._updateMapStyle();
this.leafletMap.on("click", (ev) => {
if (this._clickCount === 0) {
setTimeout(() => {
if (this._clickCount === 1) {
fireEvent(this, "map-clicked", {
location: [ev.latlng.lat, ev.latlng.lng],
});
}
this._clickCount = 0;
}, 250);
}
this._clickCount++;
});
this._loaded = true;
} finally {
this._loading = false;
Expand Down Expand Up @@ -558,6 +584,9 @@ export class HaMap extends ReactiveElement {
#map {
height: 100%;
}
#map.clickable {
cursor: pointer;
}
#map.dark {
background: #090909;
}
Expand All @@ -571,6 +600,7 @@ export class HaMap extends ReactiveElement {
color: #000000;
--map-filter: invert(0);
}
#map.clickable:active,
#map:active {
cursor: grabbing;
cursor: -moz-grabbing;
Expand Down

0 comments on commit a3ca889

Please sign in to comment.