mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-20 02:38:53 +00:00
Add zones config UI (#4556)
* Add zones config UI * Update en.json * Update dialog-zone-detail.ts * Update hc-cast.ts * Update more-info-content.ts * Add drag radius and icon to dialog * Review comments
This commit is contained in:
committed by
Paulus Schoutsen
parent
def0c51669
commit
49611e285f
@@ -8,24 +8,35 @@ import {
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { Marker, Map, LeafletMouseEvent, DragEndEvent, LatLng } from "leaflet";
|
||||
import {
|
||||
Marker,
|
||||
Map,
|
||||
LeafletMouseEvent,
|
||||
DragEndEvent,
|
||||
LatLng,
|
||||
Circle,
|
||||
DivIcon,
|
||||
} from "leaflet";
|
||||
import {
|
||||
setupLeafletMap,
|
||||
LeafletModuleType,
|
||||
} from "../../common/dom/setup-leaflet-map";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { nextRender } from "../../common/util/render-status";
|
||||
|
||||
@customElement("ha-location-editor")
|
||||
class LocationEditor extends LitElement {
|
||||
@property() public location?: [number, number];
|
||||
@property() public radius?: number;
|
||||
@property() public icon?: string;
|
||||
public fitZoom = 16;
|
||||
|
||||
private _iconEl?: DivIcon;
|
||||
private _ignoreFitToMap?: [number, number];
|
||||
|
||||
// tslint:disable-next-line
|
||||
private Leaflet?: LeafletModuleType;
|
||||
private _leafletMap?: Map;
|
||||
private _locationMarker?: Marker;
|
||||
private _locationMarker?: Marker | Circle;
|
||||
|
||||
public fitMap(): void {
|
||||
if (!this._leafletMap || !this.location) {
|
||||
@@ -53,11 +64,24 @@ class LocationEditor extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateMarker();
|
||||
if (!this._ignoreFitToMap || this._ignoreFitToMap !== this.location) {
|
||||
this.fitMap();
|
||||
if (changedProps.has("location")) {
|
||||
this._updateMarker();
|
||||
if (
|
||||
this.location &&
|
||||
(!this._ignoreFitToMap ||
|
||||
this._ignoreFitToMap[0] !== this.location[0] ||
|
||||
this._ignoreFitToMap[1] !== this.location[1])
|
||||
) {
|
||||
this.fitMap();
|
||||
}
|
||||
this._ignoreFitToMap = undefined;
|
||||
}
|
||||
if (changedProps.has("radius")) {
|
||||
this._updateRadius();
|
||||
}
|
||||
if (changedProps.has("icon")) {
|
||||
this._updateIcon();
|
||||
}
|
||||
this._ignoreFitToMap = undefined;
|
||||
}
|
||||
|
||||
private get _mapEl(): HTMLDivElement {
|
||||
@@ -65,18 +89,23 @@ class LocationEditor extends LitElement {
|
||||
}
|
||||
|
||||
private async _initMap(): Promise<void> {
|
||||
[this._leafletMap, this.Leaflet] = await setupLeafletMap(this._mapEl);
|
||||
[this._leafletMap, this.Leaflet] = await setupLeafletMap(
|
||||
this._mapEl,
|
||||
false,
|
||||
Boolean(this.radius)
|
||||
);
|
||||
this._leafletMap.addEventListener(
|
||||
"click",
|
||||
// @ts-ignore
|
||||
(ev: LeafletMouseEvent) => this._updateLocation(ev.latlng)
|
||||
(ev: LeafletMouseEvent) => this._locationUpdated(ev.latlng)
|
||||
);
|
||||
this._updateIcon();
|
||||
this._updateMarker();
|
||||
this.fitMap();
|
||||
this._leafletMap.invalidateSize();
|
||||
}
|
||||
|
||||
private _updateLocation(latlng: LatLng) {
|
||||
private _locationUpdated(latlng: LatLng) {
|
||||
let longitude = latlng.lng;
|
||||
if (Math.abs(longitude) > 180.0) {
|
||||
// Normalize longitude if map provides values beyond -180 to +180 degrees.
|
||||
@@ -86,7 +115,68 @@ class LocationEditor extends LitElement {
|
||||
fireEvent(this, "change", undefined, { bubbles: false });
|
||||
}
|
||||
|
||||
private _updateMarker(): void {
|
||||
private _radiusUpdated() {
|
||||
this._ignoreFitToMap = this.location;
|
||||
this.radius = (this._locationMarker as Circle).getRadius();
|
||||
fireEvent(this, "change", undefined, { bubbles: false });
|
||||
}
|
||||
|
||||
private _updateIcon() {
|
||||
if (!this.icon) {
|
||||
this._iconEl = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
// create icon
|
||||
let iconHTML = "";
|
||||
const el = document.createElement("ha-icon");
|
||||
el.setAttribute("icon", this.icon);
|
||||
iconHTML = el.outerHTML;
|
||||
|
||||
this._iconEl = this.Leaflet!.divIcon({
|
||||
html: iconHTML,
|
||||
iconSize: [24, 24],
|
||||
className: "light leaflet-edit-move",
|
||||
});
|
||||
this._setIcon();
|
||||
}
|
||||
|
||||
private _setIcon() {
|
||||
if (!this._locationMarker || !this._iconEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.radius) {
|
||||
(this._locationMarker as Marker).setIcon(this._iconEl);
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const moveMarker = this._locationMarker.editing._moveMarker;
|
||||
moveMarker.setIcon(this._iconEl);
|
||||
}
|
||||
|
||||
private _setupEdit() {
|
||||
// @ts-ignore
|
||||
this._locationMarker.editing.enable();
|
||||
// @ts-ignore
|
||||
const moveMarker = this._locationMarker.editing._moveMarker;
|
||||
// @ts-ignore
|
||||
const resizeMarker = this._locationMarker.editing._resizeMarkers[0];
|
||||
this._setIcon();
|
||||
moveMarker.addEventListener(
|
||||
"dragend",
|
||||
// @ts-ignore
|
||||
(ev: DragEndEvent) => this._locationUpdated(ev.target.getLatLng())
|
||||
);
|
||||
resizeMarker.addEventListener(
|
||||
"dragend",
|
||||
// @ts-ignore
|
||||
(ev: DragEndEvent) => this._radiusUpdated(ev)
|
||||
);
|
||||
}
|
||||
|
||||
private async _updateMarker(): Promise<void> {
|
||||
if (!this.location) {
|
||||
if (this._locationMarker) {
|
||||
this._locationMarker.remove();
|
||||
@@ -97,17 +187,41 @@ class LocationEditor extends LitElement {
|
||||
|
||||
if (this._locationMarker) {
|
||||
this._locationMarker.setLatLng(this.location);
|
||||
if (this.radius) {
|
||||
// @ts-ignore
|
||||
this._locationMarker.editing.disable();
|
||||
await nextRender();
|
||||
this._setupEdit();
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._locationMarker = this.Leaflet!.marker(this.location, {
|
||||
draggable: true,
|
||||
});
|
||||
this._locationMarker.addEventListener(
|
||||
"dragend",
|
||||
// @ts-ignore
|
||||
(ev: DragEndEvent) => this._updateLocation(ev.target.getLatLng())
|
||||
);
|
||||
this._leafletMap!.addLayer(this._locationMarker);
|
||||
|
||||
if (!this.radius) {
|
||||
this._locationMarker = this.Leaflet!.marker(this.location, {
|
||||
draggable: true,
|
||||
});
|
||||
this._setIcon();
|
||||
this._locationMarker.addEventListener(
|
||||
"dragend",
|
||||
// @ts-ignore
|
||||
(ev: DragEndEvent) => this._locationUpdated(ev.target.getLatLng())
|
||||
);
|
||||
this._leafletMap!.addLayer(this._locationMarker);
|
||||
} else {
|
||||
this._locationMarker = this.Leaflet!.circle(this.location, {
|
||||
color: "#FF9800",
|
||||
radius: this.radius,
|
||||
});
|
||||
this._leafletMap!.addLayer(this._locationMarker);
|
||||
this._setupEdit();
|
||||
}
|
||||
}
|
||||
|
||||
private _updateRadius(): void {
|
||||
if (!this._locationMarker || !this.radius) {
|
||||
return;
|
||||
}
|
||||
(this._locationMarker as Circle).setRadius(this.radius);
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
@@ -119,6 +233,13 @@ class LocationEditor extends LitElement {
|
||||
#map {
|
||||
height: 100%;
|
||||
}
|
||||
.leaflet-edit-move {
|
||||
cursor: move !important;
|
||||
}
|
||||
.leaflet-edit-resize {
|
||||
border-radius: 50%;
|
||||
cursor: nesw-resize !important;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user