diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 1bcfa3871f..edccd2d22c 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -5,10 +5,18 @@ import type { ChartOptions, TooltipModel, } from "chart.js"; -import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { + css, + CSSResultGroup, + html, + nothing, + LitElement, + PropertyValues, +} from "lit"; import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import { styleMap } from "lit/directives/style-map"; +import { fireEvent } from "../../common/dom/fire_event"; import { clamp } from "../../common/number/clamp"; import { HomeAssistant } from "../../types"; import { debounce } from "../../common/util/debounce"; @@ -27,6 +35,11 @@ interface Tooltip left: string; } +export interface ChartDatasetExtra { + show_legend?: boolean; + legend_label?: string; +} + @customElement("ha-chart-base") export class HaChartBase extends LitElement { public chart?: Chart; @@ -38,6 +51,8 @@ export class HaChartBase extends LitElement { @property({ attribute: false }) public data: ChartData = { datasets: [] }; + @property({ attribute: false }) public extraData?: ChartDatasetExtra[]; + @property({ attribute: false }) public options?: ChartOptions; @property({ attribute: false }) public plugins?: any[]; @@ -46,6 +61,8 @@ export class HaChartBase extends LitElement { @property({ type: Number }) public paddingYAxis = 0; + @property({ type: Boolean }) public externalHidden = false; + @state() private _chartHeight?: number; @state() private _tooltip?: Tooltip; @@ -148,6 +165,19 @@ export class HaChartBase extends LitElement { } } + if (changedProps.has("data")) { + if (this.externalHidden) { + this._hiddenDatasets = new Set(); + if (this.data?.datasets) { + this.data.datasets.forEach((dataset, index) => { + if (dataset.hidden) { + this._hiddenDatasets.add(index); + } + }); + } + } + } + if (!this.hasUpdated || !this.chart) { return; } @@ -157,7 +187,7 @@ export class HaChartBase extends LitElement { return; } if (changedProps.has("data")) { - if (this._hiddenDatasets.size) { + if (this._hiddenDatasets.size && !this.externalHidden) { this.data.datasets.forEach((dataset, index) => { dataset.hidden = this._hiddenDatasets.has(index); }); @@ -175,25 +205,30 @@ export class HaChartBase extends LitElement { ${this.options?.plugins?.legend?.display === true ? html`
-
${dataset.label}
- ` + .title=${this.extraData?.[index]?.legend_label ?? + dataset.label} + > +
+
+ ${this.extraData?.[index]?.legend_label ?? + dataset.label} +
+ ` )} ` @@ -339,9 +374,19 @@ export class HaChartBase extends LitElement { if (this.chart.isDatasetVisible(index)) { this.chart.setDatasetVisibility(index, false); this._hiddenDatasets.add(index); + if (this.externalHidden) { + fireEvent(this, "dataset-hidden", { + index, + }); + } } else { this.chart.setDatasetVisibility(index, true); this._hiddenDatasets.delete(index); + if (this.externalHidden) { + fireEvent(this, "dataset-unhidden", { + index, + }); + } } this.chart.update("none"); this.requestUpdate("_hiddenDatasets"); @@ -486,4 +531,8 @@ declare global { interface HTMLElementTagNameMap { "ha-chart-base": HaChartBase; } + interface HASSDomEvents { + "dataset-hidden": { index: number }; + "dataset-unhidden": { index: number }; + } } diff --git a/src/components/chart/statistics-chart.ts b/src/components/chart/statistics-chart.ts index 0e2fa2a9f5..0c5597878c 100644 --- a/src/components/chart/statistics-chart.ts +++ b/src/components/chart/statistics-chart.ts @@ -32,7 +32,11 @@ import { } from "../../data/recorder"; import type { HomeAssistant } from "../../types"; import "./ha-chart-base"; -import type { ChartResizeOptions, HaChartBase } from "./ha-chart-base"; +import type { + ChartResizeOptions, + ChartDatasetExtra, + HaChartBase, +} from "./ha-chart-base"; export const supportedStatTypeMap: Record = { mean: "mean", @@ -79,10 +83,14 @@ export class StatisticsChart extends LitElement { @state() private _chartData: ChartData = { datasets: [] }; + @state() private _chartDatasetExtra: ChartDatasetExtra[] = []; + @state() private _statisticIds: string[] = []; @state() private _chartOptions?: ChartOptions; + @state() private _hiddenStats = new Set(); + @query("ha-chart-base") private _chart?: HaChartBase; private _computedStyle?: CSSStyleDeclaration; @@ -96,6 +104,9 @@ export class StatisticsChart extends LitElement { } public willUpdate(changedProps: PropertyValues) { + if (changedProps.has("legendMode")) { + this._hiddenStats.clear(); + } if ( !this.hasUpdated || changedProps.has("unit") || @@ -110,7 +121,8 @@ export class StatisticsChart extends LitElement { changedProps.has("statisticsData") || changedProps.has("statTypes") || changedProps.has("chartType") || - changedProps.has("hideLegend") + changedProps.has("hideLegend") || + changedProps.has("_hiddenStats") ) { this._generateData(); } @@ -145,14 +157,30 @@ export class StatisticsChart extends LitElement { return html` `; } + private _datasetHidden(ev) { + ev.stopPropagation(); + this._hiddenStats.add(this._statisticIds[ev.detail.index]); + this.requestUpdate("_hiddenStats"); + } + + private _datasetUnhidden(ev) { + ev.stopPropagation(); + this._hiddenStats.delete(this._statisticIds[ev.detail.index]); + this.requestUpdate("_hiddenStats"); + } + private _createOptions(unit?: string) { this._chartOptions = { parsing: false, @@ -274,6 +302,7 @@ export class StatisticsChart extends LitElement { let colorIndex = 0; const statisticsData = Object.entries(this.statisticsData); const totalDataSets: ChartDataset<"line">[] = []; + const totalDatasetExtras: ChartDatasetExtra[] = []; const statisticIds: string[] = []; let endTime: Date; @@ -324,6 +353,7 @@ export class StatisticsChart extends LitElement { // The datasets for the current statistic const statDataSets: ChartDataset<"line">[] = []; + const statDatasetExtras: ChartDatasetExtra[] = []; const pushData = ( start: Date, @@ -384,9 +414,20 @@ export class StatisticsChart extends LitElement { }) : this.statTypes; + let displayed_legend = false; sortedTypes.forEach((type) => { if (statisticsHaveType(stats, type)) { const band = drawBands && (type === "min" || type === "max"); + if (!this.hideLegend) { + const show_legend = hasMean + ? type === "mean" + : displayed_legend === false; + statDatasetExtras.push({ + legend_label: name, + show_legend, + }); + displayed_legend = displayed_legend || show_legend; + } statTypes.push(type); statDataSets.push({ label: name @@ -408,6 +449,9 @@ export class StatisticsChart extends LitElement { band && hasMean ? color + (this.hideLegend ? "00" : "7F") : color, backgroundColor: band ? color + "3F" : color + "7F", pointRadius: 0, + hidden: !this.hideLegend + ? this._hiddenStats.has(statistic_id) + : false, data: [], // @ts-ignore unit: meta?.unit_of_measurement, @@ -446,6 +490,7 @@ export class StatisticsChart extends LitElement { // Concat two arrays Array.prototype.push.apply(totalDataSets, statDataSets); + Array.prototype.push.apply(totalDatasetExtras, statDatasetExtras); }); if (unit) { @@ -455,6 +500,7 @@ export class StatisticsChart extends LitElement { this._chartData = { datasets: totalDataSets, }; + this._chartDatasetExtra = totalDatasetExtras; this._statisticIds = statisticIds; }