mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add new config options for map entity markers (#17938)
This commit is contained in:
parent
6b33b4e656
commit
579050bfc7
@ -15,7 +15,7 @@ class HaEntityMarker extends LitElement {
|
|||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
class="marker"
|
class="marker ${this.entityPicture ? "picture" : ""}"
|
||||||
style=${styleMap({ "border-color": this.entityColor })}
|
style=${styleMap({ "border-color": this.entityColor })}
|
||||||
@click=${this._badgeTap}
|
@click=${this._badgeTap}
|
||||||
>
|
>
|
||||||
@ -45,7 +45,6 @@ class HaEntityMarker extends LitElement {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
font-size: var(--ha-marker-font-size, 1.5em);
|
font-size: var(--ha-marker-font-size, 1.5em);
|
||||||
@ -54,6 +53,9 @@ class HaEntityMarker extends LitElement {
|
|||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
background-color: var(--card-background-color);
|
background-color: var(--card-background-color);
|
||||||
}
|
}
|
||||||
|
.marker.picture {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
.entity-picture {
|
.entity-picture {
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -37,6 +37,9 @@ export interface HaMapPaths {
|
|||||||
export interface HaMapEntity {
|
export interface HaMapEntity {
|
||||||
entity_id: string;
|
entity_id: string;
|
||||||
color: string;
|
color: string;
|
||||||
|
label_mode?: "name" | "state";
|
||||||
|
name?: string;
|
||||||
|
focus?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("ha-map")
|
@customElement("ha-map")
|
||||||
@ -71,6 +74,8 @@ export class HaMap extends ReactiveElement {
|
|||||||
|
|
||||||
private _mapItems: Array<Marker | Circle> = [];
|
private _mapItems: Array<Marker | Circle> = [];
|
||||||
|
|
||||||
|
private _mapFocusItems: Array<Marker | Circle> = [];
|
||||||
|
|
||||||
private _mapZones: Array<Marker | Circle> = [];
|
private _mapZones: Array<Marker | Circle> = [];
|
||||||
|
|
||||||
private _mapPaths: Array<Polyline | CircleMarker> = [];
|
private _mapPaths: Array<Polyline | CircleMarker> = [];
|
||||||
@ -168,7 +173,7 @@ export class HaMap extends ReactiveElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._mapItems.length && !this.layers?.length) {
|
if (!this._mapFocusItems.length && !this.layers?.length) {
|
||||||
this.leafletMap.setView(
|
this.leafletMap.setView(
|
||||||
new this.Leaflet.LatLng(
|
new this.Leaflet.LatLng(
|
||||||
this.hass.config.latitude,
|
this.hass.config.latitude,
|
||||||
@ -180,7 +185,9 @@ export class HaMap extends ReactiveElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let bounds = this.Leaflet.latLngBounds(
|
let bounds = this.Leaflet.latLngBounds(
|
||||||
this._mapItems ? this._mapItems.map((item) => item.getLatLng()) : []
|
this._mapFocusItems
|
||||||
|
? this._mapFocusItems.map((item) => item.getLatLng())
|
||||||
|
: []
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.fitZones) {
|
if (this.fitZones) {
|
||||||
@ -324,6 +331,7 @@ export class HaMap extends ReactiveElement {
|
|||||||
if (this._mapItems.length) {
|
if (this._mapItems.length) {
|
||||||
this._mapItems.forEach((marker) => marker.remove());
|
this._mapItems.forEach((marker) => marker.remove());
|
||||||
this._mapItems = [];
|
this._mapItems = [];
|
||||||
|
this._mapFocusItems = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._mapZones.length) {
|
if (this._mapZones.length) {
|
||||||
@ -353,7 +361,8 @@ export class HaMap extends ReactiveElement {
|
|||||||
if (!stateObj) {
|
if (!stateObj) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const title = computeStateName(stateObj);
|
const customTitle = typeof entity !== "string" ? entity.name : undefined;
|
||||||
|
const title = customTitle ?? computeStateName(stateObj);
|
||||||
const {
|
const {
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
@ -413,17 +422,20 @@ export class HaMap extends ReactiveElement {
|
|||||||
|
|
||||||
// DRAW ENTITY
|
// DRAW ENTITY
|
||||||
// create icon
|
// create icon
|
||||||
const entityName = title
|
const entityName =
|
||||||
.split(" ")
|
typeof entity !== "string" && entity.label_mode === "state"
|
||||||
.map((part) => part[0])
|
? this.hass.formatEntityState(stateObj)
|
||||||
.join("")
|
: customTitle ??
|
||||||
.substr(0, 3);
|
title
|
||||||
|
.split(" ")
|
||||||
|
.map((part) => part[0])
|
||||||
|
.join("")
|
||||||
|
.substr(0, 3);
|
||||||
|
|
||||||
// create marker with the icon
|
// create marker with the icon
|
||||||
this._mapItems.push(
|
const marker = Leaflet.marker([latitude, longitude], {
|
||||||
Leaflet.marker([latitude, longitude], {
|
icon: Leaflet.divIcon({
|
||||||
icon: Leaflet.divIcon({
|
html: `
|
||||||
html: `
|
|
||||||
<ha-entity-marker
|
<ha-entity-marker
|
||||||
entity-id="${getEntityId(entity)}"
|
entity-id="${getEntityId(entity)}"
|
||||||
entity-name="${entityName}"
|
entity-name="${entityName}"
|
||||||
@ -437,12 +449,15 @@ export class HaMap extends ReactiveElement {
|
|||||||
}
|
}
|
||||||
></ha-entity-marker>
|
></ha-entity-marker>
|
||||||
`,
|
`,
|
||||||
iconSize: [48, 48],
|
iconSize: [48, 48],
|
||||||
className: "",
|
className: "",
|
||||||
}),
|
}),
|
||||||
title: computeStateName(stateObj),
|
title: title,
|
||||||
})
|
});
|
||||||
);
|
this._mapItems.push(marker);
|
||||||
|
if (typeof entity === "string" || entity.focus !== false) {
|
||||||
|
this._mapFocusItems.push(marker);
|
||||||
|
}
|
||||||
|
|
||||||
// create circle around if entity has accuracy
|
// create circle around if entity has accuracy
|
||||||
if (gpsAccuracy) {
|
if (gpsAccuracy) {
|
||||||
|
@ -48,6 +48,11 @@ import { MapCardConfig } from "./types";
|
|||||||
export const DEFAULT_HOURS_TO_SHOW = 0;
|
export const DEFAULT_HOURS_TO_SHOW = 0;
|
||||||
export const DEFAULT_ZOOM = 14;
|
export const DEFAULT_ZOOM = 14;
|
||||||
|
|
||||||
|
interface MapEntityConfig extends EntityConfig {
|
||||||
|
label_mode?: "state" | "name";
|
||||||
|
focus?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("hui-map-card")
|
@customElement("hui-map-card")
|
||||||
class HuiMapCard extends LitElement implements LovelaceCard {
|
class HuiMapCard extends LitElement implements LovelaceCard {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -63,7 +68,7 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
|||||||
@query("ha-map")
|
@query("ha-map")
|
||||||
private _map?: HaMap;
|
private _map?: HaMap;
|
||||||
|
|
||||||
private _configEntities?: string[];
|
private _configEntities?: MapEntityConfig[];
|
||||||
|
|
||||||
private _colorDict: Record<string, string> = {};
|
private _colorDict: Record<string, string> = {};
|
||||||
|
|
||||||
@ -94,11 +99,9 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._config = config;
|
this._config = config;
|
||||||
this._configEntities = (
|
this._configEntities = config.entities
|
||||||
config.entities
|
? processConfigEntities<MapEntityConfig>(config.entities)
|
||||||
? processConfigEntities<EntityConfig>(config.entities)
|
: [];
|
||||||
: []
|
|
||||||
).map((entity) => entity.entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCardSize(): number {
|
public getCardSize(): number {
|
||||||
@ -238,7 +241,7 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
|||||||
this._stateHistory = combinedHistory;
|
this._stateHistory = combinedHistory;
|
||||||
},
|
},
|
||||||
this._config!.hours_to_show! ?? DEFAULT_HOURS_TO_SHOW,
|
this._config!.hours_to_show! ?? DEFAULT_HOURS_TO_SHOW,
|
||||||
this._configEntities!,
|
(this._configEntities || []).map((entity) => entity.entity)!,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false
|
false
|
||||||
@ -309,16 +312,14 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
|||||||
(
|
(
|
||||||
states: HassEntities,
|
states: HassEntities,
|
||||||
config: MapCardConfig,
|
config: MapCardConfig,
|
||||||
configEntities?: string[]
|
configEntities?: MapEntityConfig[]
|
||||||
) => {
|
) => {
|
||||||
if (!states || !config) {
|
if (!states || !config) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entities = configEntities || [];
|
const geoEntities: string[] = [];
|
||||||
|
|
||||||
if (config.geo_location_sources) {
|
if (config.geo_location_sources) {
|
||||||
const geoEntities: string[] = [];
|
|
||||||
// Calculate visible geo location sources
|
// Calculate visible geo location sources
|
||||||
const includesAll = config.geo_location_sources.includes("all");
|
const includesAll = config.geo_location_sources.includes("all");
|
||||||
for (const stateObj of Object.values(states)) {
|
for (const stateObj of Object.values(states)) {
|
||||||
@ -330,14 +331,21 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
|||||||
geoEntities.push(stateObj.entity_id);
|
geoEntities.push(stateObj.entity_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entities = [...entities, ...geoEntities];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return entities.map((entity) => ({
|
return [
|
||||||
entity_id: entity,
|
...(configEntities || []).map((entityConf) => ({
|
||||||
color: this._getColor(entity),
|
entity_id: entityConf.entity,
|
||||||
}));
|
color: this._getColor(entityConf.entity),
|
||||||
|
label_mode: entityConf.label_mode,
|
||||||
|
focus: entityConf.focus,
|
||||||
|
name: entityConf.name,
|
||||||
|
})),
|
||||||
|
...geoEntities.map((entity) => ({
|
||||||
|
entity_id: entity,
|
||||||
|
color: this._getColor(entity),
|
||||||
|
})),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
object,
|
object,
|
||||||
optional,
|
optional,
|
||||||
string,
|
string,
|
||||||
|
union,
|
||||||
} from "superstruct";
|
} from "superstruct";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { hasLocation } from "../../../../common/entity/has_location";
|
import { hasLocation } from "../../../../common/entity/has_location";
|
||||||
@ -25,10 +26,19 @@ import { EntityConfig } from "../../entity-rows/types";
|
|||||||
import { LovelaceCardEditor } from "../../types";
|
import { LovelaceCardEditor } from "../../types";
|
||||||
import { processEditorEntities } from "../process-editor-entities";
|
import { processEditorEntities } from "../process-editor-entities";
|
||||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||||
import { entitiesConfigStruct } from "../structs/entities-struct";
|
|
||||||
import { EntitiesEditorEvent } from "../types";
|
import { EntitiesEditorEvent } from "../types";
|
||||||
import { configElementStyle } from "./config-elements-style";
|
import { configElementStyle } from "./config-elements-style";
|
||||||
|
|
||||||
|
export const mapEntitiesConfigStruct = union([
|
||||||
|
object({
|
||||||
|
entity: string(),
|
||||||
|
label_mode: optional(string()),
|
||||||
|
focus: optional(boolean()),
|
||||||
|
name: optional(string()),
|
||||||
|
}),
|
||||||
|
string(),
|
||||||
|
]);
|
||||||
|
|
||||||
const cardConfigStruct = assign(
|
const cardConfigStruct = assign(
|
||||||
baseLovelaceCardConfig,
|
baseLovelaceCardConfig,
|
||||||
object({
|
object({
|
||||||
@ -36,7 +46,7 @@ const cardConfigStruct = assign(
|
|||||||
aspect_ratio: optional(string()),
|
aspect_ratio: optional(string()),
|
||||||
default_zoom: optional(number()),
|
default_zoom: optional(number()),
|
||||||
dark_mode: optional(boolean()),
|
dark_mode: optional(boolean()),
|
||||||
entities: array(entitiesConfigStruct),
|
entities: array(mapEntitiesConfigStruct),
|
||||||
hours_to_show: optional(number()),
|
hours_to_show: optional(number()),
|
||||||
geo_location_sources: optional(array(string())),
|
geo_location_sources: optional(array(string())),
|
||||||
auto_fit: optional(boolean()),
|
auto_fit: optional(boolean()),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user