Improve hand dragging with long press (#3432)

This PR makes a small improvement to the hand tool to address a "long
press"-related issues.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
This commit is contained in:
Steve Ruiz 2024-04-10 13:02:50 +01:00 committed by GitHub
parent 987b1ac0b9
commit 180cb67250
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 45 additions and 15 deletions

View file

@ -280,6 +280,8 @@ input,
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
pointer-events: none;
}

View file

@ -15,6 +15,8 @@ import { STRUCTURED_CLONE_OBJECT_PROTOTYPE } from '@tldraw/utils'
* @public
*/
export function devFreeze<T>(object: T): T {
return object
if (process.env.NODE_ENV === 'production') {
return object
}

View file

@ -4,6 +4,7 @@ import {
TLEventHandlers,
TLFrameShape,
TLGroupShape,
TLPointerEventInfo,
TLShapeId,
} from '@tldraw/editor'
@ -52,9 +53,13 @@ export class Pointing extends StateNode {
this.editor.setErasingShapes([...erasing])
}
override onLongPress: TLEventHandlers['onLongPress'] = (info) => {
this.startErasing(info)
}
override onPointerMove: TLEventHandlers['onPointerMove'] = (info) => {
if (this.editor.inputs.isDragging) {
this.parent.transition('erasing', info)
this.startErasing(info)
}
}
@ -74,6 +79,10 @@ export class Pointing extends StateNode {
this.cancel()
}
private startErasing(info: TLPointerEventInfo) {
this.parent.transition('erasing', info)
}
complete() {
const erasingShapeIds = this.editor.getErasingShapeIds()

View file

@ -3,7 +3,10 @@ import { CAMERA_SLIDE_FRICTION, StateNode, TLEventHandlers, Vec } from '@tldraw/
export class Dragging extends StateNode {
static override id = 'dragging'
initialCamera = new Vec()
override onEnter = () => {
this.initialCamera = Vec.From(this.editor.getCamera())
this.update()
}
@ -16,7 +19,7 @@ export class Dragging extends StateNode {
}
override onCancel: TLEventHandlers['onCancel'] = () => {
this.complete()
this.parent.transition('idle')
}
override onComplete = () => {
@ -24,21 +27,27 @@ export class Dragging extends StateNode {
}
private update() {
const { currentScreenPoint, previousScreenPoint } = this.editor.inputs
const { initialCamera, editor } = this
const { currentScreenPoint, originScreenPoint } = editor.inputs
const delta = Vec.Sub(currentScreenPoint, previousScreenPoint)
if (Math.abs(delta.x) > 0 || Math.abs(delta.y) > 0) {
this.editor.pan(delta)
}
const delta = Vec.Sub(currentScreenPoint, originScreenPoint).div(editor.getZoomLevel())
if (delta.len2() === 0) return
editor.setCamera(initialCamera.clone().add(delta))
}
private complete() {
this.editor.slideCamera({
speed: Math.min(2, this.editor.inputs.pointerVelocity.len()),
direction: this.editor.inputs.pointerVelocity,
friction: CAMERA_SLIDE_FRICTION,
})
const { editor } = this
const { pointerVelocity } = editor.inputs
const velocityAtPointerUp = Math.min(pointerVelocity.len(), 2)
if (velocityAtPointerUp > 0.1) {
this.editor.slideCamera({
speed: velocityAtPointerUp,
direction: pointerVelocity,
friction: CAMERA_SLIDE_FRICTION,
})
}
this.parent.transition('idle')
}

View file

@ -11,12 +11,20 @@ export class Pointing extends StateNode {
)
}
override onPointerMove: TLEventHandlers['onPointerMove'] = (info) => {
override onLongPress: TLEventHandlers['onLongPress'] = () => {
this.startDragging()
}
override onPointerMove: TLEventHandlers['onPointerMove'] = () => {
if (this.editor.inputs.isDragging) {
this.parent.transition('dragging', info)
this.startDragging()
}
}
private startDragging() {
this.parent.transition('dragging')
}
override onPointerUp: TLEventHandlers['onPointerUp'] = () => {
this.complete()
}