From 8e05f068c59386aedaf17b036681bb7f644e3693 Mon Sep 17 00:00:00 2001 From: azure <983547216@qq.com> Date: Thu, 4 Sep 2025 19:16:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=9D=E5=AD=98=E4=B8=80=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/utils/DraggableResizableWindow.ts | 200 ++++++++++----------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/src/core/utils/DraggableResizableWindow.ts b/src/core/utils/DraggableResizableWindow.ts index 7b98fdf..71a0a81 100644 --- a/src/core/utils/DraggableResizableWindow.ts +++ b/src/core/utils/DraggableResizableWindow.ts @@ -292,6 +292,106 @@ export class DraggableResizableWindow { if (isFinal) this.applyBoundary(); } + private animateTo(targetX: number, targetY: number, duration: number, onComplete?: () => void) { + if (this.animationFrame) cancelAnimationFrame(this.animationFrame); + + const startX = this.currentX; + const startY = this.currentY; + const deltaX = targetX - startX; + const deltaY = targetY - startY; + const startTime = performance.now(); + + const step = (now: number) => { + const elapsed = now - startTime; + const progress = Math.min(elapsed / duration, 1); + const ease = 1 - Math.pow(1 - progress, 3); + + const x = startX + deltaX * ease; + const y = startY + deltaY * ease; + + this.applyPosition(x, y, false); + this.onDragMove?.(x, y); + + if (progress < 1) { + this.animationFrame = requestAnimationFrame(step); + } else { + this.applyPosition(targetX, targetY, true); + this.onDragMove?.(targetX, targetY); + onComplete?.(); + } + }; + + this.animationFrame = requestAnimationFrame(step); + } + + private applyBoundary() { + if (!this.boundary || this.allowOverflow) return; + + let { x, y } = { x: this.currentX, y: this.currentY }; + + if (this.boundary instanceof HTMLElement && this.containerRect) { + const rect = this.target.getBoundingClientRect(); + const minX = 0; + const minY = 0; + const maxX = this.containerRect.width - rect.width; + const maxY = this.containerRect.height - rect.height; + + x = Math.min(Math.max(x, minX), maxX); + y = Math.min(Math.max(y, minY), maxY); + } else if (!(this.boundary instanceof HTMLElement)) { + if (this.boundary.minX !== undefined) x = Math.max(x, this.boundary.minX); + if (this.boundary.maxX !== undefined) x = Math.min(x, this.boundary.maxX); + if (this.boundary.minY !== undefined) y = Math.max(y, this.boundary.minY); + if (this.boundary.maxY !== undefined) y = Math.min(y, this.boundary.maxY); + } + + this.currentX = x; + this.currentY = y; + this.applyPosition(x, y, false); + } + + private applySnapping(x: number, y: number) { + let { x: snappedX, y: snappedY } = { x, y }; + + // 1. 容器吸附 + const containerSnap = this.getSnapPoints(); + if (this.snapThreshold > 0) { + for (const sx of containerSnap.x) { + if (Math.abs(x - sx) <= this.snapThreshold) { + snappedX = sx; + break; + } + } + for (const sy of containerSnap.y) { + if (Math.abs(y - sy) <= this.snapThreshold) { + snappedY = sy; + break; + } + } + } + + // 2. 窗口吸附 TODO + + return { x: snappedX, y: snappedY }; + } + + private getSnapPoints() { + const snapPoints = { x: [] as number[], y: [] as number[] }; + + if (this.boundary instanceof HTMLElement && this.containerRect) { + const rect = this.target.getBoundingClientRect(); + snapPoints.x = [0, this.containerRect.width - rect.width]; + snapPoints.y = [0, this.containerRect.height - rect.height]; + } else if (!(this.boundary instanceof HTMLElement) && this.boundary) { + if (this.boundary.minX !== undefined) snapPoints.x.push(this.boundary.minX); + if (this.boundary.maxX !== undefined) snapPoints.x.push(this.boundary.maxX); + if (this.boundary.minY !== undefined) snapPoints.y.push(this.boundary.minY); + if (this.boundary.maxY !== undefined) snapPoints.y.push(this.boundary.maxY); + } + + return snapPoints; + } + private onMouseDownResize = (e: MouseEvent) => { const dir = this.getResizeDirection(e); if (!dir) return; @@ -451,106 +551,6 @@ export class DraggableResizableWindow { if (!this.currentDirection && !this.isDragging) this.updateCursor(null); }; - private animateTo(targetX: number, targetY: number, duration: number, onComplete?: () => void) { - if (this.animationFrame) cancelAnimationFrame(this.animationFrame); - - const startX = this.currentX; - const startY = this.currentY; - const deltaX = targetX - startX; - const deltaY = targetY - startY; - const startTime = performance.now(); - - const step = (now: number) => { - const elapsed = now - startTime; - const progress = Math.min(elapsed / duration, 1); - const ease = 1 - Math.pow(1 - progress, 3); - - const x = startX + deltaX * ease; - const y = startY + deltaY * ease; - - this.applyPosition(x, y, false); - this.onDragMove?.(x, y); - - if (progress < 1) { - this.animationFrame = requestAnimationFrame(step); - } else { - this.applyPosition(targetX, targetY, true); - this.onDragMove?.(targetX, targetY); - onComplete?.(); - } - }; - - this.animationFrame = requestAnimationFrame(step); - } - - private applyBoundary() { - if (!this.boundary || this.allowOverflow) return; - - let { x, y } = { x: this.currentX, y: this.currentY }; - - if (this.boundary instanceof HTMLElement && this.containerRect) { - const rect = this.target.getBoundingClientRect(); - const minX = 0; - const minY = 0; - const maxX = this.containerRect.width - rect.width; - const maxY = this.containerRect.height - rect.height; - - x = Math.min(Math.max(x, minX), maxX); - y = Math.min(Math.max(y, minY), maxY); - } else if (!(this.boundary instanceof HTMLElement)) { - if (this.boundary.minX !== undefined) x = Math.max(x, this.boundary.minX); - if (this.boundary.maxX !== undefined) x = Math.min(x, this.boundary.maxX); - if (this.boundary.minY !== undefined) y = Math.max(y, this.boundary.minY); - if (this.boundary.maxY !== undefined) y = Math.min(y, this.boundary.maxY); - } - - this.currentX = x; - this.currentY = y; - this.applyPosition(x, y, false); - } - - private applySnapping(x: number, y: number) { - let { x: snappedX, y: snappedY } = { x, y }; - - // 1. 容器吸附 - const containerSnap = this.getSnapPoints(); - if (this.snapThreshold > 0) { - for (const sx of containerSnap.x) { - if (Math.abs(x - sx) <= this.snapThreshold) { - snappedX = sx; - break; - } - } - for (const sy of containerSnap.y) { - if (Math.abs(y - sy) <= this.snapThreshold) { - snappedY = sy; - break; - } - } - } - - // 2. 窗口吸附 TODO - - return { x: snappedX, y: snappedY }; - } - - private getSnapPoints() { - const snapPoints = { x: [] as number[], y: [] as number[] }; - - if (this.boundary instanceof HTMLElement && this.containerRect) { - const rect = this.target.getBoundingClientRect(); - snapPoints.x = [0, this.containerRect.width - rect.width]; - snapPoints.y = [0, this.containerRect.height - rect.height]; - } else if (!(this.boundary instanceof HTMLElement) && this.boundary) { - if (this.boundary.minX !== undefined) snapPoints.x.push(this.boundary.minX); - if (this.boundary.maxX !== undefined) snapPoints.x.push(this.boundary.maxX); - if (this.boundary.minY !== undefined) snapPoints.y.push(this.boundary.minY); - if (this.boundary.maxY !== undefined) snapPoints.y.push(this.boundary.maxY); - } - - return snapPoints; - } - private observeResize(container: HTMLElement) { if (this.resizeObserver) this.resizeObserver.disconnect(); this.resizeObserver = new ResizeObserver(() => {