mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Chart updates to improve stability, possible fix for infinite loop (#18329)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
10bcaadcdb
commit
3e6ab8b179
@ -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 { debounce } from "../../common/util/debounce";
|
||||
|
||||
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
|
||||
|
||||
@ -52,6 +53,12 @@ export class HaChartBase extends LitElement {
|
||||
|
||||
@state() private _hiddenDatasets: Set<number> = new Set();
|
||||
|
||||
private _paddingUpdateCount = 0;
|
||||
|
||||
private _paddingUpdateLock = false;
|
||||
|
||||
private _paddingYAxisInternal = 0;
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._releaseCanvas();
|
||||
@ -104,9 +111,44 @@ export class HaChartBase extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
public shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
if (
|
||||
this._paddingUpdateLock &&
|
||||
changedProps.size === 1 &&
|
||||
changedProps.has("paddingYAxis")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private _debouncedClearUpdates = debounce(
|
||||
() => {
|
||||
this._paddingUpdateCount = 0;
|
||||
},
|
||||
2000,
|
||||
false
|
||||
);
|
||||
|
||||
public willUpdate(changedProps: PropertyValues): void {
|
||||
super.willUpdate(changedProps);
|
||||
|
||||
if (!this._paddingUpdateLock) {
|
||||
this._paddingYAxisInternal = this.paddingYAxis;
|
||||
if (changedProps.size === 1 && changedProps.has("paddingYAxis")) {
|
||||
this._paddingUpdateCount++;
|
||||
if (this._paddingUpdateCount > 300) {
|
||||
this._paddingUpdateLock = true;
|
||||
// eslint-disable-next-line
|
||||
console.error(
|
||||
"Detected excessive chart padding updates, possibly an infinite loop. Disabling axis padding."
|
||||
);
|
||||
} else {
|
||||
this._debouncedClearUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.hasUpdated || !this.chart) {
|
||||
return;
|
||||
}
|
||||
@ -171,10 +213,10 @@ export class HaChartBase extends LitElement {
|
||||
this.height ?? this._chartHeight ?? this.clientWidth / 2
|
||||
}px`,
|
||||
"padding-left": `${
|
||||
computeRTL(this.hass) ? 0 : this.paddingYAxis
|
||||
computeRTL(this.hass) ? 0 : this._paddingYAxisInternal
|
||||
}px`,
|
||||
"padding-right": `${
|
||||
computeRTL(this.hass) ? this.paddingYAxis : 0
|
||||
computeRTL(this.hass) ? this._paddingYAxisInternal : 0
|
||||
}px`,
|
||||
})}
|
||||
>
|
||||
@ -324,7 +366,7 @@ export class HaChartBase extends LitElement {
|
||||
clamp(
|
||||
context.tooltip.caretX,
|
||||
100,
|
||||
this.clientWidth - 100 - this.paddingYAxis
|
||||
this.clientWidth - 100 - this._paddingYAxisInternal
|
||||
) -
|
||||
100 +
|
||||
"px",
|
||||
|
@ -73,9 +73,9 @@ export class StateHistoryCharts extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public isLoadingData = false;
|
||||
|
||||
@state() private _computedStartTime!: Date;
|
||||
private _computedStartTime!: Date;
|
||||
|
||||
@state() private _computedEndTime!: Date;
|
||||
private _computedEndTime!: Date;
|
||||
|
||||
@state() private _maxYWidth = 0;
|
||||
|
||||
@ -114,31 +114,6 @@ export class StateHistoryCharts extends LitElement {
|
||||
${this.hass.localize("ui.components.history_charts.no_history_found")}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
|
||||
this._computedEndTime =
|
||||
this.upToNow || !this.endTime || this.endTime > now ? now : this.endTime;
|
||||
|
||||
if (this.startTime) {
|
||||
this._computedStartTime = this.startTime;
|
||||
} else if (this.hoursToShow) {
|
||||
this._computedStartTime = new Date(
|
||||
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
|
||||
);
|
||||
} else {
|
||||
this._computedStartTime = new Date(
|
||||
this.historyData.timeline.reduce(
|
||||
(minTime, stateInfo) =>
|
||||
Math.min(
|
||||
minTime,
|
||||
new Date(stateInfo.data[0].last_changed).getTime()
|
||||
),
|
||||
new Date().getTime()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const combinedItems = this.historyData.timeline.length
|
||||
? (this.virtualize
|
||||
? chunkData(this.historyData.timeline, CANVAS_TIMELINE_ROWS_CHUNK)
|
||||
@ -220,10 +195,45 @@ export class StateHistoryCharts extends LitElement {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected willUpdate() {
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
if (!this.hasUpdated) {
|
||||
loadVirtualizer();
|
||||
}
|
||||
if (
|
||||
[...changedProps.keys()].some(
|
||||
(prop) =>
|
||||
!(
|
||||
["_maxYWidth", "_childYWidths", "_chartCount"] as PropertyKey[]
|
||||
).includes(prop)
|
||||
)
|
||||
) {
|
||||
// Don't recompute times when we just want to update layout
|
||||
const now = new Date();
|
||||
|
||||
this._computedEndTime =
|
||||
this.upToNow || !this.endTime || this.endTime > now
|
||||
? now
|
||||
: this.endTime;
|
||||
|
||||
if (this.startTime) {
|
||||
this._computedStartTime = this.startTime;
|
||||
} else if (this.hoursToShow) {
|
||||
this._computedStartTime = new Date(
|
||||
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
|
||||
);
|
||||
} else {
|
||||
this._computedStartTime = new Date(
|
||||
this.historyData.timeline.reduce(
|
||||
(minTime, stateInfo) =>
|
||||
Math.min(
|
||||
minTime,
|
||||
new Date(stateInfo.data[0].last_changed).getTime()
|
||||
),
|
||||
new Date().getTime()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user