From 00667f1296ecaad7e7bdc7bdcac3a2bd05b05400 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Wed, 25 Jan 2023 07:42:20 -0800 Subject: [PATCH] Vertically align history charts on left axis (#14919) Co-authored-by: Bram Kragten fixes undefined --- src/components/chart/ha-chart-base.ts | 8 +++++ .../chart/state-history-chart-line.ts | 20 +++++++++++ .../chart/state-history-chart-timeline.ts | 18 ++++++++++ src/components/chart/state-history-charts.ts | 35 +++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 30dc0f548b..0f7c5b9d3c 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -10,6 +10,8 @@ import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import { styleMap } from "lit/directives/style-map"; import { clamp } from "../../common/number/clamp"; +import { computeRTL } from "../../common/util/compute_rtl"; +import { HomeAssistant } from "../../types"; export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000; @@ -22,6 +24,8 @@ interface Tooltip extends TooltipModel { export default class HaChartBase extends LitElement { public chart?: Chart; + @property({ attribute: false }) public hass!: HomeAssistant; + @property({ attribute: "chart-type", reflect: true }) public chartType: ChartType = "line"; @@ -33,6 +37,8 @@ export default class HaChartBase extends LitElement { @property({ type: Number }) public height?: number; + @property({ type: Number }) public paddingYAxis = 0; + @state() private _chartHeight?: number; @state() private _tooltip?: Tooltip; @@ -128,6 +134,8 @@ export default class HaChartBase extends LitElement { style=${styleMap({ height: `${this.height ?? this._chartHeight}px`, overflow: this._chartHeight ? "initial" : "hidden", + "padding-left": `${computeRTL(this.hass) ? 0 : this.paddingYAxis}px`, + "padding-right": `${computeRTL(this.hass) ? this.paddingYAxis : 0}px`, })} > diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts index 95f52185fc..dc24388d13 100644 --- a/src/components/chart/state-history-chart-line.ts +++ b/src/components/chart/state-history-chart-line.ts @@ -2,6 +2,8 @@ import type { ChartData, ChartDataset, ChartOptions } from "chart.js"; import { html, LitElement, PropertyValues } from "lit"; import { property, state } from "lit/decorators"; import { getGraphColorByIndex } from "../../common/color/colors"; +import { fireEvent } from "../../common/dom/fire_event"; +import { computeRTL } from "../../common/util/compute_rtl"; import { formatNumber, numberFormatToLocale, @@ -30,17 +32,25 @@ class StateHistoryChartLine extends LitElement { @property({ attribute: false }) public endTime!: Date; + @property({ type: Number }) public paddingYAxis = 0; + + @property({ type: Number }) public chartIndex?; + @state() private _chartData?: ChartData<"line">; @state() private _chartOptions?: ChartOptions; + @state() private _yWidth = 0; + private _chartTime: Date = new Date(); protected render() { return html` `; @@ -84,6 +94,16 @@ class StateHistoryChartLine extends LitElement { display: true, text: this.unit, }, + afterUpdate: (y) => { + if (this._yWidth !== Math.floor(y.width)) { + this._yWidth = Math.floor(y.width); + fireEvent(this, "y-width-changed", { + value: this._yWidth, + chartIndex: this.chartIndex, + }); + } + }, + position: computeRTL(this.hass) ? "right" : "left", }, }, plugins: { diff --git a/src/components/chart/state-history-chart-timeline.ts b/src/components/chart/state-history-chart-timeline.ts index ac8de6813b..78b3831ba0 100644 --- a/src/components/chart/state-history-chart-timeline.ts +++ b/src/components/chart/state-history-chart-timeline.ts @@ -2,6 +2,7 @@ import type { ChartData, ChartDataset, ChartOptions } from "chart.js"; import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators"; import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time"; +import { fireEvent } from "../../common/dom/fire_event"; import { numberFormatToLocale } from "../../common/number/format_number"; import { computeRTL } from "../../common/util/compute_rtl"; import { TimelineEntity } from "../../data/history"; @@ -32,18 +33,26 @@ export class StateHistoryChartTimeline extends LitElement { @property({ attribute: false }) public endTime!: Date; + @property({ type: Number }) public paddingYAxis = 0; + + @property({ type: Number }) public chartIndex?; + @state() private _chartData?: ChartData<"timeline">; @state() private _chartOptions?: ChartOptions<"timeline">; + @state() private _yWidth = 0; + private _chartTime: Date = new Date(); protected render() { return html` `; @@ -131,6 +140,15 @@ export class StateHistoryChartTimeline extends LitElement { scaleInstance.width = narrow ? 105 : 185; } }, + afterUpdate: (y) => { + if (this._yWidth !== Math.floor(y.width)) { + this._yWidth = Math.floor(y.width); + fireEvent(this, "y-width-changed", { + value: this._yWidth, + chartIndex: this.chartIndex, + }); + } + }, position: computeRTL(this.hass) ? "right" : "left", }, }, diff --git a/src/components/chart/state-history-charts.ts b/src/components/chart/state-history-charts.ts index a4f467cfd8..4da124dc90 100644 --- a/src/components/chart/state-history-charts.ts +++ b/src/components/chart/state-history-charts.ts @@ -31,6 +31,12 @@ const chunkData = (inputArray: any[], chunks: number) => return results; }, []); +declare global { + interface HASSDomEvents { + "y-width-changed": { value: number; chartIndex: number }; + } +} + @customElement("state-history-charts") class StateHistoryCharts extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -56,6 +62,12 @@ class StateHistoryCharts extends LitElement { @state() private _computedEndTime!: Date; + @state() private _maxYWidth = 0; + + @state() private _childYWidths: number[] = []; + + @state() private _chartCount = 0; + // @ts-ignore @restoreScroll(".container") private _savedScrollPos?: number; @@ -99,6 +111,8 @@ class StateHistoryCharts extends LitElement { ).concat(this.historyData.line) : this.historyData.line; + this._chartCount = combinedItems.length; + return this.virtualize ? html`
`; } @@ -144,6 +161,9 @@ class StateHistoryCharts extends LitElement { .names=${this.names} .narrow=${this.narrow} .chunked=${this.virtualize} + .paddingYAxis=${this._maxYWidth} + .chartIndex=${index} + @y-width-changed=${this._yWidthChanged} > `; }; @@ -152,6 +172,21 @@ class StateHistoryCharts extends LitElement { return !(changedProps.size === 1 && changedProps.has("hass")); } + protected updated(changedProps: PropertyValues) { + if (changedProps.has("_chartCount")) { + if (this._chartCount < this._childYWidths.length) { + this._childYWidths.length = this._chartCount; + this._maxYWidth = + this._childYWidths.length === 0 ? 0 : Math.max(...this._childYWidths); + } + } + } + + private _yWidthChanged(e: CustomEvent) { + this._childYWidths[e.detail.chartIndex] = e.detail.value; + this._maxYWidth = Math.max(...this._childYWidths); + } + private _isHistoryEmpty(): boolean { const historyDataEmpty = !this.historyData ||