From bf0367bd0d06665a6ee44ba14f041bbf38a8322a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Myrland?= Date: Sat, 2 Oct 2021 13:46:52 +0200 Subject: [PATCH] Improves scroll interaction for sequence editor - Scroll paning (`shift + scroll`) is now synced for the keyframe viewport, easing viewport and scrollbar (Closes #22) - Scroll zooming out (`ctrl + scroll down`) is now bounded to avoid zooming out to infinity (Closes #19) There is still some quirky behaviour when using scroll to zoom inwards. It does not seem to respect the `pivotPointInUnitSpace` correctly. I've tried fixing it, but I've hit a dead end. --- packages/playground/src/index.html | 1 + .../Right/HorizontallyScrollableArea.tsx | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/playground/src/index.html b/packages/playground/src/index.html index 087be91..4738f60 100644 --- a/packages/playground/src/index.html +++ b/packages/playground/src/index.html @@ -7,6 +7,7 @@ margin: 0; padding: 0; height: 100%; + background: black; } diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/HorizontallyScrollableArea.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/HorizontallyScrollableArea.tsx index 8a62e82..1e92826 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/HorizontallyScrollableArea.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/HorizontallyScrollableArea.tsx @@ -11,6 +11,7 @@ import styled from 'styled-components' import {useReceiveVerticalWheelEvent} from '@theatre/studio/panels/SequenceEditorPanel/VerticalScrollContainer' import {pointerEventsAutoInNormalMode} from '@theatre/studio/css' import {useCursorLock} from '@theatre/studio/uiComponents/PointerEventsHandler' +import type {IRange} from '@theatre/shared/utils/types' const Container = styled.div` position: absolute; @@ -192,7 +193,8 @@ function useHandlePanAndZoom( ) const oldRange = val(layoutP.clippedSpace.range) - const scaleFactor = 1 + event.deltaY * 0.03 + const delta = normalize(event.deltaY, [-50, 50]) + const scaleFactor = 1 + delta * 0.03 const newRange = mapValues(oldRange, (originalPos) => { return ( @@ -201,6 +203,33 @@ function useHandlePanAndZoom( ) }) + // Set maximum scroll points based on the sequence length. + // This is to avoid zooming out to infinity. + const sequenceLength = val(layoutP.sheet).getSequence().length + const maxEnd = sequenceLength + sequenceLength * 0.25 + + val(layoutP.clippedSpace.setRange)( + normalizeRange(newRange, [0, maxEnd]), + ) + } + // paning + else if (event.shiftKey) { + event.preventDefault() + event.stopPropagation() + + const sequenceLength = val(layoutP.sheet).getSequence().length + const oldRange = val(layoutP.clippedSpace.range) + const windowSize = oldRange.end - oldRange.start + const speed = windowSize / sequenceLength + + const delta = normalize(event.deltaY, [-50, 50]) + const scaleFactor = delta * 0.05 * speed + + const newRange = mapValues( + oldRange, + (originalPos) => originalPos + scaleFactor, + ) + val(layoutP.clippedSpace.setRange)(newRange) } } @@ -217,6 +246,17 @@ function useHandlePanAndZoom( }, [node, layoutP]) } +function normalize(value: number, [min, max]: [min: number, max: number]) { + return Math.max(Math.min(value, max), min) +} + +function normalizeRange( + range: IRange, + minMax: [min: number, max: number], +) { + return mapValues(range, (pos) => normalize(pos, minMax)) +} + function useUpdateScrollFromClippedSpaceRange( layoutP: Pointer, node: HTMLDivElement | null,