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.
This commit is contained in:
Jørn Myrland 2021-10-02 13:46:52 +02:00 committed by Aria
parent 4d49a8bdd6
commit bf0367bd0d
2 changed files with 42 additions and 1 deletions

View file

@ -7,6 +7,7 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100%; height: 100%;
background: black;
} }
</style> </style>
</head> </head>

View file

@ -11,6 +11,7 @@ import styled from 'styled-components'
import {useReceiveVerticalWheelEvent} from '@theatre/studio/panels/SequenceEditorPanel/VerticalScrollContainer' import {useReceiveVerticalWheelEvent} from '@theatre/studio/panels/SequenceEditorPanel/VerticalScrollContainer'
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css' import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
import {useCursorLock} from '@theatre/studio/uiComponents/PointerEventsHandler' import {useCursorLock} from '@theatre/studio/uiComponents/PointerEventsHandler'
import type {IRange} from '@theatre/shared/utils/types'
const Container = styled.div` const Container = styled.div`
position: absolute; position: absolute;
@ -192,7 +193,8 @@ function useHandlePanAndZoom(
) )
const oldRange = val(layoutP.clippedSpace.range) 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) => { const newRange = mapValues(oldRange, (originalPos) => {
return ( 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) val(layoutP.clippedSpace.setRange)(newRange)
} }
} }
@ -217,6 +246,17 @@ function useHandlePanAndZoom(
}, [node, layoutP]) }, [node, layoutP])
} }
function normalize(value: number, [min, max]: [min: number, max: number]) {
return Math.max(Math.min(value, max), min)
}
function normalizeRange(
range: IRange<number>,
minMax: [min: number, max: number],
) {
return mapValues(range, (pos) => normalize(pos, minMax))
}
function useUpdateScrollFromClippedSpaceRange( function useUpdateScrollFromClippedSpaceRange(
layoutP: Pointer<SequenceEditorPanelLayout>, layoutP: Pointer<SequenceEditorPanelLayout>,
node: HTMLDivElement | null, node: HTMLDivElement | null,