From 1699732853e9fdd1422620c040211a3216230d79 Mon Sep 17 00:00:00 2001 From: Guy Geva Date: Wed, 9 Feb 2022 16:59:27 +0200 Subject: [PATCH 1/7] Document setZoomLevel, change the distance from center check to use the distance formula --- src/eterna/pose2D/Pose2D.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/eterna/pose2D/Pose2D.ts b/src/eterna/pose2D/Pose2D.ts index 47db4a9bd..af3f9db27 100644 --- a/src/eterna/pose2D/Pose2D.ts +++ b/src/eterna/pose2D/Pose2D.ts @@ -317,10 +317,16 @@ export default class Pose2D extends ContainerObject implements Updatable { return this._zoomLevel; } + /** + * @param animate should the zoom happen in an animation over time, instead of instantaniously + * @param center should the camera move to the center of the screen + */ public setZoomLevel(zoomLevel: number, animate: boolean = true, center: boolean = false): void { - if ((this._zoomLevel !== zoomLevel || center) && animate) { - if (this._zoomLevel === zoomLevel && center) { - if (Math.abs(this._width / 2 - this._offX) + Math.abs(this._height / 2 - this._offY) < 50) { + const needsToZoom = this._zoomLevel !== zoomLevel; + if ((needsToZoom || center) && animate) { + if (!needsToZoom && center) { + const distanceFromCenter = Math.hypot(this._width / 2 - this._offX, this._height / 2 - this._offY); + if (distanceFromCenter < 50) { return; } } @@ -349,7 +355,7 @@ export default class Pose2D extends ContainerObject implements Updatable { this._zoomLevel = zoomLevel; this.computeLayout(true); this._redraw = true; - } else if (this._zoomLevel !== zoomLevel) { + } else if (needsToZoom) { this._zoomLevel = zoomLevel; this.computeLayout(true); this._redraw = true; From 2b8f24c2355e04165ea1011501655b7cd1e7937a Mon Sep 17 00:00:00 2001 From: Guy Geva Date: Thu, 10 Feb 2022 21:57:33 +0200 Subject: [PATCH 2/7] Refactor zooming to respect the mouse position, add world<->screen utilities to Pose2D --- src/eterna/pose2D/Pose2D.ts | 87 ++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/src/eterna/pose2D/Pose2D.ts b/src/eterna/pose2D/Pose2D.ts index af3f9db27..6a9166df4 100644 --- a/src/eterna/pose2D/Pose2D.ts +++ b/src/eterna/pose2D/Pose2D.ts @@ -257,6 +257,32 @@ export default class Pose2D extends ContainerObject implements Updatable { })); } + public get mousePosition() { + return Pose2D.P; + } + + public worldToScreenPosition( + worldPosition: Point, + offset: Point | null = null, + zoomLevel: number | null = null + ): Point { + zoomLevel ??= this.zoomLevel; + offset ??= new Point(this._offX, this._offY); + const spacing = Pose2D.ZOOM_SPACINGS[zoomLevel]; + return new Point(offset.x + worldPosition.x * spacing, offset.y + worldPosition.y * spacing); + } + + public screenToWorldPosition( + screenPosition: Point, + offset: Point | null = null, + zoomLevel: number | null = null + ): Point { + zoomLevel ??= this.zoomLevel; + offset ??= new Point(this._offX, this._offY); + const spacing = Pose2D.ZOOM_SPACINGS[zoomLevel]; + return new Point((screenPosition.x - offset.x) / spacing, (screenPosition.y - offset.y) / spacing); + } + public setSize(width: number, height: number): void { this._width = width; this._height = height; @@ -334,20 +360,37 @@ export default class Pose2D extends ContainerObject implements Updatable { this._startOffsetX = this._offX; this._startOffsetY = this._offY; - let scaler = 1; - if (zoomLevel > this._zoomLevel) { - scaler = Pose2D.ZOOM_SPACINGS[zoomLevel] / Pose2D.ZOOM_SPACINGS[this._zoomLevel]; - } - - if (!this._offsetTranslating && !center) { - this._endOffsetX = scaler * (this._offX - this._width / 2) + this._width / 2; - this._endOffsetY = scaler * (this._offY - this._height / 2) + this._height / 2; - } else if (this._offsetTranslating) { - this._endOffsetX = scaler * (this._endOffsetX - this._width / 2) + this._width / 2; - this._endOffsetY = scaler * (this._endOffsetY - this._height / 2) + this._height / 2; - } else { + if (center) { this._endOffsetX = this._width / 2; this._endOffsetY = this._height / 2; + } else { + /** The offset after the current animation finishes */ + let effectiveOffset: Point; + if (this._offsetTranslating) { + // TODO: should this be different? I need to respect if the mosue moved + // also what if the user presses the button? + // also what if the user drags in the middle of the zoom? + effectiveOffset = new Point(this._endOffsetX, this._endOffsetY); + } else { + effectiveOffset = new Point(this._offX, this._offY); + } + + const oldMouseScreenPosition = this.mousePosition; + const mouseWorldPosition = this.screenToWorldPosition( + oldMouseScreenPosition, + effectiveOffset, + this.zoomLevel + ); + const newMouseScreenPosition = this.worldToScreenPosition( + mouseWorldPosition, + effectiveOffset, + zoomLevel + ); + + // The mouse should stay at the same point in space before and after zooming, + // so move the offset to cancel the mouse movement. + this._endOffsetX = effectiveOffset.x + oldMouseScreenPosition.x - newMouseScreenPosition.x; + this._endOffsetY = effectiveOffset.y + oldMouseScreenPosition.y - newMouseScreenPosition.y; } this._offsetTranslating = true; @@ -2790,6 +2833,15 @@ export default class Pose2D extends ContainerObject implements Updatable { if (prog >= 1) { prog = 1; + } + + if (this._offsetTranslating) { + this._redraw = true; + this._offX = prog * this._endOffsetX + (1 - prog) * this._startOffsetX; + this._offY = prog * this._endOffsetY + (1 - prog) * this._startOffsetY; + } + + if (prog >= 1) { this._offsetTranslating = false; this.redrawAnnotations(); @@ -2799,12 +2851,6 @@ export default class Pose2D extends ContainerObject implements Updatable { this.clearAnnotationCanvas(); } - if (this._offsetTranslating) { - this._redraw = true; - this._offX = prog * this._endOffsetX + (1 - prog) * this._startOffsetX; - this._offY = prog * this._endOffsetY + (1 - prog) * this._startOffsetY; - } - this.setAnimationProgress(prog); } else if (currentTime - this.lastSampledTime > 2 && !this._isExploding) { this.lastSampledTime = currentTime; @@ -3061,8 +3107,8 @@ export default class Pose2D extends ContainerObject implements Updatable { const vx: number = this._baseToX[ii] - this._baseFromX[ii]; const vy: number = this._baseToY[ii] - this._baseFromY[ii]; - const currentX: number = this._baseFromX[ii] + ((vx + (vx * progress)) / 2) * progress; - const currentY: number = this._baseFromY[ii] + ((vy + (vy * progress)) / 2) * progress; + const currentX = this._baseFromX[ii] + vx * progress; + const currentY = this._baseFromY[ii] + vy * progress; this._bases[ii].setXY(currentX, currentY); } @@ -4310,6 +4356,7 @@ export default class Pose2D extends ContainerObject implements Updatable { private _offY: number = 0; private _prevOffsetX: number = 0; private _prevOffsetY: number = 0; + /** Are we currently animating a movement */ private _offsetTranslating: boolean; private _startOffsetX: number; private _startOffsetY: number; From 1465e91be4552dac3dd1fed6e9449bee6f24faea Mon Sep 17 00:00:00 2001 From: Guy Geva Date: Fri, 11 Feb 2022 00:07:32 +0200 Subject: [PATCH 3/7] Refactor Pose2D to use Point for offsets --- src/eterna/pose2D/Pose2D.ts | 123 ++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/src/eterna/pose2D/Pose2D.ts b/src/eterna/pose2D/Pose2D.ts index 6a9166df4..93b8ea1dd 100644 --- a/src/eterna/pose2D/Pose2D.ts +++ b/src/eterna/pose2D/Pose2D.ts @@ -267,9 +267,12 @@ export default class Pose2D extends ContainerObject implements Updatable { zoomLevel: number | null = null ): Point { zoomLevel ??= this.zoomLevel; - offset ??= new Point(this._offX, this._offY); + offset ??= this._offset; const spacing = Pose2D.ZOOM_SPACINGS[zoomLevel]; - return new Point(offset.x + worldPosition.x * spacing, offset.y + worldPosition.y * spacing); + return new Point( + offset.x + worldPosition.x * spacing, + offset.y + worldPosition.y * spacing + ); } public screenToWorldPosition( @@ -278,9 +281,12 @@ export default class Pose2D extends ContainerObject implements Updatable { zoomLevel: number | null = null ): Point { zoomLevel ??= this.zoomLevel; - offset ??= new Point(this._offX, this._offY); + offset ??= this._offset; const spacing = Pose2D.ZOOM_SPACINGS[zoomLevel]; - return new Point((screenPosition.x - offset.x) / spacing, (screenPosition.y - offset.y) / spacing); + return new Point( + (screenPosition.x - offset.x) / spacing, + (screenPosition.y - offset.y) / spacing + ); } public setSize(width: number, height: number): void { @@ -351,29 +357,26 @@ export default class Pose2D extends ContainerObject implements Updatable { const needsToZoom = this._zoomLevel !== zoomLevel; if ((needsToZoom || center) && animate) { if (!needsToZoom && center) { - const distanceFromCenter = Math.hypot(this._width / 2 - this._offX, this._height / 2 - this._offY); + // TODO Guy: hypot is expensive and I don't even need the sqrt + const distanceFromCenter = Math.hypot( + this._width / 2 - this._offset.x, + this._height / 2 - this._offset.y + ); if (distanceFromCenter < 50) { return; } } - this._startOffsetX = this._offX; - this._startOffsetY = this._offY; + this._startOffset = this._offset.clone(); if (center) { - this._endOffsetX = this._width / 2; - this._endOffsetY = this._height / 2; + this._endOffset = new Point(this._width / 2, this._height / 2); } else { + // TODO: should this be different? I need to respect if the mosue moved + // also what if the user presses the button? + // also what if the user drags in the middle of the zoom? /** The offset after the current animation finishes */ - let effectiveOffset: Point; - if (this._offsetTranslating) { - // TODO: should this be different? I need to respect if the mosue moved - // also what if the user presses the button? - // also what if the user drags in the middle of the zoom? - effectiveOffset = new Point(this._endOffsetX, this._endOffsetY); - } else { - effectiveOffset = new Point(this._offX, this._offY); - } + const effectiveOffset = this._offsetTranslating ? this._endOffset : this._offset; const oldMouseScreenPosition = this.mousePosition; const mouseWorldPosition = this.screenToWorldPosition( @@ -389,8 +392,10 @@ export default class Pose2D extends ContainerObject implements Updatable { // The mouse should stay at the same point in space before and after zooming, // so move the offset to cancel the mouse movement. - this._endOffsetX = effectiveOffset.x + oldMouseScreenPosition.x - newMouseScreenPosition.x; - this._endOffsetY = effectiveOffset.y + oldMouseScreenPosition.y - newMouseScreenPosition.y; + this._endOffset = new Point( + effectiveOffset.x + oldMouseScreenPosition.x - newMouseScreenPosition.x, + effectiveOffset.y + oldMouseScreenPosition.y - newMouseScreenPosition.y + ); } this._offsetTranslating = true; @@ -571,8 +576,8 @@ export default class Pose2D extends ContainerObject implements Updatable { if (out == null) { out = new Point(); } - out.x = this._bases[seq].x + this._offX; - out.y = this._bases[seq].y + this._offY; + out.x = this._bases[seq].x + this._offset.x; + out.y = this._bases[seq].y + this._offset.y; return out; } @@ -591,8 +596,8 @@ export default class Pose2D extends ContainerObject implements Updatable { public getBaseOutXY(seq: number, out: Point | null = null): Point { out = this._bases[seq].getOutXY(out); - out.x += this._offX; - out.y += this._offY; + out.x += this._offset.x; + out.y += this._offset.y; return out; } @@ -1222,16 +1227,16 @@ export default class Pose2D extends ContainerObject implements Updatable { if (!this._targetPairs.isPaired(startIdx)) { // Update individual base coordinates. this._bases[startIdx].setXY( - (mouseX - this._offX), - (mouseY - this._offY) + (mouseX - this._offset.x), + (mouseY - this._offset.y) ); // Update the customLayout in the same way. // Actually, after writing this, I no longer know why it works. for (let ii = 0; ii < localCustomLayout.length; ++ii) { localCustomLayout[startIdx] = [ - localCustomLayout[ii][0] as number + (mouseX - this._offX) - this._bases[ii].x, - localCustomLayout[ii][1] as number + (mouseY - this._offY) - this._bases[ii].y + localCustomLayout[ii][0] as number + (mouseX - this._offset.x) - this._bases[ii].x, + localCustomLayout[ii][1] as number + (mouseY - this._offset.y) - this._bases[ii].y ]; } @@ -1244,8 +1249,8 @@ export default class Pose2D extends ContainerObject implements Updatable { for (const bp of stem) { for (const idx of bp) { this._bases[idx].setXY( - mouseX + this._bases[idx].x - origX - this._offX, - mouseY + this._bases[idx].y - origY - this._offY + mouseX + this._bases[idx].x - origX - this._offset.x, + mouseY + this._bases[idx].y - origY - this._offset.y ); this._bases[idx].setDirty(); @@ -1275,7 +1280,7 @@ export default class Pose2D extends ContainerObject implements Updatable { const fullSeqLen = this.fullSequenceLength; for (let ii = 0; ii < fullSeqLen; ii++) { const mouseDist: number = this._bases[ii].isClicked( - mouseX - this._offX, mouseY - this._offY, this._zoomLevel, this._coloring + mouseX - this._offset.x, mouseY - this._offset.y, this._zoomLevel, this._coloring ); if (mouseDist >= 0) { if (closestIndex < 0 || mouseDist < closestDist) { @@ -1322,8 +1327,8 @@ export default class Pose2D extends ContainerObject implements Updatable { if (!this._coloring) { this.clearMouse(); } - const mouseX = this._bases[closestIndex].x + this._offX; - const mouseY = this._bases[closestIndex].y + this._offY; + const mouseX = this._bases[closestIndex].x + this._offset.x; + const mouseY = this._bases[closestIndex].y + this._offset.y; this._paintCursor.display.x = mouseX; this._paintCursor.display.y = mouseY; @@ -1393,11 +1398,11 @@ export default class Pose2D extends ContainerObject implements Updatable { } public get xOffset(): number { - return this._offX; + return this._offset.x; } public get yOffset(): number { - return this._offY; + return this._offset.y; } public setOffset(offX: number, offY: number): void { @@ -1408,8 +1413,8 @@ export default class Pose2D extends ContainerObject implements Updatable { this._annotationDialog.display.x -= (this.xOffset - offX); this._annotationDialog.display.y -= (this.yOffset - offY); } - this._offX = offX; - this._offY = offY; + this._offset.x = offX; + this._offset.y = offY; this._redraw = true; } @@ -1815,8 +1820,7 @@ export default class Pose2D extends ContainerObject implements Updatable { } public updateHighlightsAndScores(): void { - this._prevOffsetX = -1; - this._prevOffsetY = -1; + this._prevOffset = new Point(-1, -1); this.generateScoreNodes(); } @@ -2161,7 +2165,7 @@ export default class Pose2D extends ContainerObject implements Updatable { const fullSeqLen = this.fullSequenceLength; for (let ii = 0; ii < fullSeqLen; ii++) { const mouseDist: number = this._bases[ii].isClicked( - mouseX - this._offX, mouseY - this._offY, this._zoomLevel, false + mouseX - this._offset.x, mouseY - this._offset.y, this._zoomLevel, false ); if (mouseDist >= 0) { if (closestIndex < 0 || mouseDist < closestDist) { @@ -2797,7 +2801,7 @@ export default class Pose2D extends ContainerObject implements Updatable { } this._bases[ii].setDrawParams( - this._zoomLevel, this._offX, this._offY, currentTime, drawFlags, numberBitmap, hlState + this._zoomLevel, this._offset.x, this._offset.y, currentTime, drawFlags, numberBitmap, hlState ); } } @@ -2837,8 +2841,10 @@ export default class Pose2D extends ContainerObject implements Updatable { if (this._offsetTranslating) { this._redraw = true; - this._offX = prog * this._endOffsetX + (1 - prog) * this._startOffsetX; - this._offY = prog * this._endOffsetY + (1 - prog) * this._startOffsetY; + this._offset = new Point( + prog * this._endOffset.x + (1 - prog) * this._startOffset.x, + prog * this._endOffset.y + (1 - prog) * this._startOffset.y + ); } if (prog >= 1) { @@ -2863,7 +2869,8 @@ export default class Pose2D extends ContainerObject implements Updatable { } // Update score node - this.updateScoreNodeVisualization(this._offX !== this._prevOffsetX || this._offY !== this._prevOffsetY); + // TODO Guy: test + this.updateScoreNodeVisualization(!this._offset.equals(this._prevOffset)); // / Bitblt rendering const needRedraw = this._bases.some( @@ -3019,12 +3026,14 @@ export default class Pose2D extends ContainerObject implements Updatable { if (this._isExploding && !this._offsetTranslating && this._baseToX == null) { if (this._explosionStartTime < 0) { this._explosionStartTime = currentTime; - this._origOffsetX = this._offX; - this._origOffsetY = this._offY; + this._origOffset = this._offset.clone(); } - this._offX = this._origOffsetX + (Math.random() * 2 - 1) * 5; - this._offY = this._origOffsetY + (Math.random() * 2 - 1) * 5; + // TODO Guy: Should we call setOffset here? + this._offset = new Point( + this._origOffset.x + (Math.random() * 2 - 1) * 5, + this._origOffset.y + (Math.random() * 2 - 1) * 5 + ); this._redraw = true; const prog = (currentTime - this._explosionStartTime) * 5; @@ -3073,8 +3082,7 @@ export default class Pose2D extends ContainerObject implements Updatable { } } - this._prevOffsetX = this._offX; - this._prevOffsetY = this._offY; + this._prevOffset = this._offset.clone(); } public lateUpdate(_dt: number): void { @@ -4352,16 +4360,12 @@ export default class Pose2D extends ContainerObject implements Updatable { private lastSampledTime: number = -1; // Pose position offset - private _offX: number = 0; - private _offY: number = 0; - private _prevOffsetX: number = 0; - private _prevOffsetY: number = 0; + private _offset: Point = new Point(0, 0); + private _prevOffset: Point = new Point(0, 0); /** Are we currently animating a movement */ private _offsetTranslating: boolean; - private _startOffsetX: number; - private _startOffsetY: number; - private _endOffsetX: number; - private _endOffsetY: number; + private _startOffset: Point; + private _endOffset: Point; // For base moving animation private _baseFromX: number[] | null; @@ -4380,8 +4384,7 @@ export default class Pose2D extends ContainerObject implements Updatable { private _isExploding: boolean = false; private _explosionStartTime: number = -1; private _explosionRays: LightRay[]; - private _origOffsetX: number; - private _origOffsetY: number; + private _origOffset: Point; private _onExplosionComplete: (() => void) | null; From 16c235ae6bf9f7ba3b3ec8b841f9cc4942e9e7f3 Mon Sep 17 00:00:00 2001 From: Guy Geva Date: Mon, 14 Feb 2022 22:01:19 +0200 Subject: [PATCH 4/7] Rename offsetTranslating to animatingZoom, make stuff call setOffset --- src/eterna/pose2D/Pose2D.ts | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/eterna/pose2D/Pose2D.ts b/src/eterna/pose2D/Pose2D.ts index 93b8ea1dd..c1c85f4f6 100644 --- a/src/eterna/pose2D/Pose2D.ts +++ b/src/eterna/pose2D/Pose2D.ts @@ -357,12 +357,9 @@ export default class Pose2D extends ContainerObject implements Updatable { const needsToZoom = this._zoomLevel !== zoomLevel; if ((needsToZoom || center) && animate) { if (!needsToZoom && center) { - // TODO Guy: hypot is expensive and I don't even need the sqrt - const distanceFromCenter = Math.hypot( - this._width / 2 - this._offset.x, - this._height / 2 - this._offset.y - ); - if (distanceFromCenter < 50) { + const squaredDistanceFromCenter = (this._width / 2 - this._offset.x) ** 2 + + (this._height / 2 - this._offset.y) ** 2; + if (squaredDistanceFromCenter < 50 ** 2) { return; } } @@ -376,7 +373,7 @@ export default class Pose2D extends ContainerObject implements Updatable { // also what if the user presses the button? // also what if the user drags in the middle of the zoom? /** The offset after the current animation finishes */ - const effectiveOffset = this._offsetTranslating ? this._endOffset : this._offset; + const effectiveOffset = this._animatingZoom ? this._endOffset : this._offset; const oldMouseScreenPosition = this.mousePosition; const mouseWorldPosition = this.screenToWorldPosition( @@ -398,7 +395,7 @@ export default class Pose2D extends ContainerObject implements Updatable { ); } - this._offsetTranslating = true; + this._animatingZoom = true; this._zoomLevel = zoomLevel; this.computeLayout(true); @@ -2839,16 +2836,16 @@ export default class Pose2D extends ContainerObject implements Updatable { prog = 1; } - if (this._offsetTranslating) { + if (this._animatingZoom) { this._redraw = true; - this._offset = new Point( + this.setOffset( prog * this._endOffset.x + (1 - prog) * this._startOffset.x, prog * this._endOffset.y + (1 - prog) * this._startOffset.y ); } if (prog >= 1) { - this._offsetTranslating = false; + this._animatingZoom = false; this.redrawAnnotations(); } else { @@ -2869,7 +2866,6 @@ export default class Pose2D extends ContainerObject implements Updatable { } // Update score node - // TODO Guy: test this.updateScoreNodeVisualization(!this._offset.equals(this._prevOffset)); // / Bitblt rendering @@ -3005,7 +3001,7 @@ export default class Pose2D extends ContainerObject implements Updatable { } // / Praise stacks when RNA is not moving - if (!this._offsetTranslating && this._baseToX == null) { + if (!this._animatingZoom && this._baseToX == null) { if (this._praiseQueue.length > 0) { for (let ii = 0; ii < this._praiseQueue.length; ii += 2) { this.onPraiseStack( @@ -3023,14 +3019,13 @@ export default class Pose2D extends ContainerObject implements Updatable { } } - if (this._isExploding && !this._offsetTranslating && this._baseToX == null) { + if (this._isExploding && !this._animatingZoom && this._baseToX == null) { if (this._explosionStartTime < 0) { this._explosionStartTime = currentTime; this._origOffset = this._offset.clone(); } - // TODO Guy: Should we call setOffset here? - this._offset = new Point( + this.setOffset( this._origOffset.x + (Math.random() * 2 - 1) * 5, this._origOffset.y + (Math.random() * 2 - 1) * 5 ); @@ -4362,8 +4357,7 @@ export default class Pose2D extends ContainerObject implements Updatable { // Pose position offset private _offset: Point = new Point(0, 0); private _prevOffset: Point = new Point(0, 0); - /** Are we currently animating a movement */ - private _offsetTranslating: boolean; + private _animatingZoom: boolean; private _startOffset: Point; private _endOffset: Point; From 2239eb20710ad69c6119cc703e572bd842b3b9dc Mon Sep 17 00:00:00 2001 From: Jonathan Romano Date: Tue, 8 Mar 2022 22:50:11 -0500 Subject: [PATCH 5/7] Remove extranious getter --- src/eterna/pose2D/Pose2D.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/eterna/pose2D/Pose2D.ts b/src/eterna/pose2D/Pose2D.ts index c1c85f4f6..b384a31ca 100644 --- a/src/eterna/pose2D/Pose2D.ts +++ b/src/eterna/pose2D/Pose2D.ts @@ -257,10 +257,6 @@ export default class Pose2D extends ContainerObject implements Updatable { })); } - public get mousePosition() { - return Pose2D.P; - } - public worldToScreenPosition( worldPosition: Point, offset: Point | null = null, @@ -375,7 +371,7 @@ export default class Pose2D extends ContainerObject implements Updatable { /** The offset after the current animation finishes */ const effectiveOffset = this._animatingZoom ? this._endOffset : this._offset; - const oldMouseScreenPosition = this.mousePosition; + const oldMouseScreenPosition = Pose2D.P; const mouseWorldPosition = this.screenToWorldPosition( oldMouseScreenPosition, effectiveOffset, From 549561a2debcd08f3cd3da160c10b26e9fbb4ab4 Mon Sep 17 00:00:00 2001 From: Guy Geva Date: Fri, 6 May 2022 17:14:15 +0300 Subject: [PATCH 6/7] Split setZoomLevel into helper zoomOntoMouse and focusOnScreenPoint --- src/eterna/pose2D/Pose2D.ts | 84 ++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/src/eterna/pose2D/Pose2D.ts b/src/eterna/pose2D/Pose2D.ts index b384a31ca..b276747c3 100644 --- a/src/eterna/pose2D/Pose2D.ts +++ b/src/eterna/pose2D/Pose2D.ts @@ -344,12 +344,52 @@ export default class Pose2D extends ContainerObject implements Updatable { public get zoomLevel(): number { return this._zoomLevel; } + + public focusOnScreenPoint(screenPoint: Point) { + // Guy TODO: Should I use .set/.copyFrom or `=`? + this._startOffset = this._offset.clone(); + this._endOffset = screenPoint.clone(); + } + + private zoomOntoMouse(newZoomLevel: number){ + // Guy TODO: should this be different? I need to respect if the mosue moved + // also what if the user presses the button? + // also what if the user drags in the middle of the zoom? + /** The offset after the current animation finishes */ + const effectiveOffset = this._animatingZoom ? this._endOffset : this._offset; + + const oldMouseScreenPosition = Pose2D.P; + const mouseWorldPosition = this.screenToWorldPosition( + oldMouseScreenPosition, + effectiveOffset, + this.zoomLevel + ); + const newMouseScreenPosition = this.worldToScreenPosition( + mouseWorldPosition, + effectiveOffset, + newZoomLevel + ); + + // The mouse should stay at the same point in space before and after zooming, + // so move the offset to cancel the mouse movement. + this.focusOnScreenPoint(new Point( + effectiveOffset.x + oldMouseScreenPosition.x - newMouseScreenPosition.x, + effectiveOffset.y + oldMouseScreenPosition.y - newMouseScreenPosition.y + )); + } /** * @param animate should the zoom happen in an animation over time, instead of instantaniously * @param center should the camera move to the center of the screen */ public setZoomLevel(zoomLevel: number, animate: boolean = true, center: boolean = false): void { + console.trace(); + // I need to extract the inner logic to make sure I can use it in any way I want: + // * Just set the zoom level and the target offset (don't calculate the mouse at all) + // * potential: Just set the zoom level, and zoom according to any arbitrary focus? + // * Zoom in / out on the mouse + // * Zoom in / out on an arbitrary point + // * Zoom in / out on the center of the RNA const needsToZoom = this._zoomLevel !== zoomLevel; if ((needsToZoom || center) && animate) { if (!needsToZoom && center) { @@ -360,47 +400,23 @@ export default class Pose2D extends ContainerObject implements Updatable { } } - this._startOffset = this._offset.clone(); - if (center) { - this._endOffset = new Point(this._width / 2, this._height / 2); + this.focusOnScreenPoint(new Point(this._width / 2, this._height / 2)); } else { - // TODO: should this be different? I need to respect if the mosue moved - // also what if the user presses the button? - // also what if the user drags in the middle of the zoom? - /** The offset after the current animation finishes */ - const effectiveOffset = this._animatingZoom ? this._endOffset : this._offset; - - const oldMouseScreenPosition = Pose2D.P; - const mouseWorldPosition = this.screenToWorldPosition( - oldMouseScreenPosition, - effectiveOffset, - this.zoomLevel - ); - const newMouseScreenPosition = this.worldToScreenPosition( - mouseWorldPosition, - effectiveOffset, - zoomLevel - ); - - // The mouse should stay at the same point in space before and after zooming, - // so move the offset to cancel the mouse movement. - this._endOffset = new Point( - effectiveOffset.x + oldMouseScreenPosition.x - newMouseScreenPosition.x, - effectiveOffset.y + oldMouseScreenPosition.y - newMouseScreenPosition.y - ); + this.zoomOntoMouse(zoomLevel); } this._animatingZoom = true; - this._zoomLevel = zoomLevel; - this.computeLayout(true); - this._redraw = true; - } else if (needsToZoom) { - this._zoomLevel = zoomLevel; - this.computeLayout(true); - this._redraw = true; } + // Guy TODO: make sure that I didn't break anything here + // I think that I made it still happen if all 3 values are false? might just wrap everything in an if or add a return at the start + // Guy TODO: Where should _zoomLevel = zoomLevel sit? + this._zoomLevel = zoomLevel; + // Guy TODO: What do these 2 lines do? is it just because I changed the zoomLevel, or also because I changed the offset? + // If it's because I change the offset, can I put that in setOffset? + this.computeLayout(true); + this._redraw = true; } public computeDefaultZoomLevel(): number { From 6febe8ef77f7622fbd178624de08788c76366316 Mon Sep 17 00:00:00 2001 From: Guy Geva Date: Fri, 6 May 2022 17:15:03 +0300 Subject: [PATCH 7/7] Fix centering when changing to PIP Mode --- src/eterna/mode/PoseEdit/PoseEditMode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eterna/mode/PoseEdit/PoseEditMode.ts b/src/eterna/mode/PoseEdit/PoseEditMode.ts index f5b575c9a..4eeb59c8b 100644 --- a/src/eterna/mode/PoseEdit/PoseEditMode.ts +++ b/src/eterna/mode/PoseEdit/PoseEditMode.ts @@ -1612,7 +1612,7 @@ export default class PoseEditMode extends GameMode { )); for (const pose of this._poses) { - pose.setZoomLevel(minZoom); + pose.setZoomLevel(minZoom, true, true); } } else { this._toolbar.stateToggle.display.visible = true;