mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-13 04:16:34 +00:00
Location selector: Move location on map click (#22198)
* Add button to location-selector to move marker to current view * move on click * double-click handling
This commit is contained in:
parent
a7406b3201
commit
a3ca889ca3
@ -79,6 +79,7 @@ export class HaLocationSelector extends LitElement {
|
|||||||
.locations=${this._location(this.selector, this.value)}
|
.locations=${this._location(this.selector, this.value)}
|
||||||
@location-updated=${this._locationChanged}
|
@location-updated=${this._locationChanged}
|
||||||
@radius-updated=${this._radiusChanged}
|
@radius-updated=${this._radiusChanged}
|
||||||
|
pin-on-click
|
||||||
></ha-locations-editor>
|
></ha-locations-editor>
|
||||||
<ha-form
|
<ha-form
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
@ -58,6 +58,9 @@ export class HaLocationsEditor extends LitElement {
|
|||||||
@property({ attribute: "theme-mode", type: String })
|
@property({ attribute: "theme-mode", type: String })
|
||||||
public themeMode: ThemeMode = "auto";
|
public themeMode: ThemeMode = "auto";
|
||||||
|
|
||||||
|
@property({ type: Boolean, attribute: "pin-on-click" })
|
||||||
|
public pinOnClick = false;
|
||||||
|
|
||||||
@state() private _locationMarkers?: Record<string, Marker | Circle>;
|
@state() private _locationMarkers?: Record<string, Marker | Circle>;
|
||||||
|
|
||||||
@state() private _circles: Record<string, Circle> = {};
|
@state() private _circles: Record<string, Circle> = {};
|
||||||
@ -129,6 +132,8 @@ export class HaLocationsEditor extends LitElement {
|
|||||||
.zoom=${this.zoom}
|
.zoom=${this.zoom}
|
||||||
.autoFit=${this.autoFit}
|
.autoFit=${this.autoFit}
|
||||||
.themeMode=${this.themeMode}
|
.themeMode=${this.themeMode}
|
||||||
|
.clickable=${this.pinOnClick}
|
||||||
|
@map-clicked=${this._mapClicked}
|
||||||
></ha-map>
|
></ha-map>
|
||||||
${this.helper
|
${this.helper
|
||||||
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
|
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
|
||||||
@ -193,15 +198,21 @@ export class HaLocationsEditor extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _normalizeLongitude(longitude: number): number {
|
||||||
|
if (Math.abs(longitude) > 180.0) {
|
||||||
|
// Normalize longitude if map provides values beyond -180 to +180 degrees.
|
||||||
|
return (((longitude % 360.0) + 540.0) % 360.0) - 180.0;
|
||||||
|
}
|
||||||
|
return longitude;
|
||||||
|
}
|
||||||
|
|
||||||
private _updateLocation(ev: DragEndEvent) {
|
private _updateLocation(ev: DragEndEvent) {
|
||||||
const marker = ev.target;
|
const marker = ev.target;
|
||||||
const latlng: LatLng = marker.getLatLng();
|
const latlng: LatLng = marker.getLatLng();
|
||||||
let longitude: number = latlng.lng;
|
const location: [number, number] = [
|
||||||
if (Math.abs(longitude) > 180.0) {
|
latlng.lat,
|
||||||
// Normalize longitude if map provides values beyond -180 to +180 degrees.
|
this._normalizeLongitude(latlng.lng),
|
||||||
longitude = (((longitude % 360.0) + 540.0) % 360.0) - 180.0;
|
];
|
||||||
}
|
|
||||||
const location: [number, number] = [latlng.lat, longitude];
|
|
||||||
fireEvent(
|
fireEvent(
|
||||||
this,
|
this,
|
||||||
"location-updated",
|
"location-updated",
|
||||||
@ -226,6 +237,22 @@ export class HaLocationsEditor extends LitElement {
|
|||||||
fireEvent(this, "marker-clicked", { id: marker.id }, { bubbles: false });
|
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 {
|
private _updateMarkers(): void {
|
||||||
if (!this.locations || !this.locations.length) {
|
if (!this.locations || !this.locations.length) {
|
||||||
this._circles = {};
|
this._circles = {};
|
||||||
|
@ -12,6 +12,7 @@ import type {
|
|||||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||||
import { ReactiveElement, css } from "lit";
|
import { ReactiveElement, css } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { formatDateTime } from "../../common/datetime/format_date_time";
|
import { formatDateTime } from "../../common/datetime/format_date_time";
|
||||||
import {
|
import {
|
||||||
formatTimeWeekday,
|
formatTimeWeekday,
|
||||||
@ -26,6 +27,13 @@ import { isTouch } from "../../util/is_touch";
|
|||||||
import "../ha-icon-button";
|
import "../ha-icon-button";
|
||||||
import "./ha-entity-marker";
|
import "./ha-entity-marker";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// for fire event
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"map-clicked": { location: [number, number] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getEntityId = (entity: string | HaMapEntity): string =>
|
const getEntityId = (entity: string | HaMapEntity): string =>
|
||||||
typeof entity === "string" ? entity : entity.entity_id;
|
typeof entity === "string" ? entity : entity.entity_id;
|
||||||
|
|
||||||
@ -59,6 +67,8 @@ export class HaMap extends ReactiveElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public layers?: Layer[];
|
@property({ attribute: false }) public layers?: Layer[];
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public clickable = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public autoFit = false;
|
@property({ type: Boolean }) public autoFit = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public renderPassive = false;
|
@property({ type: Boolean }) public renderPassive = false;
|
||||||
@ -90,6 +100,8 @@ export class HaMap extends ReactiveElement {
|
|||||||
|
|
||||||
private _mapPaths: Array<Polyline | CircleMarker> = [];
|
private _mapPaths: Array<Polyline | CircleMarker> = [];
|
||||||
|
|
||||||
|
private _clickCount = 0;
|
||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this._loadMap();
|
this._loadMap();
|
||||||
@ -173,6 +185,7 @@ export class HaMap extends ReactiveElement {
|
|||||||
|
|
||||||
private _updateMapStyle(): void {
|
private _updateMapStyle(): void {
|
||||||
const map = this.renderRoot.querySelector("#map");
|
const map = this.renderRoot.querySelector("#map");
|
||||||
|
map!.classList.toggle("clickable", this.clickable);
|
||||||
map!.classList.toggle("dark", this._darkMode);
|
map!.classList.toggle("dark", this._darkMode);
|
||||||
map!.classList.toggle("forced-dark", this.themeMode === "dark");
|
map!.classList.toggle("forced-dark", this.themeMode === "dark");
|
||||||
map!.classList.toggle("forced-light", this.themeMode === "light");
|
map!.classList.toggle("forced-light", this.themeMode === "light");
|
||||||
@ -192,6 +205,19 @@ export class HaMap extends ReactiveElement {
|
|||||||
try {
|
try {
|
||||||
[this.leafletMap, this.Leaflet] = await setupLeafletMap(map);
|
[this.leafletMap, this.Leaflet] = await setupLeafletMap(map);
|
||||||
this._updateMapStyle();
|
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;
|
this._loaded = true;
|
||||||
} finally {
|
} finally {
|
||||||
this._loading = false;
|
this._loading = false;
|
||||||
@ -558,6 +584,9 @@ export class HaMap extends ReactiveElement {
|
|||||||
#map {
|
#map {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
#map.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
#map.dark {
|
#map.dark {
|
||||||
background: #090909;
|
background: #090909;
|
||||||
}
|
}
|
||||||
@ -571,6 +600,7 @@ export class HaMap extends ReactiveElement {
|
|||||||
color: #000000;
|
color: #000000;
|
||||||
--map-filter: invert(0);
|
--map-filter: invert(0);
|
||||||
}
|
}
|
||||||
|
#map.clickable:active,
|
||||||
#map:active {
|
#map:active {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
cursor: -moz-grabbing;
|
cursor: -moz-grabbing;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user