From 7cd6fe2d22bb668321849e5421dbc8c7657068eb Mon Sep 17 00:00:00 2001 From: Jamie Wong Date: Sat, 25 Nov 2017 02:13:01 -0800 Subject: [PATCH] Reintroduce pan and zoom clamping --- flamechart.tsx | 60 ++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/flamechart.tsx b/flamechart.tsx index 3ca6e56..835a2aa 100644 --- a/flamechart.tsx +++ b/flamechart.tsx @@ -116,6 +116,9 @@ export class FlamechartView extends Component { this.WORLD_SPACE_FRAME_HEIGHT )) } + private worldSpaceSize() { + return this.configSpaceToWorldSpace().transformVector(this.configSpaceSize()) + } private worldSpaceToViewSpace() { return AffineTransform.betweenRects( @@ -150,47 +153,52 @@ export class FlamechartView extends Component { private pan(viewSpaceDelta: Vec2) { const worldSpaceDelta = this.worldSpaceToViewSpace().inverseTransformVector(viewSpaceDelta) if (!worldSpaceDelta) return - - // TODO(jlfwong): Add back clamping of panning bounds - /* - const worldSpacePanningBounds = new Rect( - new Vec2(0, 0), - this.configSpaceToWorldSpace().transformVector(this.configSpaceSize()).minus(this.worldSpaceViewportRect.size) - ) - */ - - this.worldSpaceViewportRect = AffineTransform.withTranslation(worldSpaceDelta) - .transformRect(this.worldSpaceViewportRect) + this.transformViewport(AffineTransform.withTranslation(worldSpaceDelta)) } - private zoom(worldSpaceZoomCenter: Vec2, multiplier: number) { - /* - multiplier = clamp(multiplier, - 5 / this.worldSpaceViewportRect.width(), - this.viewportWidth() / this.worldSpaceViewportRect.width() - ) - */ + private zoom(viewSpaceZoomCenter: Vec2, multiplier: number) { + const worldSpaceZoomCenter = this.worldSpaceToViewSpace().inverseTransformPosition(viewSpaceZoomCenter) + if (!worldSpaceZoomCenter) return const zoomTransform = AffineTransform .withTranslation(worldSpaceZoomCenter.times(-1)) .scaledBy(new Vec2(multiplier, 1)) .translatedBy(worldSpaceZoomCenter) + this.transformViewport(zoomTransform) + } - this.worldSpaceViewportRect = zoomTransform.transformRect(this.worldSpaceViewportRect) + private transformViewport(transform: AffineTransform) { + const viewportRect = transform.transformRect(this.worldSpaceViewportRect) + + const worldSpaceOriginBounds = new Rect( + new Vec2(0, 0), + this.worldSpaceSize().minus(viewportRect.size) + ) + + const worldSpaceSizeBounds = new Rect( + new Vec2(1, viewportRect.height()), + new Vec2(this.worldSpaceSize().x, viewportRect.height()) + ) + + this.worldSpaceViewportRect = new Rect( + worldSpaceOriginBounds.closestPointTo(viewportRect.origin), + worldSpaceSizeBounds.closestPointTo(viewportRect.size) + ) } private onWheel = (ev: WheelEvent) => { ev.preventDefault() + // TODO(jlfwong): When scrolling and adding or releasing + // a modifier key, any momentum scrolling from previous + // initiated momentum scrolling may still take effect. + // Figure out how to prevent this. + // + // Also, support drag-based panning, and pinch-to-zoom if (ev.metaKey) { - const viewSpaceZoomCenter = new Vec2(ev.offsetX, ev.offsetY) - const worldSpaceZoomCenter = this.worldSpaceToViewSpace().inverseTransformPosition(viewSpaceZoomCenter) - - if (worldSpaceZoomCenter) { - const multiplier = 1 + (ev.deltaY / 100) - this.zoom(worldSpaceZoomCenter, multiplier) - } + const multiplier = 1 + (ev.deltaY / 100) + this.zoom(new Vec2(ev.offsetX, ev.offsetY), multiplier) } else { this.pan(new Vec2(ev.deltaX, ev.deltaY)) }