Skip to content

Commit 4b758c4

Browse files
committed
feat: Batched animation speed updates
1 parent 8750887 commit 4b758c4

1 file changed

Lines changed: 35 additions & 11 deletions

File tree

src/index.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ export class SunsynkPowerFlowCard extends LitElement {
9898

9999
private durationPrev: { [name: string]: number } = {};
100100
private durationCur: { [name: string]: number } = {};
101+
// Batch animation speed changes to minimize DOM work
102+
private _pendingSpeedUpdates: Map<string, number> = new Map();
103+
private _speedRafId: number | null = null;
101104

102105
// Performance: track only entities we care about and last seen states
103106
private _trackedEntityIds: Set<string> = new Set();
@@ -2835,19 +2838,40 @@ export class SunsynkPowerFlowCard extends LitElement {
28352838

28362839
changeAnimationSpeed(el: string, speedRaw: number) {
28372840
const speed = speedRaw >= 1 ? Utils.toNum(speedRaw, 3) : 1;
2838-
const flow = this[`${el}Flow`] as SVGSVGElement;
28392841
this.durationCur[el] = speed;
2840-
if (flow && this._isVisible && this.durationPrev[el] != speed) {
2841-
// console.log(`${el} found, duration change ${this.durationPrev[el]} -> ${this.durationCur[el]}`);
2842-
// this.gridFlow.pauseAnimations();
2843-
requestAnimationFrame(() => {
2844-
flow.setCurrentTime(
2845-
flow.getCurrentTime() * (speed / this.durationPrev[el]),
2846-
);
2847-
});
2848-
// this.gridFlow.unpauseAnimations();
2842+
// Defer DOM mutation: queue update and flush once per frame
2843+
if (this._isVisible) {
2844+
this._pendingSpeedUpdates.set(el, speed);
2845+
if (this._speedRafId == null) {
2846+
this._speedRafId = requestAnimationFrame(() => {
2847+
this._flushAnimationSpeedUpdates();
2848+
});
2849+
}
2850+
} else {
2851+
// If hidden, just record the new duration; apply when visible
2852+
this.durationPrev[el] = this.durationCur[el];
2853+
}
2854+
}
2855+
2856+
private _flushAnimationSpeedUpdates() {
2857+
this._speedRafId = null;
2858+
if (!this._isVisible || this._pendingSpeedUpdates.size === 0) {
2859+
this._pendingSpeedUpdates.clear();
2860+
return;
2861+
}
2862+
for (const [el, speed] of this._pendingSpeedUpdates) {
2863+
const flow = this[`${el}Flow`] as SVGSVGElement | undefined;
2864+
const prev = this.durationPrev[el] ?? 1;
2865+
if (flow && prev !== speed) {
2866+
try {
2867+
flow.setCurrentTime(flow.getCurrentTime() * (speed / prev));
2868+
} catch {
2869+
// ignore if SVG is not ready
2870+
}
2871+
}
2872+
this.durationPrev[el] = this.durationCur[el];
28492873
}
2850-
this.durationPrev[el] = this.durationCur[el];
2874+
this._pendingSpeedUpdates.clear();
28512875
}
28522876

28532877
get isCompactCard() {

0 commit comments

Comments
 (0)