Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new config options for map entity markers #17938

Merged
merged 3 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/components/map/ha-entity-marker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class HaEntityMarker extends LitElement {
protected render() {
return html`
<div
class="marker"
class="marker ${this.entityPicture ? "picture" : ""}"
style=${styleMap({ "border-color": this.entityColor })}
@click=${this._badgeTap}
>
Expand Down Expand Up @@ -45,7 +45,6 @@ class HaEntityMarker extends LitElement {
justify-content: center;
align-items: center;
box-sizing: border-box;
overflow: hidden;
width: 48px;
height: 48px;
font-size: var(--ha-marker-font-size, 1.5em);
Expand All @@ -54,6 +53,9 @@ class HaEntityMarker extends LitElement {
color: var(--primary-text-color);
background-color: var(--card-background-color);
}
.marker.picture {
overflow: hidden;
}
.entity-picture {
background-size: cover;
height: 100%;
Expand Down
51 changes: 33 additions & 18 deletions src/components/map/ha-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export interface HaMapPaths {
export interface HaMapEntity {
entity_id: string;
color: string;
label_mode?: "name" | "state";
name?: string;
focus?: boolean;
}

@customElement("ha-map")
Expand Down Expand Up @@ -71,6 +74,8 @@ export class HaMap extends ReactiveElement {

private _mapItems: Array<Marker | Circle> = [];

private _mapFocusItems: Array<Marker | Circle> = [];

private _mapZones: Array<Marker | Circle> = [];

private _mapPaths: Array<Polyline | CircleMarker> = [];
Expand Down Expand Up @@ -168,7 +173,7 @@ export class HaMap extends ReactiveElement {
return;
}

if (!this._mapItems.length && !this.layers?.length) {
if (!this._mapFocusItems.length && !this.layers?.length) {
this.leafletMap.setView(
new this.Leaflet.LatLng(
this.hass.config.latitude,
Expand All @@ -180,7 +185,9 @@ export class HaMap extends ReactiveElement {
}

let bounds = this.Leaflet.latLngBounds(
this._mapItems ? this._mapItems.map((item) => item.getLatLng()) : []
this._mapFocusItems
? this._mapFocusItems.map((item) => item.getLatLng())
: []
);

if (this.fitZones) {
Expand Down Expand Up @@ -324,6 +331,7 @@ export class HaMap extends ReactiveElement {
if (this._mapItems.length) {
this._mapItems.forEach((marker) => marker.remove());
this._mapItems = [];
this._mapFocusItems = [];
}

if (this._mapZones.length) {
Expand Down Expand Up @@ -353,7 +361,8 @@ export class HaMap extends ReactiveElement {
if (!stateObj) {
continue;
}
const title = computeStateName(stateObj);
const customTitle = typeof entity !== "string" ? entity.name : undefined;
const title = customTitle ?? computeStateName(stateObj);
const {
latitude,
longitude,
Expand Down Expand Up @@ -413,17 +422,20 @@ export class HaMap extends ReactiveElement {

// DRAW ENTITY
// create icon
const entityName = title
.split(" ")
.map((part) => part[0])
.join("")
.substr(0, 3);
const entityName =
typeof entity !== "string" && entity.label_mode === "state"
? this.hass.formatEntityState(stateObj)
: customTitle ??
title
.split(" ")
.map((part) => part[0])
.join("")
.substr(0, 3);

// create marker with the icon
this._mapItems.push(
Leaflet.marker([latitude, longitude], {
icon: Leaflet.divIcon({
html: `
const marker = Leaflet.marker([latitude, longitude], {
icon: Leaflet.divIcon({
html: `
<ha-entity-marker
entity-id="${getEntityId(entity)}"
entity-name="${entityName}"
Expand All @@ -437,12 +449,15 @@ export class HaMap extends ReactiveElement {
}
></ha-entity-marker>
`,
iconSize: [48, 48],
className: "",
}),
title: computeStateName(stateObj),
})
);
iconSize: [48, 48],
className: "",
}),
title: title,
});
this._mapItems.push(marker);
if (typeof entity === "string" || entity.focus !== false) {
this._mapFocusItems.push(marker);
}

// create circle around if entity has accuracy
if (gpsAccuracy) {
Expand Down
42 changes: 25 additions & 17 deletions src/panels/lovelace/cards/hui-map-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ import { MapCardConfig } from "./types";
export const DEFAULT_HOURS_TO_SHOW = 0;
export const DEFAULT_ZOOM = 14;

interface MapEntityConfig extends EntityConfig {
label_mode?: "state" | "name";
focus?: boolean;
}

@customElement("hui-map-card")
class HuiMapCard extends LitElement implements LovelaceCard {
@property({ attribute: false }) public hass!: HomeAssistant;
Expand All @@ -63,7 +68,7 @@ class HuiMapCard extends LitElement implements LovelaceCard {
@query("ha-map")
private _map?: HaMap;

private _configEntities?: string[];
private _configEntities?: MapEntityConfig[];

private _colorDict: Record<string, string> = {};

Expand Down Expand Up @@ -94,11 +99,9 @@ class HuiMapCard extends LitElement implements LovelaceCard {
}

this._config = config;
this._configEntities = (
config.entities
? processConfigEntities<EntityConfig>(config.entities)
: []
).map((entity) => entity.entity);
this._configEntities = config.entities
? processConfigEntities<MapEntityConfig>(config.entities)
: [];
}

public getCardSize(): number {
Expand Down Expand Up @@ -238,7 +241,7 @@ class HuiMapCard extends LitElement implements LovelaceCard {
this._stateHistory = combinedHistory;
},
this._config!.hours_to_show! ?? DEFAULT_HOURS_TO_SHOW,
this._configEntities!,
(this._configEntities || []).map((entity) => entity.entity)!,
false,
false,
false
Expand Down Expand Up @@ -309,16 +312,14 @@ class HuiMapCard extends LitElement implements LovelaceCard {
(
states: HassEntities,
config: MapCardConfig,
configEntities?: string[]
configEntities?: MapEntityConfig[]
) => {
if (!states || !config) {
return undefined;
}

let entities = configEntities || [];

const geoEntities: string[] = [];
if (config.geo_location_sources) {
const geoEntities: string[] = [];
// Calculate visible geo location sources
const includesAll = config.geo_location_sources.includes("all");
for (const stateObj of Object.values(states)) {
Expand All @@ -330,14 +331,21 @@ class HuiMapCard extends LitElement implements LovelaceCard {
geoEntities.push(stateObj.entity_id);
}
}

entities = [...entities, ...geoEntities];
}

return entities.map((entity) => ({
entity_id: entity,
color: this._getColor(entity),
}));
return [
...(configEntities || []).map((entityConf) => ({
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),
})),
];
}
);

Expand Down
14 changes: 12 additions & 2 deletions src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
object,
optional,
string,
union,
} from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import { hasLocation } from "../../../../common/entity/has_location";
Expand All @@ -25,18 +26,27 @@ import { EntityConfig } from "../../entity-rows/types";
import { LovelaceCardEditor } from "../../types";
import { processEditorEntities } from "../process-editor-entities";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { entitiesConfigStruct } from "../structs/entities-struct";
import { EntitiesEditorEvent } from "../types";
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(
baseLovelaceCardConfig,
object({
title: optional(string()),
aspect_ratio: optional(string()),
default_zoom: optional(number()),
dark_mode: optional(boolean()),
entities: array(entitiesConfigStruct),
entities: array(mapEntitiesConfigStruct),
hours_to_show: optional(number()),
geo_location_sources: optional(array(string())),
auto_fit: optional(boolean()),
Expand Down