kopia lustrzana https://github.com/Tldraw/Tldraw
402 wiersze
9.0 KiB
TypeScript
402 wiersze
9.0 KiB
TypeScript
import type React from 'react'
|
|
import type { TLBounds, TLKeyboardInfo, TLPointerInfo } from './types'
|
|
import { Utils } from './utils'
|
|
import { Vec } from '@tldraw/vec'
|
|
|
|
const DOUBLE_CLICK_DURATION = 250
|
|
|
|
export class Inputs {
|
|
pointer?: TLPointerInfo<string>
|
|
|
|
keyboard?: TLKeyboardInfo
|
|
|
|
keys: Record<string, boolean> = {}
|
|
|
|
isPinching = false
|
|
|
|
bounds: TLBounds = {
|
|
minX: 0,
|
|
maxX: 640,
|
|
minY: 0,
|
|
maxY: 480,
|
|
width: 640,
|
|
height: 480,
|
|
}
|
|
|
|
zoom = 1
|
|
|
|
pointerUpTime = 0
|
|
|
|
activePointer?: number
|
|
|
|
pointerIsValid(e: TouchEvent | React.TouchEvent | PointerEvent | React.PointerEvent) {
|
|
if ('pointerId' in e) {
|
|
if (this.activePointer && this.activePointer !== e.pointerId) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if ('touches' in e) {
|
|
const touch = e.changedTouches[0]
|
|
if (this.activePointer && this.activePointer !== touch.identifier) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
touchStart<T extends string>(e: TouchEvent | React.TouchEvent, target: T): TLPointerInfo<T> {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const touch = e.changedTouches[0]
|
|
|
|
this.activePointer = touch.identifier
|
|
|
|
const info: TLPointerInfo<T> = {
|
|
target,
|
|
pointerId: touch.identifier,
|
|
origin: Inputs.getPoint(touch, this.bounds),
|
|
delta: [0, 0],
|
|
point: Inputs.getPoint(touch, this.bounds),
|
|
pressure: Inputs.getPressure(touch),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
touchEnd<T extends string>(e: TouchEvent | React.TouchEvent, target: T): TLPointerInfo<T> {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const touch = e.changedTouches[0]
|
|
|
|
const info: TLPointerInfo<T> = {
|
|
target,
|
|
pointerId: touch.identifier,
|
|
origin: Inputs.getPoint(touch, this.bounds),
|
|
delta: [0, 0],
|
|
point: Inputs.getPoint(touch, this.bounds),
|
|
pressure: Inputs.getPressure(touch),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
this.activePointer = undefined
|
|
|
|
return info
|
|
}
|
|
|
|
touchMove<T extends string>(e: TouchEvent | React.TouchEvent, target: T): TLPointerInfo<T> {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const touch = e.changedTouches[0]
|
|
|
|
const prev = this.pointer
|
|
|
|
const point = Inputs.getPoint(touch, this.bounds)
|
|
|
|
const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
|
|
|
|
const info: TLPointerInfo<T> = {
|
|
origin: point,
|
|
...prev,
|
|
target,
|
|
pointerId: touch.identifier,
|
|
point,
|
|
delta,
|
|
pressure: Inputs.getPressure(touch),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
pointerDown<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const point = Inputs.getPoint(e, this.bounds)
|
|
|
|
this.activePointer = e.pointerId
|
|
|
|
const info: TLPointerInfo<T> = {
|
|
target,
|
|
pointerId: e.pointerId,
|
|
origin: point,
|
|
point: point,
|
|
delta: [0, 0],
|
|
pressure: Inputs.getPressure(e),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
pointerEnter<T extends string>(
|
|
e: PointerEvent | React.PointerEvent,
|
|
target: T
|
|
): TLPointerInfo<T> {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const point = Inputs.getPoint(e, this.bounds)
|
|
|
|
const info: TLPointerInfo<T> = {
|
|
target,
|
|
pointerId: e.pointerId,
|
|
origin: point,
|
|
delta: [0, 0],
|
|
point: point,
|
|
pressure: Inputs.getPressure(e),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
pointerMove<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const prev = this.pointer
|
|
|
|
const point = Inputs.getPoint(e, this.bounds)
|
|
|
|
const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
|
|
|
|
const info: TLPointerInfo<T> = {
|
|
origin: point,
|
|
...prev,
|
|
target,
|
|
pointerId: e.pointerId,
|
|
point,
|
|
delta,
|
|
pressure: Inputs.getPressure(e),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
pointerUp<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const prev = this.pointer
|
|
|
|
const point = Inputs.getPoint(e, this.bounds)
|
|
|
|
const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
|
|
|
|
this.activePointer = undefined
|
|
|
|
const info: TLPointerInfo<T> = {
|
|
origin: point,
|
|
...prev,
|
|
target,
|
|
pointerId: e.pointerId,
|
|
point,
|
|
delta,
|
|
pressure: Inputs.getPressure(e),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
this.pointerUpTime = Date.now()
|
|
|
|
return info
|
|
}
|
|
|
|
panStart = (e: WheelEvent): TLPointerInfo<'wheel'> => {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const info: TLPointerInfo<'wheel'> = {
|
|
target: 'wheel',
|
|
pointerId: this.pointer?.pointerId || 0,
|
|
origin: this.pointer?.origin || [0, 0],
|
|
delta: [0, 0],
|
|
pressure: 0.5,
|
|
point: Inputs.getPoint(e, this.bounds),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
pan = (delta: number[], e: WheelEvent): TLPointerInfo<'wheel'> => {
|
|
if (!this.pointer || this.pointer.target !== 'wheel') {
|
|
return this.panStart(e)
|
|
}
|
|
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
const prev = this.pointer
|
|
|
|
const point = Inputs.getPoint(e, this.bounds)
|
|
|
|
const info: TLPointerInfo<'wheel'> = {
|
|
...prev,
|
|
target: 'wheel',
|
|
delta,
|
|
point,
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
isDoubleClick() {
|
|
if (!this.pointer) return false
|
|
|
|
const { origin, point } = this.pointer
|
|
|
|
const isDoubleClick =
|
|
Date.now() - this.pointerUpTime < DOUBLE_CLICK_DURATION && Vec.dist(origin, point) < 4
|
|
|
|
// Reset the active pointer, in case it got stuck
|
|
if (isDoubleClick) this.activePointer = undefined
|
|
|
|
return isDoubleClick
|
|
}
|
|
|
|
clear() {
|
|
this.pointer = undefined
|
|
}
|
|
|
|
resetDoubleClick() {
|
|
this.pointerUpTime = 0
|
|
}
|
|
|
|
keydown = (e: KeyboardEvent | React.KeyboardEvent): TLKeyboardInfo => {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
this.keys[e.key] = true
|
|
|
|
return {
|
|
point: this.pointer?.point || [0, 0],
|
|
origin: this.pointer?.origin || [0, 0],
|
|
key: e.key,
|
|
keys: Object.keys(this.keys),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
}
|
|
}
|
|
|
|
keyup = (e: KeyboardEvent | React.KeyboardEvent): TLKeyboardInfo => {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
|
|
|
delete this.keys[e.key]
|
|
|
|
return {
|
|
point: this.pointer?.point || [0, 0],
|
|
origin: this.pointer?.origin || [0, 0],
|
|
key: e.key,
|
|
keys: Object.keys(this.keys),
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
}
|
|
}
|
|
|
|
pinch(point: number[], origin: number[]) {
|
|
const { shiftKey, ctrlKey, metaKey, altKey } = this.keys
|
|
|
|
const delta = Vec.sub(origin, point)
|
|
|
|
const info: TLPointerInfo<'pinch'> = {
|
|
pointerId: 0,
|
|
target: 'pinch',
|
|
origin,
|
|
delta: delta,
|
|
point: Vec.sub(Vec.toFixed(point), [this.bounds.minX, this.bounds.minY]),
|
|
pressure: 0.5,
|
|
shiftKey,
|
|
ctrlKey,
|
|
metaKey: Utils.isDarwin() ? metaKey : ctrlKey,
|
|
altKey,
|
|
spaceKey: this.keys[' '],
|
|
}
|
|
|
|
this.pointer = info
|
|
|
|
return info
|
|
}
|
|
|
|
reset() {
|
|
this.pointerUpTime = 0
|
|
this.pointer = undefined
|
|
this.keyboard = undefined
|
|
this.activePointer = undefined
|
|
this.keys = {}
|
|
}
|
|
|
|
static getPoint(
|
|
e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent,
|
|
bounds: TLBounds
|
|
): number[] {
|
|
return [+e.clientX.toFixed(2) - bounds.minX, +e.clientY.toFixed(2) - bounds.minY]
|
|
}
|
|
|
|
static getPressure(e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent) {
|
|
return 'pressure' in e ? +e.pressure.toFixed(2) || 0.5 : 0.5
|
|
}
|
|
|
|
static commandKey(): string {
|
|
return Utils.isDarwin() ? '⌘' : 'Ctrl'
|
|
}
|
|
}
|
|
|
|
export const inputs = new Inputs()
|