Skip to content

Commit

Permalink
Chart updates to improve stability, possible fix for infinite loop (#…
Browse files Browse the repository at this point in the history
…18329)

Co-authored-by: Bram Kragten <[email protected]>
  • Loading branch information
karwosts and bramkragten authored Oct 24, 2023
1 parent 10bcaad commit 3e6ab8b
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 31 deletions.
48 changes: 45 additions & 3 deletions src/components/chart/ha-chart-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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`,
})}
>
Expand Down Expand Up @@ -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",
Expand Down
66 changes: 38 additions & 28 deletions src/components/chart/state-history-charts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 3e6ab8b

Please sign in to comment.