diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 7a7fa68567..09d3bd0d44 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -35,6 +35,15 @@ const LEGEND_OVERFLOW_LIMIT = 10; const LEGEND_OVERFLOW_LIMIT_MOBILE = 6; const DOUBLE_TAP_TIME = 300; +export type CustomLegendOption = ECOption["legend"] & { + type: "custom"; + data?: { + id?: string; + name: string; + itemStyle?: Record; + }[]; +}; + @customElement("ha-chart-base") export class HaChartBase extends LitElement { public chart?: EChartsType; @@ -219,16 +228,18 @@ export class HaChartBase extends LitElement { if (!this.options?.legend || !this.data) { return nothing; } - const legend = ensureArray(this.options.legend)[0] as LegendComponentOption; - if (!legend.show || legend.type !== "custom") { + const legend = ensureArray(this.options.legend).find( + (l) => l.show && l.type === "custom" + ) as CustomLegendOption | undefined; + if (!legend) { return nothing; } const datasets = ensureArray(this.data); - const items: LegendComponentOption["data"] = + const items = legend.data || - ((datasets + datasets .filter((d) => (d.data as any[])?.length && (d.id || d.name)) - .map((d) => d.name ?? d.id) || []) as string[]); + .map((d) => ({ id: d.id, name: d.name })); const isMobile = window.matchMedia( "all and (max-width: 450px), all and (max-height: 500px)" @@ -249,25 +260,29 @@ export class HaChartBase extends LitElement { } let itemStyle: Record = {}; let name = ""; + let id = ""; if (typeof item === "string") { name = item; - const dataset = datasets.find( - (d) => d.id === item || d.name === item - ); - itemStyle = { - color: dataset?.color as string, - ...(dataset?.itemStyle as { borderColor?: string }), - }; + id = item; } else { name = item.name ?? ""; + id = item.id ?? name; itemStyle = item.itemStyle ?? {}; } + const dataset = + datasets.find((d) => d.id === id) ?? + datasets.find((d) => d.name === id); + itemStyle = { + color: dataset?.color as string, + ...(dataset?.itemStyle as { borderColor?: string }), + itemStyle, + }; const color = itemStyle?.color as string; const borderColor = itemStyle?.borderColor as string; return html`
  • { - const data = this._hiddenDatasets.has(String(s.name ?? s.id)) + const data = this._hiddenDatasets.has(String(s.id ?? s.name)) ? undefined : s.data; if (data && s.type === "line") { @@ -740,13 +755,13 @@ export class HaChartBase extends LitElement { if (!this.chart) { return; } - const name = ev.currentTarget?.name; - if (this._hiddenDatasets.has(name)) { - this._hiddenDatasets.delete(name); - fireEvent(this, "dataset-unhidden", { name }); + const id = ev.currentTarget?.id; + if (this._hiddenDatasets.has(id)) { + this._hiddenDatasets.delete(id); + fireEvent(this, "dataset-unhidden", { id }); } else { - this._hiddenDatasets.add(name); - fireEvent(this, "dataset-hidden", { name }); + this._hiddenDatasets.add(id); + fireEvent(this, "dataset-hidden", { id }); } this.requestUpdate("_hiddenDatasets"); } @@ -881,8 +896,8 @@ declare global { "ha-chart-base": HaChartBase; } interface HASSDomEvents { - "dataset-hidden": { name: string }; - "dataset-unhidden": { name: string }; + "dataset-hidden": { id: string }; + "dataset-unhidden": { id: string }; "chart-click": ECElementEvent; } } diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts index 362d7ab579..e95d67ef07 100644 --- a/src/components/chart/state-history-chart-line.ts +++ b/src/components/chart/state-history-chart-line.ts @@ -111,7 +111,7 @@ export class StateHistoryChartLine extends LitElement { this._chartData.forEach((dataset, index) => { if ( dataset.tooltip?.show === false || - this._hiddenStats.has(dataset.name as string) + this._hiddenStats.has(dataset.id as string) ) return; const param = params.find( @@ -185,11 +185,11 @@ export class StateHistoryChartLine extends LitElement { }; private _datasetHidden(ev: CustomEvent) { - this._hiddenStats.add(ev.detail.name); + this._hiddenStats.add(ev.detail.id); } private _datasetUnhidden(ev: CustomEvent) { - this._hiddenStats.delete(ev.detail.name); + this._hiddenStats.delete(ev.detail.id); } public willUpdate(changedProps: PropertyValues) { diff --git a/src/components/chart/statistics-chart.ts b/src/components/chart/statistics-chart.ts index 596eb92b7d..341decfd3d 100644 --- a/src/components/chart/statistics-chart.ts +++ b/src/components/chart/statistics-chart.ts @@ -31,6 +31,7 @@ import { } from "../../data/recorder"; import type { ECOption } from "../../resources/echarts"; import type { HomeAssistant } from "../../types"; +import type { CustomLegendOption } from "./ha-chart-base"; import "./ha-chart-base"; export const supportedStatTypeMap: Record = { @@ -96,7 +97,7 @@ export class StatisticsChart extends LitElement { @state() private _chartData: (LineSeriesOption | BarSeriesOption)[] = []; - @state() private _legendData: string[] = []; + @state() private _legendData: NonNullable = []; @state() private _statisticIds: string[] = []; @@ -183,12 +184,12 @@ export class StatisticsChart extends LitElement { } private _datasetHidden(ev: CustomEvent) { - this._hiddenStats.add(ev.detail.name); + this._hiddenStats.add(ev.detail.id); this.requestUpdate("_hiddenStats"); } private _datasetUnhidden(ev: CustomEvent) { - this._hiddenStats.delete(ev.detail.name); + this._hiddenStats.delete(ev.detail.id); this.requestUpdate("_hiddenStats"); } @@ -199,8 +200,8 @@ export class StatisticsChart extends LitElement { : ""; return params .map((param, index: number) => { - if (rendered[param.seriesName]) return ""; - rendered[param.seriesName] = true; + if (rendered[param.seriesIndex]) return ""; + rendered[param.seriesIndex] = true; const statisticId = this._statisticIds[param.seriesIndex]; const stateObj = this.hass.states[statisticId]; @@ -367,6 +368,7 @@ export class StatisticsChart extends LitElement { const statisticsData = Object.entries(this.statisticsData); const totalDataSets: typeof this._chartData = []; const legendData: { + id: string; name: string; color?: ZRColor; borderColor?: ZRColor; @@ -540,6 +542,7 @@ export class StatisticsChart extends LitElement { : displayedLegend === false; if (showLegend) { statLegendData.push({ + id: statistic_id, name, color: series.color as ZRColor, borderColor: series.itemStyle?.borderColor, @@ -584,7 +587,7 @@ export class StatisticsChart extends LitElement { } dataValues.push(val); }); - if (!this._hiddenStats.has(name)) { + if (!this._hiddenStats.has(statistic_id)) { pushData(startDate, new Date(stat.end), dataValues); } }); @@ -598,10 +601,10 @@ export class StatisticsChart extends LitElement { this.unit = unit; } - legendData.forEach(({ name, color, borderColor }) => { + legendData.forEach(({ id, name, color, borderColor }) => { // Add an empty series for the legend totalDataSets.push({ - id: name + "-legend", + id: id, name: name, color, itemStyle: { @@ -616,7 +619,7 @@ export class StatisticsChart extends LitElement { this._chartData = totalDataSets; if (legendData.length !== this._legendData.length) { // only update the legend if it has changed or it will trigger options update - this._legendData = legendData.map(({ name }) => name); + this._legendData = legendData.map(({ id, name }) => ({ id, name })); } this._statisticIds = statisticIds; } diff --git a/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts index d3d4839431..64ba5fd67b 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts @@ -6,7 +6,6 @@ import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import type { BarSeriesOption } from "echarts/charts"; -import type { LegendComponentOption } from "echarts/components"; import { getGraphColorByIndex } from "../../../../common/color/colors"; import { getEnergyColor } from "./common/color"; import "../../../../components/ha-card"; @@ -39,6 +38,7 @@ import { import { storage } from "../../../../common/decorators/storage"; import type { ECOption } from "../../../../resources/echarts"; import { formatNumber } from "../../../../common/number/format_number"; +import type { CustomLegendOption } from "../../../../components/chart/ha-chart-base"; const UNIT = "kWh"; @@ -55,7 +55,7 @@ export class HuiEnergyDevicesDetailGraphCard @state() private _data?: EnergyData; - @state() private _legendData?: LegendComponentOption["data"]; + @state() private _legendData?: CustomLegendOption["data"]; @state() private _start = startOfToday(); @@ -149,12 +149,12 @@ export class HuiEnergyDevicesDetailGraphCard ); private _datasetHidden(ev) { - this._hiddenStats = [...this._hiddenStats, ev.detail.name]; + this._hiddenStats = [...this._hiddenStats, ev.detail.id]; } private _datasetUnhidden(ev) { this._hiddenStats = this._hiddenStats.filter( - (stat) => stat !== ev.detail.name + (stat) => stat !== ev.detail.id ); } @@ -314,6 +314,7 @@ export class HuiEnergyDevicesDetailGraphCard datasets.push(...processedData); this._legendData = processedData.map((d) => ({ + id: d.id as string, name: d.name as string, itemStyle: { color: d.color as string, @@ -330,6 +331,7 @@ export class HuiEnergyDevicesDetailGraphCard ); datasets.push(untrackedData); this._legendData.push({ + id: untrackedData.id as string, name: untrackedData.name as string, itemStyle: { color: untrackedData.color as string,