|  | @@ -0,0 +1,46 @@
 | 
	
		
			
				|  |  | +import { Vec } from '@tldraw/vec'
 | 
	
		
			
				|  |  | +import { TLApp, TLMoveTool, TLShape, TLToolState } from '~lib'
 | 
	
		
			
				|  |  | +import type { TLEventInfo, TLEventMap, TLEvents } from '~types'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +type GestureInfo<
 | 
	
		
			
				|  |  | +  S extends TLShape,
 | 
	
		
			
				|  |  | +  K extends TLEventMap,
 | 
	
		
			
				|  |  | +  E extends TLEventInfo<S> = TLEventInfo<S>
 | 
	
		
			
				|  |  | +> = {
 | 
	
		
			
				|  |  | +  info: E & { delta: number[]; point: number[]; offset: number[] }
 | 
	
		
			
				|  |  | +  event: K['wheel'] | K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export class PinchingState<
 | 
	
		
			
				|  |  | +  S extends TLShape,
 | 
	
		
			
				|  |  | +  K extends TLEventMap,
 | 
	
		
			
				|  |  | +  R extends TLApp<S, K>,
 | 
	
		
			
				|  |  | +  P extends TLMoveTool<S, K, R>
 | 
	
		
			
				|  |  | +> extends TLToolState<S, K, R, P> {
 | 
	
		
			
				|  |  | +  static id = 'pinching'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private origin: number[] = [0, 0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private prevDelta: number[] = [0, 0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private pinchCamera(point: number[], delta: number[], zoom: number) {
 | 
	
		
			
				|  |  | +    const { camera } = this.app.viewport
 | 
	
		
			
				|  |  | +    const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom))
 | 
	
		
			
				|  |  | +    const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint)
 | 
	
		
			
				|  |  | +    const p1 = Vec.sub(Vec.div(point, zoom), nextPoint)
 | 
	
		
			
				|  |  | +    this.app.setCamera(Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom)
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  onEnter = (info: GestureInfo<S, K>) => {
 | 
	
		
			
				|  |  | +    this.prevDelta = info.info.delta
 | 
	
		
			
				|  |  | +    this.origin = info.info.point
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  onPinch: TLEvents<S>['pinch'] = info => {
 | 
	
		
			
				|  |  | +    this.pinchCamera(info.point, [0, 0], info.offset[0])
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  onPinchEnd: TLEvents<S>['pinch'] = () => {
 | 
	
		
			
				|  |  | +    this.tool.transition('idle')
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 |