perf: Cache panel position to reduce layout thrashing and synchronize control movement by disabling transitions.
This commit is contained in:
@@ -8,6 +8,9 @@ import { StateManager } from './StateManager';
|
||||
export class PositionManager {
|
||||
stateManager: StateManager;
|
||||
panelElement: HTMLElement;
|
||||
// Cache the calculated position to avoid getBoundingClientRect() and layout thrashing
|
||||
// This also ensures controls move in perfect sync with the panel, ignoring CSS transitions
|
||||
cachedPanelPosition: { x: number, y: number, width: number, height: number } | null = null;
|
||||
|
||||
constructor(stateManager: StateManager, panelElement: HTMLElement) {
|
||||
this.stateManager = stateManager;
|
||||
@@ -52,6 +55,8 @@ export class PositionManager {
|
||||
|
||||
this.panelElement.style.left = `${boundedX}px`;
|
||||
this.panelElement.style.top = `${boundedY}px`;
|
||||
|
||||
this.cachedPanelPosition = { x: boundedX, y: boundedY, width: panelWidth, height: panelHeight };
|
||||
}
|
||||
|
||||
calculateNormalPosition(): void {
|
||||
@@ -125,6 +130,8 @@ export class PositionManager {
|
||||
|
||||
this.panelElement.style.left = `${left}px`;
|
||||
this.panelElement.style.top = `${top}px`;
|
||||
|
||||
this.cachedPanelPosition = { x: left, y: top, width: panelWidth, height: panelHeight };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,11 +151,26 @@ export class PositionManager {
|
||||
const magnifyGlass = window.comfyUIMagnifyGlass;
|
||||
let referenceRect: DOMRect | null = null;
|
||||
|
||||
// 1. Position relative to PANEL (Preferred if visible)
|
||||
if (isPanelVisible && this.panelElement) {
|
||||
// Position relative to panel
|
||||
referenceRect = this.panelElement.getBoundingClientRect();
|
||||
} else if (magnifyGlass && magnifyGlass.ui && magnifyGlass.ui.glassDiv) {
|
||||
// Position relative to magnify glass
|
||||
// Priority: Use Cached Position (Logical) -> Avoids 'chasing' CSS transitions
|
||||
if (this.cachedPanelPosition) {
|
||||
// Convert simple object to Rect-like interface for compatibility
|
||||
referenceRect = {
|
||||
left: this.cachedPanelPosition.x,
|
||||
top: this.cachedPanelPosition.y,
|
||||
right: this.cachedPanelPosition.x + this.cachedPanelPosition.width,
|
||||
bottom: this.cachedPanelPosition.y + this.cachedPanelPosition.height,
|
||||
width: this.cachedPanelPosition.width,
|
||||
height: this.cachedPanelPosition.height
|
||||
} as DOMRect;
|
||||
} else {
|
||||
// Fallback: Read DOM (May cause layout thrashing/lag)
|
||||
referenceRect = this.panelElement.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
// 2. Position relative to GLASS (Fallback if panel hidden)
|
||||
else if (magnifyGlass && magnifyGlass.ui && magnifyGlass.ui.glassDiv) {
|
||||
referenceRect = magnifyGlass.ui.glassDiv.getBoundingClientRect();
|
||||
// Don't show controls if glass is hidden/invalid
|
||||
if (referenceRect.width === 0 || referenceRect.height === 0) {
|
||||
@@ -159,6 +181,9 @@ export class PositionManager {
|
||||
|
||||
if (!referenceRect) return;
|
||||
|
||||
// Enforce no transition on controls to prevent 'rubber-banding'
|
||||
controlsElement.style.transition = 'none';
|
||||
|
||||
const controlsPosition = this.stateManager.state.settings["🔍MagnifyGlass.ControlsPosition"] || "right";
|
||||
const margin = 4;
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ class PositionManager {
|
||||
constructor(stateManager, panelElement) {
|
||||
__publicField(this, "stateManager");
|
||||
__publicField(this, "panelElement");
|
||||
// Cache the calculated position to avoid getBoundingClientRect() and layout thrashing
|
||||
// This also ensures controls move in perfect sync with the panel, ignoring CSS transitions
|
||||
__publicField(this, "cachedPanelPosition", null);
|
||||
this.stateManager = stateManager;
|
||||
this.panelElement = panelElement;
|
||||
}
|
||||
@@ -34,6 +37,7 @@ class PositionManager {
|
||||
const boundedY = Math.max(margin, Math.min(y, window.innerHeight - panelHeight - margin));
|
||||
this.panelElement.style.left = `${boundedX}px`;
|
||||
this.panelElement.style.top = `${boundedY}px`;
|
||||
this.cachedPanelPosition = { x: boundedX, y: boundedY, width: panelWidth, height: panelHeight };
|
||||
}
|
||||
calculateNormalPosition() {
|
||||
var _a, _b, _c;
|
||||
@@ -93,6 +97,7 @@ class PositionManager {
|
||||
top = Math.max(4, Math.min(top, window.innerHeight - panelHeight - 4));
|
||||
this.panelElement.style.left = `${left}px`;
|
||||
this.panelElement.style.top = `${top}px`;
|
||||
this.cachedPanelPosition = { x: left, y: top, width: panelWidth, height: panelHeight };
|
||||
}
|
||||
/**
|
||||
* Position the floating controls relative to the panel.
|
||||
@@ -108,7 +113,18 @@ class PositionManager {
|
||||
const magnifyGlass = window.comfyUIMagnifyGlass;
|
||||
let referenceRect = null;
|
||||
if (isPanelVisible && this.panelElement) {
|
||||
referenceRect = this.panelElement.getBoundingClientRect();
|
||||
if (this.cachedPanelPosition) {
|
||||
referenceRect = {
|
||||
left: this.cachedPanelPosition.x,
|
||||
top: this.cachedPanelPosition.y,
|
||||
right: this.cachedPanelPosition.x + this.cachedPanelPosition.width,
|
||||
bottom: this.cachedPanelPosition.y + this.cachedPanelPosition.height,
|
||||
width: this.cachedPanelPosition.width,
|
||||
height: this.cachedPanelPosition.height
|
||||
};
|
||||
} else {
|
||||
referenceRect = this.panelElement.getBoundingClientRect();
|
||||
}
|
||||
} else if (magnifyGlass && magnifyGlass.ui && magnifyGlass.ui.glassDiv) {
|
||||
referenceRect = magnifyGlass.ui.glassDiv.getBoundingClientRect();
|
||||
if (referenceRect.width === 0 || referenceRect.height === 0) {
|
||||
@@ -117,6 +133,7 @@ class PositionManager {
|
||||
}
|
||||
}
|
||||
if (!referenceRect) return;
|
||||
controlsElement.style.transition = "none";
|
||||
const controlsPosition = this.stateManager.state.settings["🔍MagnifyGlass.ControlsPosition"] || "right";
|
||||
const margin = 4;
|
||||
let left;
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user