mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 03:06:41 +00:00
Fix for charts with identically named entities (#26166)
* Fix for charts with identically named entities * lint * type fix
This commit is contained in:
parent
aee9e4b0a5
commit
72a12a4ba4
@ -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<string, any>;
|
||||
}[];
|
||||
};
|
||||
|
||||
@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<string, any> = {};
|
||||
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`<li
|
||||
.name=${name}
|
||||
.id=${id}
|
||||
@click=${this._legendClick}
|
||||
class=${classMap({ hidden: this._hiddenDatasets.has(name) })}
|
||||
class=${classMap({ hidden: this._hiddenDatasets.has(id) })}
|
||||
.title=${name}
|
||||
>
|
||||
<div
|
||||
@ -645,7 +660,7 @@ export class HaChartBase extends LitElement {
|
||||
| YAXisOption
|
||||
| undefined;
|
||||
const series = ensureArray(this.data).map((s) => {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<StatisticType, StatisticType> = {
|
||||
@ -96,7 +97,7 @@ export class StatisticsChart extends LitElement {
|
||||
|
||||
@state() private _chartData: (LineSeriesOption | BarSeriesOption)[] = [];
|
||||
|
||||
@state() private _legendData: string[] = [];
|
||||
@state() private _legendData: NonNullable<CustomLegendOption["data"]> = [];
|
||||
|
||||
@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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user