refactor: reimplement glass positioning with dynamic anchoring for improved responsiveness and boundary handling
This commit is contained in:
@@ -19,10 +19,10 @@ export class EventHandler {
|
||||
constructor(magnifyGlass: MagnifyGlass) {
|
||||
this.magnifyGlass = magnifyGlass;
|
||||
|
||||
// Bind methods to maintain context
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handleKeyUp = this.handleKeyUp.bind(this);
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,6 +32,7 @@ export class EventHandler {
|
||||
document.addEventListener("keydown", this.handleKeyDown);
|
||||
document.addEventListener("keyup", this.handleKeyUp);
|
||||
document.addEventListener("mousemove", this.handleMouseMove);
|
||||
window.addEventListener("resize", this.handleResize);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,6 +42,22 @@ export class EventHandler {
|
||||
document.removeEventListener("keydown", this.handleKeyDown);
|
||||
document.removeEventListener("keyup", this.handleKeyUp);
|
||||
document.removeEventListener("mousemove", this.handleMouseMove);
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle window resize events.
|
||||
*/
|
||||
handleResize(): void {
|
||||
if (this.magnifyGlass && this.magnifyGlass.ui) {
|
||||
this.magnifyGlass.ui.updateResponsivePosition();
|
||||
// Also update panel position if it exists
|
||||
const infoPanel = (window as any).infoPanelManager;
|
||||
if (infoPanel && infoPanel.positionManager) {
|
||||
// Determine if we should move it
|
||||
infoPanel.positionManager.positionPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,11 +247,11 @@ export class EventHandler {
|
||||
const glassSize = this.magnifyGlass.config.glassSize;
|
||||
|
||||
if (!this.magnifyGlass.state.wasActivatedBefore && this.magnifyGlass.ui.glassDiv) {
|
||||
// First activation - position at top right of the window
|
||||
const leftPos = window.innerWidth - glassSize - DEFAULT_PADDING;
|
||||
console.log(`[MagnifyGlass] Initial position - innerWidth: ${window.innerWidth}, glassSize: ${glassSize}, padding: ${DEFAULT_PADDING}, left: ${leftPos}, yOffset: ${DEFAULT_GLASS_Y_OFFSET}`);
|
||||
this.magnifyGlass.ui.glassDiv.style.left = `${leftPos}px`;
|
||||
// First activation - position at top right of the window (Anchored)
|
||||
// Using style.right ensures it stays on the right even if window resizes before first usage
|
||||
this.magnifyGlass.ui.glassDiv.style.right = `${DEFAULT_PADDING}px`;
|
||||
this.magnifyGlass.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.magnifyGlass.ui.glassDiv.style.left = 'auto'; // Ensure left is unset
|
||||
this.magnifyGlass.state.wasActivatedBefore = true;
|
||||
} else {
|
||||
this.magnifyGlass.ui.positionGlass(clientX, clientY);
|
||||
|
||||
@@ -82,6 +82,10 @@ export class MagnifyGlass {
|
||||
// Create UI elements
|
||||
this.ui.createElements();
|
||||
|
||||
// Ensure glass is validly positioned (within viewport) right away
|
||||
// This handles cases where config has saved positions from a different monitor size
|
||||
this.ui.updateResponsivePosition();
|
||||
|
||||
// Setup WebGL renderer
|
||||
this.renderer = new WebGLRenderer(this.config, this.state, this.ui);
|
||||
if (!this.renderer.isValid()) {
|
||||
@@ -387,10 +391,24 @@ export class MagnifyGlass {
|
||||
|
||||
// Reset magnify glass position to top-right corner
|
||||
if (this.ui.glassDiv) {
|
||||
const glassSize = this.config.glassSize;
|
||||
this.ui.glassDiv.style.left = `${window.innerWidth - glassSize - DEFAULT_PADDING}px`;
|
||||
this.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.state.wasActivatedBefore = false;
|
||||
// If it's the first activation, position at top right of the window (Anchored)
|
||||
// Otherwise, reset to the last known position or default if not active.
|
||||
if (!this.state.wasActivatedBefore) {
|
||||
const padding = DEFAULT_PADDING;
|
||||
// Using style.right ensures it stays on the right even if window resizes before first usage
|
||||
this.ui.glassDiv.style.right = `${padding}px`;
|
||||
this.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.ui.glassDiv.style.left = 'auto'; // Ensure left is unset
|
||||
this.state.wasActivatedBefore = true;
|
||||
} else {
|
||||
// If it was already activated, and we are resetting, we might want to keep its current position
|
||||
// or explicitly reset it to the initial anchored position.
|
||||
// For now, let's re-apply the anchored position on reset if it was already activated.
|
||||
const padding = DEFAULT_PADDING;
|
||||
this.ui.glassDiv.style.right = `${padding}px`;
|
||||
this.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.ui.glassDiv.style.left = 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
// Reset inspector panel position if exists
|
||||
|
||||
+106
-42
@@ -4,7 +4,7 @@
|
||||
* Handles creation and management of DOM elements for the magnifying glass.
|
||||
*/
|
||||
|
||||
import { Z_INDEX, DEFAULT_PADDING } from '../shared/constants';
|
||||
import { Z_INDEX, DEFAULT_PADDING, DEFAULT_GLASS_Y_OFFSET } from '../shared/constants';
|
||||
import { Icons } from '../shared/icons';
|
||||
import { Logger } from '../shared/logger';
|
||||
import type { ConfigManager } from './ConfigManager';
|
||||
@@ -160,57 +160,95 @@ export class UiManager {
|
||||
* @param clientX - Client X coordinate
|
||||
* @param clientY - Client Y coordinate
|
||||
*/
|
||||
/**
|
||||
* Position the glass relative to cursor.
|
||||
* Uses dynamic anchoring (Left/Right, Top/Bottom) based on screen quadrant.
|
||||
* @param clientX - Client X coordinate
|
||||
* @param clientY - Client Y coordinate
|
||||
*/
|
||||
positionGlass(clientX: number, clientY: number): void {
|
||||
if (!this.config.followCursor || !this.glassDiv) return;
|
||||
|
||||
const glassSize = this.config.glassSize;
|
||||
const offsetAmount = DEFAULT_PADDING;
|
||||
let newLeft: number;
|
||||
let newTop: number;
|
||||
const vw = window.innerWidth;
|
||||
const vh = window.innerHeight;
|
||||
|
||||
// Determine base coordinates (top-left based)
|
||||
let targetX: number;
|
||||
let targetY: number;
|
||||
|
||||
// Calculate standard Top-Left based positions first
|
||||
switch (this.config.glassPosition) {
|
||||
case "Top":
|
||||
newLeft = clientX - (glassSize / 2);
|
||||
newTop = clientY - glassSize - offsetAmount;
|
||||
targetX = clientX - (glassSize / 2);
|
||||
targetY = clientY - glassSize - offsetAmount;
|
||||
break;
|
||||
case "Bottom":
|
||||
newLeft = clientX - (glassSize / 2);
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX - (glassSize / 2);
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
case "Left":
|
||||
newLeft = clientX - glassSize - offsetAmount;
|
||||
newTop = clientY - (glassSize / 2);
|
||||
targetX = clientX - glassSize - offsetAmount;
|
||||
targetY = clientY - (glassSize / 2);
|
||||
break;
|
||||
case "Right":
|
||||
newLeft = clientX + offsetAmount;
|
||||
newTop = clientY - (glassSize / 2);
|
||||
targetX = clientX + offsetAmount;
|
||||
targetY = clientY - (glassSize / 2);
|
||||
break;
|
||||
case "Top-Left":
|
||||
newLeft = clientX - glassSize - offsetAmount;
|
||||
newTop = clientY - glassSize - offsetAmount;
|
||||
targetX = clientX - glassSize - offsetAmount;
|
||||
targetY = clientY - glassSize - offsetAmount;
|
||||
break;
|
||||
case "Top-Right":
|
||||
newLeft = clientX + offsetAmount;
|
||||
newTop = clientY - glassSize - offsetAmount;
|
||||
targetX = clientX + offsetAmount;
|
||||
targetY = clientY - glassSize - offsetAmount;
|
||||
break;
|
||||
case "Bottom-Left":
|
||||
newLeft = clientX - glassSize - offsetAmount;
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX - glassSize - offsetAmount;
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
case "Bottom-Right":
|
||||
newLeft = clientX + offsetAmount;
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX + offsetAmount;
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
default:
|
||||
newLeft = clientX - (glassSize / 2);
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX - (glassSize / 2);
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
}
|
||||
|
||||
this.glassDiv.style.left = `${newLeft}px`;
|
||||
this.glassDiv.style.top = `${newTop}px`;
|
||||
// Apply Dynamic Anchoring based on resulting position's center relative to screen
|
||||
const glassCenterX = targetX + (glassSize / 2);
|
||||
const glassCenterY = targetY + (glassSize / 2);
|
||||
|
||||
this.adjustForBoundaries(clientX, clientY);
|
||||
// Horizontal Anchor
|
||||
if (glassCenterX > vw / 2) {
|
||||
// Anchor Right
|
||||
const rightPos = vw - (targetX + glassSize);
|
||||
this.glassDiv.style.right = `${rightPos}px`;
|
||||
this.glassDiv.style.left = 'auto';
|
||||
} else {
|
||||
// Anchor Left
|
||||
this.glassDiv.style.left = `${targetX}px`;
|
||||
this.glassDiv.style.right = 'auto';
|
||||
}
|
||||
|
||||
// Vertical Anchor
|
||||
if (glassCenterY > vh / 2) {
|
||||
// Anchor Bottom
|
||||
const bottomPos = vh - (targetY + glassSize);
|
||||
this.glassDiv.style.bottom = `${bottomPos}px`;
|
||||
this.glassDiv.style.top = 'auto';
|
||||
} else {
|
||||
// Anchor Top
|
||||
this.glassDiv.style.top = `${targetY}px`;
|
||||
this.glassDiv.style.bottom = 'auto';
|
||||
}
|
||||
|
||||
// We run a lightweight clamp to ensure it doesn't bleed offscreen during movement
|
||||
// (Though the anchor logic implicitly handles resize, dragging near edges might need clamping)
|
||||
this.adjustForBoundaries();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,32 +256,58 @@ export class UiManager {
|
||||
* @param clientX - Client X coordinate
|
||||
* @param clientY - Client Y coordinate
|
||||
*/
|
||||
adjustForBoundaries(clientX: number, clientY: number): void {
|
||||
/**
|
||||
* Adjust glass position to stay within viewport boundaries.
|
||||
* Respects the current anchor (Left/Right, Top/Bottom).
|
||||
*/
|
||||
adjustForBoundaries(): void {
|
||||
if (!this.glassDiv) return;
|
||||
|
||||
const glassRect = this.glassDiv.getBoundingClientRect();
|
||||
const glassSize = this.config.glassSize;
|
||||
const padding = DEFAULT_PADDING;
|
||||
const vw = window.innerWidth;
|
||||
const vh = window.innerHeight;
|
||||
|
||||
// Check right boundary
|
||||
if (glassRect.right > window.innerWidth) {
|
||||
this.glassDiv.style.left = `${clientX - glassRect.width - DEFAULT_PADDING}px`;
|
||||
// Check if anchored Right or Left
|
||||
const isAnchoredRight = this.glassDiv.style.right !== 'auto' && this.glassDiv.style.right !== '';
|
||||
|
||||
if (isAnchoredRight) {
|
||||
let currentRight = parseFloat(this.glassDiv.style.right) || padding;
|
||||
// Clamp Right: max(padding, min(current, vw - size - padding))
|
||||
// Ensure it doesn't go off left side (vw - size - padding)
|
||||
currentRight = Math.max(padding, Math.min(currentRight, vw - glassSize - padding));
|
||||
this.glassDiv.style.right = `${currentRight}px`;
|
||||
} else {
|
||||
// Anchor Left
|
||||
let currentLeft = parseFloat(this.glassDiv.style.left) || padding;
|
||||
currentLeft = Math.max(padding, Math.min(currentLeft, vw - glassSize - padding));
|
||||
this.glassDiv.style.left = `${currentLeft}px`;
|
||||
}
|
||||
|
||||
// Check left boundary
|
||||
const currentRectLeft = this.glassDiv.getBoundingClientRect();
|
||||
if (currentRectLeft.left < 0) {
|
||||
this.glassDiv.style.left = "10px";
|
||||
}
|
||||
// Check if anchored Bottom or Top
|
||||
const isAnchoredBottom = this.glassDiv.style.bottom !== 'auto' && this.glassDiv.style.bottom !== '';
|
||||
|
||||
// Check bottom boundary
|
||||
if (glassRect.bottom > window.innerHeight) {
|
||||
this.glassDiv.style.top = `${clientY - glassRect.height - DEFAULT_PADDING}px`;
|
||||
if (isAnchoredBottom) {
|
||||
let currentBottom = parseFloat(this.glassDiv.style.bottom) || padding;
|
||||
currentBottom = Math.max(padding, Math.min(currentBottom, vh - glassSize - padding));
|
||||
this.glassDiv.style.bottom = `${currentBottom}px`;
|
||||
} else {
|
||||
// Anchor Top
|
||||
let currentTop = parseFloat(this.glassDiv.style.top) || padding;
|
||||
currentTop = Math.max(padding, Math.min(currentTop, vh - glassSize - padding));
|
||||
this.glassDiv.style.top = `${currentTop}px`;
|
||||
}
|
||||
}
|
||||
|
||||
// Check top boundary
|
||||
const currentRectTop = this.glassDiv.getBoundingClientRect();
|
||||
if (currentRectTop.top < 0) {
|
||||
this.glassDiv.style.top = "10px";
|
||||
}
|
||||
/**
|
||||
* Update position safely on resize.
|
||||
* Since we use dynamic anchoring in positionGlass, CSS handles most resize cases.
|
||||
* This method ensures we verify boundaries (clamping) and fix anchors if we cross thresholds drastically.
|
||||
*/
|
||||
updateResponsivePosition(): void {
|
||||
if (!this.glassDiv) return;
|
||||
// Re-run boundary adjustments to clamp if resize pushed us offscreen
|
||||
this.adjustForBoundaries();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ class EventHandler {
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handleKeyUp = this.handleKeyUp.bind(this);
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
}
|
||||
/**
|
||||
* Attach all event listeners.
|
||||
@@ -19,6 +20,7 @@ class EventHandler {
|
||||
document.addEventListener("keydown", this.handleKeyDown);
|
||||
document.addEventListener("keyup", this.handleKeyUp);
|
||||
document.addEventListener("mousemove", this.handleMouseMove);
|
||||
window.addEventListener("resize", this.handleResize);
|
||||
}
|
||||
/**
|
||||
* Detach all event listeners.
|
||||
@@ -27,6 +29,19 @@ class EventHandler {
|
||||
document.removeEventListener("keydown", this.handleKeyDown);
|
||||
document.removeEventListener("keyup", this.handleKeyUp);
|
||||
document.removeEventListener("mousemove", this.handleMouseMove);
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
}
|
||||
/**
|
||||
* Handle window resize events.
|
||||
*/
|
||||
handleResize() {
|
||||
if (this.magnifyGlass && this.magnifyGlass.ui) {
|
||||
this.magnifyGlass.ui.updateResponsivePosition();
|
||||
const infoPanel = window.infoPanelManager;
|
||||
if (infoPanel && infoPanel.positionManager) {
|
||||
infoPanel.positionManager.positionPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handle keydown events.
|
||||
@@ -168,12 +183,11 @@ class EventHandler {
|
||||
const pixelY = cssMouseYOnCanvas * scaleY;
|
||||
this.magnifyGlass.state.x = pixelX;
|
||||
this.magnifyGlass.state.y = pixelY;
|
||||
const glassSize = this.magnifyGlass.config.glassSize;
|
||||
this.magnifyGlass.config.glassSize;
|
||||
if (!this.magnifyGlass.state.wasActivatedBefore && this.magnifyGlass.ui.glassDiv) {
|
||||
const leftPos = window.innerWidth - glassSize - DEFAULT_PADDING;
|
||||
console.log(`[MagnifyGlass] Initial position - innerWidth: ${window.innerWidth}, glassSize: ${glassSize}, padding: ${DEFAULT_PADDING}, left: ${leftPos}, yOffset: ${DEFAULT_GLASS_Y_OFFSET}`);
|
||||
this.magnifyGlass.ui.glassDiv.style.left = `${leftPos}px`;
|
||||
this.magnifyGlass.ui.glassDiv.style.right = `${DEFAULT_PADDING}px`;
|
||||
this.magnifyGlass.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.magnifyGlass.ui.glassDiv.style.left = "auto";
|
||||
this.magnifyGlass.state.wasActivatedBefore = true;
|
||||
} else {
|
||||
this.magnifyGlass.ui.positionGlass(clientX, clientY);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -51,6 +51,7 @@ class MagnifyGlass {
|
||||
this.config.loadSavedOffsets();
|
||||
this.debugger.printCanvasInfo();
|
||||
this.ui.createElements();
|
||||
this.ui.updateResponsivePosition();
|
||||
this.renderer = new WebGLRenderer(this.config, this.state, this.ui);
|
||||
if (!this.renderer.isValid()) {
|
||||
this.ui.cleanup();
|
||||
@@ -290,10 +291,18 @@ class MagnifyGlass {
|
||||
this.updateMagnifiedView();
|
||||
}
|
||||
if (this.ui.glassDiv) {
|
||||
const glassSize = this.config.glassSize;
|
||||
this.ui.glassDiv.style.left = `${window.innerWidth - glassSize - DEFAULT_PADDING}px`;
|
||||
this.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.state.wasActivatedBefore = false;
|
||||
if (!this.state.wasActivatedBefore) {
|
||||
const padding = DEFAULT_PADDING;
|
||||
this.ui.glassDiv.style.right = `${padding}px`;
|
||||
this.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.ui.glassDiv.style.left = "auto";
|
||||
this.state.wasActivatedBefore = true;
|
||||
} else {
|
||||
const padding = DEFAULT_PADDING;
|
||||
this.ui.glassDiv.style.right = `${padding}px`;
|
||||
this.ui.glassDiv.style.top = `${DEFAULT_GLASS_Y_OFFSET}px`;
|
||||
this.ui.glassDiv.style.left = "auto";
|
||||
}
|
||||
}
|
||||
const extensions = window.comfyUIMagnifyGlassExtensions;
|
||||
if (extensions && extensions.length > 0) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -129,77 +129,123 @@ class UiManager {
|
||||
* @param clientX - Client X coordinate
|
||||
* @param clientY - Client Y coordinate
|
||||
*/
|
||||
/**
|
||||
* Position the glass relative to cursor.
|
||||
* Uses dynamic anchoring (Left/Right, Top/Bottom) based on screen quadrant.
|
||||
* @param clientX - Client X coordinate
|
||||
* @param clientY - Client Y coordinate
|
||||
*/
|
||||
positionGlass(clientX, clientY) {
|
||||
if (!this.config.followCursor || !this.glassDiv) return;
|
||||
const glassSize = this.config.glassSize;
|
||||
const offsetAmount = DEFAULT_PADDING;
|
||||
let newLeft;
|
||||
let newTop;
|
||||
const vw = window.innerWidth;
|
||||
const vh = window.innerHeight;
|
||||
let targetX;
|
||||
let targetY;
|
||||
switch (this.config.glassPosition) {
|
||||
case "Top":
|
||||
newLeft = clientX - glassSize / 2;
|
||||
newTop = clientY - glassSize - offsetAmount;
|
||||
targetX = clientX - glassSize / 2;
|
||||
targetY = clientY - glassSize - offsetAmount;
|
||||
break;
|
||||
case "Bottom":
|
||||
newLeft = clientX - glassSize / 2;
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX - glassSize / 2;
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
case "Left":
|
||||
newLeft = clientX - glassSize - offsetAmount;
|
||||
newTop = clientY - glassSize / 2;
|
||||
targetX = clientX - glassSize - offsetAmount;
|
||||
targetY = clientY - glassSize / 2;
|
||||
break;
|
||||
case "Right":
|
||||
newLeft = clientX + offsetAmount;
|
||||
newTop = clientY - glassSize / 2;
|
||||
targetX = clientX + offsetAmount;
|
||||
targetY = clientY - glassSize / 2;
|
||||
break;
|
||||
case "Top-Left":
|
||||
newLeft = clientX - glassSize - offsetAmount;
|
||||
newTop = clientY - glassSize - offsetAmount;
|
||||
targetX = clientX - glassSize - offsetAmount;
|
||||
targetY = clientY - glassSize - offsetAmount;
|
||||
break;
|
||||
case "Top-Right":
|
||||
newLeft = clientX + offsetAmount;
|
||||
newTop = clientY - glassSize - offsetAmount;
|
||||
targetX = clientX + offsetAmount;
|
||||
targetY = clientY - glassSize - offsetAmount;
|
||||
break;
|
||||
case "Bottom-Left":
|
||||
newLeft = clientX - glassSize - offsetAmount;
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX - glassSize - offsetAmount;
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
case "Bottom-Right":
|
||||
newLeft = clientX + offsetAmount;
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX + offsetAmount;
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
default:
|
||||
newLeft = clientX - glassSize / 2;
|
||||
newTop = clientY + offsetAmount;
|
||||
targetX = clientX - glassSize / 2;
|
||||
targetY = clientY + offsetAmount;
|
||||
break;
|
||||
}
|
||||
this.glassDiv.style.left = `${newLeft}px`;
|
||||
this.glassDiv.style.top = `${newTop}px`;
|
||||
this.adjustForBoundaries(clientX, clientY);
|
||||
const glassCenterX = targetX + glassSize / 2;
|
||||
const glassCenterY = targetY + glassSize / 2;
|
||||
if (glassCenterX > vw / 2) {
|
||||
const rightPos = vw - (targetX + glassSize);
|
||||
this.glassDiv.style.right = `${rightPos}px`;
|
||||
this.glassDiv.style.left = "auto";
|
||||
} else {
|
||||
this.glassDiv.style.left = `${targetX}px`;
|
||||
this.glassDiv.style.right = "auto";
|
||||
}
|
||||
if (glassCenterY > vh / 2) {
|
||||
const bottomPos = vh - (targetY + glassSize);
|
||||
this.glassDiv.style.bottom = `${bottomPos}px`;
|
||||
this.glassDiv.style.top = "auto";
|
||||
} else {
|
||||
this.glassDiv.style.top = `${targetY}px`;
|
||||
this.glassDiv.style.bottom = "auto";
|
||||
}
|
||||
this.adjustForBoundaries();
|
||||
}
|
||||
/**
|
||||
* Adjust glass position to stay within viewport boundaries.
|
||||
* @param clientX - Client X coordinate
|
||||
* @param clientY - Client Y coordinate
|
||||
*/
|
||||
adjustForBoundaries(clientX, clientY) {
|
||||
/**
|
||||
* Adjust glass position to stay within viewport boundaries.
|
||||
* Respects the current anchor (Left/Right, Top/Bottom).
|
||||
*/
|
||||
adjustForBoundaries() {
|
||||
if (!this.glassDiv) return;
|
||||
const glassRect = this.glassDiv.getBoundingClientRect();
|
||||
if (glassRect.right > window.innerWidth) {
|
||||
this.glassDiv.style.left = `${clientX - glassRect.width - DEFAULT_PADDING}px`;
|
||||
const glassSize = this.config.glassSize;
|
||||
const padding = DEFAULT_PADDING;
|
||||
const vw = window.innerWidth;
|
||||
const vh = window.innerHeight;
|
||||
const isAnchoredRight = this.glassDiv.style.right !== "auto" && this.glassDiv.style.right !== "";
|
||||
if (isAnchoredRight) {
|
||||
let currentRight = parseFloat(this.glassDiv.style.right) || padding;
|
||||
currentRight = Math.max(padding, Math.min(currentRight, vw - glassSize - padding));
|
||||
this.glassDiv.style.right = `${currentRight}px`;
|
||||
} else {
|
||||
let currentLeft = parseFloat(this.glassDiv.style.left) || padding;
|
||||
currentLeft = Math.max(padding, Math.min(currentLeft, vw - glassSize - padding));
|
||||
this.glassDiv.style.left = `${currentLeft}px`;
|
||||
}
|
||||
const currentRectLeft = this.glassDiv.getBoundingClientRect();
|
||||
if (currentRectLeft.left < 0) {
|
||||
this.glassDiv.style.left = "10px";
|
||||
}
|
||||
if (glassRect.bottom > window.innerHeight) {
|
||||
this.glassDiv.style.top = `${clientY - glassRect.height - DEFAULT_PADDING}px`;
|
||||
}
|
||||
const currentRectTop = this.glassDiv.getBoundingClientRect();
|
||||
if (currentRectTop.top < 0) {
|
||||
this.glassDiv.style.top = "10px";
|
||||
const isAnchoredBottom = this.glassDiv.style.bottom !== "auto" && this.glassDiv.style.bottom !== "";
|
||||
if (isAnchoredBottom) {
|
||||
let currentBottom = parseFloat(this.glassDiv.style.bottom) || padding;
|
||||
currentBottom = Math.max(padding, Math.min(currentBottom, vh - glassSize - padding));
|
||||
this.glassDiv.style.bottom = `${currentBottom}px`;
|
||||
} else {
|
||||
let currentTop = parseFloat(this.glassDiv.style.top) || padding;
|
||||
currentTop = Math.max(padding, Math.min(currentTop, vh - glassSize - padding));
|
||||
this.glassDiv.style.top = `${currentTop}px`;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Update position safely on resize.
|
||||
* Since we use dynamic anchoring in positionGlass, CSS handles most resize cases.
|
||||
* This method ensures we verify boundaries (clamping) and fix anchors if we cross thresholds drastically.
|
||||
*/
|
||||
updateResponsivePosition() {
|
||||
if (!this.glassDiv) return;
|
||||
this.adjustForBoundaries();
|
||||
}
|
||||
/**
|
||||
* Apply current config to UI elements.
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user