mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Vertically align history charts on left axis (#14919)
Co-authored-by: Bram Kragten <mail@bramkragten.nl> fixes undefined
This commit is contained in:
parent
06368a6f0e
commit
00667f1296
@ -10,6 +10,8 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import { clamp } from "../../common/number/clamp";
|
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;
|
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
|
||||||
|
|
||||||
@ -22,6 +24,8 @@ interface Tooltip extends TooltipModel<any> {
|
|||||||
export default class HaChartBase extends LitElement {
|
export default class HaChartBase extends LitElement {
|
||||||
public chart?: Chart;
|
public chart?: Chart;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: "chart-type", reflect: true })
|
@property({ attribute: "chart-type", reflect: true })
|
||||||
public chartType: ChartType = "line";
|
public chartType: ChartType = "line";
|
||||||
|
|
||||||
@ -33,6 +37,8 @@ export default class HaChartBase extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Number }) public height?: number;
|
@property({ type: Number }) public height?: number;
|
||||||
|
|
||||||
|
@property({ type: Number }) public paddingYAxis = 0;
|
||||||
|
|
||||||
@state() private _chartHeight?: number;
|
@state() private _chartHeight?: number;
|
||||||
|
|
||||||
@state() private _tooltip?: Tooltip;
|
@state() private _tooltip?: Tooltip;
|
||||||
@ -128,6 +134,8 @@ export default class HaChartBase extends LitElement {
|
|||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
height: `${this.height ?? this._chartHeight}px`,
|
height: `${this.height ?? this._chartHeight}px`,
|
||||||
overflow: this._chartHeight ? "initial" : "hidden",
|
overflow: this._chartHeight ? "initial" : "hidden",
|
||||||
|
"padding-left": `${computeRTL(this.hass) ? 0 : this.paddingYAxis}px`,
|
||||||
|
"padding-right": `${computeRTL(this.hass) ? this.paddingYAxis : 0}px`,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<canvas></canvas>
|
<canvas></canvas>
|
||||||
|
@ -2,6 +2,8 @@ import type { ChartData, ChartDataset, ChartOptions } from "chart.js";
|
|||||||
import { html, LitElement, PropertyValues } from "lit";
|
import { html, LitElement, PropertyValues } from "lit";
|
||||||
import { property, state } from "lit/decorators";
|
import { property, state } from "lit/decorators";
|
||||||
import { getGraphColorByIndex } from "../../common/color/colors";
|
import { getGraphColorByIndex } from "../../common/color/colors";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import { computeRTL } from "../../common/util/compute_rtl";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
@ -30,17 +32,25 @@ class StateHistoryChartLine extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public endTime!: Date;
|
@property({ attribute: false }) public endTime!: Date;
|
||||||
|
|
||||||
|
@property({ type: Number }) public paddingYAxis = 0;
|
||||||
|
|
||||||
|
@property({ type: Number }) public chartIndex?;
|
||||||
|
|
||||||
@state() private _chartData?: ChartData<"line">;
|
@state() private _chartData?: ChartData<"line">;
|
||||||
|
|
||||||
@state() private _chartOptions?: ChartOptions;
|
@state() private _chartOptions?: ChartOptions;
|
||||||
|
|
||||||
|
@state() private _yWidth = 0;
|
||||||
|
|
||||||
private _chartTime: Date = new Date();
|
private _chartTime: Date = new Date();
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<ha-chart-base
|
<ha-chart-base
|
||||||
|
.hass=${this.hass}
|
||||||
.data=${this._chartData}
|
.data=${this._chartData}
|
||||||
.options=${this._chartOptions}
|
.options=${this._chartOptions}
|
||||||
|
.paddingYAxis=${this.paddingYAxis - this._yWidth}
|
||||||
chart-type="line"
|
chart-type="line"
|
||||||
></ha-chart-base>
|
></ha-chart-base>
|
||||||
`;
|
`;
|
||||||
@ -84,6 +94,16 @@ class StateHistoryChartLine extends LitElement {
|
|||||||
display: true,
|
display: true,
|
||||||
text: this.unit,
|
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: {
|
plugins: {
|
||||||
|
@ -2,6 +2,7 @@ import type { ChartData, ChartDataset, ChartOptions } from "chart.js";
|
|||||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { numberFormatToLocale } from "../../common/number/format_number";
|
import { numberFormatToLocale } from "../../common/number/format_number";
|
||||||
import { computeRTL } from "../../common/util/compute_rtl";
|
import { computeRTL } from "../../common/util/compute_rtl";
|
||||||
import { TimelineEntity } from "../../data/history";
|
import { TimelineEntity } from "../../data/history";
|
||||||
@ -32,18 +33,26 @@ export class StateHistoryChartTimeline extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public endTime!: Date;
|
@property({ attribute: false }) public endTime!: Date;
|
||||||
|
|
||||||
|
@property({ type: Number }) public paddingYAxis = 0;
|
||||||
|
|
||||||
|
@property({ type: Number }) public chartIndex?;
|
||||||
|
|
||||||
@state() private _chartData?: ChartData<"timeline">;
|
@state() private _chartData?: ChartData<"timeline">;
|
||||||
|
|
||||||
@state() private _chartOptions?: ChartOptions<"timeline">;
|
@state() private _chartOptions?: ChartOptions<"timeline">;
|
||||||
|
|
||||||
|
@state() private _yWidth = 0;
|
||||||
|
|
||||||
private _chartTime: Date = new Date();
|
private _chartTime: Date = new Date();
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<ha-chart-base
|
<ha-chart-base
|
||||||
|
.hass=${this.hass}
|
||||||
.data=${this._chartData}
|
.data=${this._chartData}
|
||||||
.options=${this._chartOptions}
|
.options=${this._chartOptions}
|
||||||
.height=${this.data.length * 30 + 30}
|
.height=${this.data.length * 30 + 30}
|
||||||
|
.paddingYAxis=${this.paddingYAxis - this._yWidth}
|
||||||
chart-type="timeline"
|
chart-type="timeline"
|
||||||
></ha-chart-base>
|
></ha-chart-base>
|
||||||
`;
|
`;
|
||||||
@ -131,6 +140,15 @@ export class StateHistoryChartTimeline extends LitElement {
|
|||||||
scaleInstance.width = narrow ? 105 : 185;
|
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",
|
position: computeRTL(this.hass) ? "right" : "left",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -31,6 +31,12 @@ const chunkData = (inputArray: any[], chunks: number) =>
|
|||||||
return results;
|
return results;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"y-width-changed": { value: number; chartIndex: number };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("state-history-charts")
|
@customElement("state-history-charts")
|
||||||
class StateHistoryCharts extends LitElement {
|
class StateHistoryCharts extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -56,6 +62,12 @@ class StateHistoryCharts extends LitElement {
|
|||||||
|
|
||||||
@state() private _computedEndTime!: Date;
|
@state() private _computedEndTime!: Date;
|
||||||
|
|
||||||
|
@state() private _maxYWidth = 0;
|
||||||
|
|
||||||
|
@state() private _childYWidths: number[] = [];
|
||||||
|
|
||||||
|
@state() private _chartCount = 0;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@restoreScroll(".container") private _savedScrollPos?: number;
|
@restoreScroll(".container") private _savedScrollPos?: number;
|
||||||
|
|
||||||
@ -99,6 +111,8 @@ class StateHistoryCharts extends LitElement {
|
|||||||
).concat(this.historyData.line)
|
).concat(this.historyData.line)
|
||||||
: this.historyData.line;
|
: this.historyData.line;
|
||||||
|
|
||||||
|
this._chartCount = combinedItems.length;
|
||||||
|
|
||||||
return this.virtualize
|
return this.virtualize
|
||||||
? html`<div class="container ha-scrollbar" @scroll=${this._saveScrollPos}>
|
? html`<div class="container ha-scrollbar" @scroll=${this._saveScrollPos}>
|
||||||
<lit-virtualizer
|
<lit-virtualizer
|
||||||
@ -130,7 +144,10 @@ class StateHistoryCharts extends LitElement {
|
|||||||
.identifier=${item.identifier}
|
.identifier=${item.identifier}
|
||||||
.showNames=${this.showNames}
|
.showNames=${this.showNames}
|
||||||
.endTime=${this._computedEndTime}
|
.endTime=${this._computedEndTime}
|
||||||
|
.paddingYAxis=${this._maxYWidth}
|
||||||
.names=${this.names}
|
.names=${this.names}
|
||||||
|
.chartIndex=${index}
|
||||||
|
@y-width-changed=${this._yWidthChanged}
|
||||||
></state-history-chart-line>
|
></state-history-chart-line>
|
||||||
</div> `;
|
</div> `;
|
||||||
}
|
}
|
||||||
@ -144,6 +161,9 @@ class StateHistoryCharts extends LitElement {
|
|||||||
.names=${this.names}
|
.names=${this.names}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.chunked=${this.virtualize}
|
.chunked=${this.virtualize}
|
||||||
|
.paddingYAxis=${this._maxYWidth}
|
||||||
|
.chartIndex=${index}
|
||||||
|
@y-width-changed=${this._yWidthChanged}
|
||||||
></state-history-chart-timeline>
|
></state-history-chart-timeline>
|
||||||
</div> `;
|
</div> `;
|
||||||
};
|
};
|
||||||
@ -152,6 +172,21 @@ class StateHistoryCharts extends LitElement {
|
|||||||
return !(changedProps.size === 1 && changedProps.has("hass"));
|
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<HASSDomEvents["y-width-changed"]>) {
|
||||||
|
this._childYWidths[e.detail.chartIndex] = e.detail.value;
|
||||||
|
this._maxYWidth = Math.max(...this._childYWidths);
|
||||||
|
}
|
||||||
|
|
||||||
private _isHistoryEmpty(): boolean {
|
private _isHistoryEmpty(): boolean {
|
||||||
const historyDataEmpty =
|
const historyDataEmpty =
|
||||||
!this.historyData ||
|
!this.historyData ||
|
||||||
|
Loading…
x
Reference in New Issue
Block a user