From a297077b4e75b74a6decbb03b623e898a46ede5e Mon Sep 17 00:00:00 2001 From: Mario Hros <966992+k3a@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:13:02 +0200 Subject: [PATCH] Handle clicking on a label of a timeline history graph card and display more info for the displayed entity --- src/components/chart/ha-chart-base.ts | 66 ++++++++++++++++++++ src/components/chart/state-history-charts.ts | 14 +++++ 2 files changed, 80 insertions(+) diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 60d0d039f8d5..01c260ffdbf6 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -12,6 +12,7 @@ import { styleMap } from "lit/directives/style-map"; import { clamp } from "../../common/number/clamp"; import { computeRTL } from "../../common/util/compute_rtl"; import { HomeAssistant } from "../../types"; +import { fireEvent } from "../../common/dom/fire_event"; export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000; @@ -271,6 +272,46 @@ export class HaChartBase extends LitElement { }; } + private _findLabel(evt): { label: string; index: number } | null { + let res: { label: string; index: number } | null = null; + + const scales = this.chart?.scales ?? []; + + const scaleDetails = Object.values(scales).map((s: any) => ({ + scaleId: s.id, + labels: s?._labelItems?.map( + (e, i) => + ({ + x: e.options.translation[0] - (s?._labelSizes?.widths[i] ?? 0), + x2: e.options.translation[0] + (s?._labelSizes?.widths[i] ?? 0) / 2, + y: e.options.translation[1] - (s?._labelSizes?.heights[i] ?? 0) / 2, + y2: + e.options.translation[1] + (s?._labelSizes?.heights[i] ?? 0) / 2, + label: e.label, + index: i, + }) ?? [] + ), + })); + + scaleDetails.forEach((l) => { + l.labels.forEach((label, index) => { + if ( + evt.x > label.x && + evt.x < label.x2 && + evt.y > label.y && + evt.y < label.y2 + ) { + res = { + label: label.label, + index, + }; + } + }); + }); + + return res; + } + private _createPlugins() { return [ ...(this.plugins || []), @@ -288,6 +329,25 @@ export class HaChartBase extends LitElement { display: false, }, }, + { + id: "labelClickHandler", + afterEvent: (chart: Chart, event) => { + const evt = event.event; + + if (evt.type !== "click" || event.inChartArea) { + return; + } + + const labelInfo = this._findLabel(evt); + + if (labelInfo) { + fireEvent(this, "label-click", { + label: labelInfo.label, + index: labelInfo.index, + }); + } + }, + }, ]; } @@ -451,4 +511,10 @@ declare global { interface HTMLElementTagNameMap { "ha-chart-base": HaChartBase; } + interface HASSDomEvents { + "label-click": { + label: string; + index: number; + }; + } } diff --git a/src/components/chart/state-history-charts.ts b/src/components/chart/state-history-charts.ts index d9dd0d983e21..001aed9c5462 100644 --- a/src/components/chart/state-history-charts.ts +++ b/src/components/chart/state-history-charts.ts @@ -13,6 +13,7 @@ import { queryAll, state, } from "lit/decorators"; +import { fireEvent } from "../../common/dom/fire_event"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { restoreScroll } from "../../common/decorators/restore-scroll"; import { @@ -198,6 +199,7 @@ export class StateHistoryCharts extends LitElement { .paddingYAxis=${this._maxYWidth} .chartIndex=${index} @y-width-changed=${this._yWidthChanged} + @label-click=${this._labelClicked} > `; }; @@ -236,6 +238,18 @@ export class StateHistoryCharts extends LitElement { this._maxYWidth = Math.max(...Object.values(this._childYWidths), 0); } + private _labelClicked(e: CustomEvent) { + const timeline = this.historyData?.timeline; + + if (timeline) { + const entityId = timeline[e.detail.index]?.entity_id; + + if (entityId) { + fireEvent(this, "hass-more-info", { entityId }); + } + } + } + private _isHistoryEmpty(): boolean { const historyDataEmpty = !this.historyData ||