ue-too
Version:
pan, zoom, and rotate your html canvas
1 lines • 57.1 kB
JavaScript
import{TemplateState as TemplateState$1,TemplateStateMachine as TemplateStateMachine$1}from"../being/interfaces";import{PointCal}from"point2point";import{Observable as Observable$1}from"../utils/observable";import{convertDeltaInViewPortToWorldSpace}from"../board-camera/utils";const NO_OP=()=>{};class TemplateStateMachine{constructor(states,initialState,context){this._timeouts=void 0,this._states=states,this._currentState=initialState,this._context=context,this._statesArray=Object.keys(states),this._stateChangeCallbacks=[],this._happensCallbacks=[]}switchTo(state){this._currentState=state}happens(event,payload){this._timeouts&&clearTimeout(this._timeouts),this._happensCallbacks.forEach((callback=>callback(event,payload,this._context)));const nextState=this._states[this._currentState].handles(event,payload,this._context,this);if(void 0!==nextState&&nextState!==this._currentState){const originalState=this._currentState;this._states[this._currentState].beforeExit(this._context,this,nextState),this.switchTo(nextState),this._states[this._currentState].uponEnter(this._context,this,originalState),this._stateChangeCallbacks.forEach((callback=>callback(originalState,this._currentState)))}return nextState}onStateChange(callback){this._stateChangeCallbacks.push(callback)}onHappens(callback){this._happensCallbacks.push(callback)}get currentState(){return this._currentState}setContext(context){this._context=context}get possibleStates(){return this._statesArray}get states(){return this._states}}class TemplateState{constructor(){this._guards={},this._eventGuards={},this._delay=void 0}get guards(){return this._guards}get eventGuards(){return this._eventGuards}get delay(){return this._delay}uponEnter(context,stateMachine,from){}beforeExit(context,stateMachine,to){}handles(event,payload,context,stateMachine){if(this.eventReactions[event]){this.eventReactions[event].action(context,payload,stateMachine);const targetState=this.eventReactions[event].defaultTargetState,guardToEvaluate=this._eventGuards[event];if(guardToEvaluate){const target=guardToEvaluate.find((guard=>!!this.guards[guard.guard]&&this.guards[guard.guard](context)));return target?target.target:targetState}return targetState}}}class Observable{constructor(){this.observers=[]}subscribe(observer,options){if(this.observers.push(observer),null==options?void 0:options.signal){if(options.signal.aborted)return this.observers=this.observers.filter((o=>o!==observer)),()=>{};const abortHandler=()=>{var _a;this.observers=this.observers.filter((o=>o!==observer)),null===(_a=options.signal)||void 0===_a||_a.removeEventListener("abort",abortHandler)};options.signal.addEventListener("abort",abortHandler)}return()=>{this.observers=this.observers.filter((o=>o!==observer))}}notify(...data){this.observers.forEach((observer=>queueMicrotask((()=>observer(...data)))))}}class CanvasPositionDimensionPublisher{constructor(canvas){this._observers=new Observable,this.lastRect=canvas.getBoundingClientRect(),this.resizeObserver=new ResizeObserver((entries=>{for(const entry of entries){const trueRect=getTrueRect(entry.target.getBoundingClientRect(),window.getComputedStyle(entry.target));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}})),this.intersectionObserver=new IntersectionObserver((entries=>{for(const entry of entries)if(entry.isIntersecting){const trueRect=getTrueRect(entry.boundingClientRect,window.getComputedStyle(entry.target));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}})),this.scrollHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),this.resizeHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),this.resizeObserver.observe(canvas),this.intersectionObserver.observe(canvas),window.addEventListener("scroll",this.scrollHandler,{passive:!0}),window.addEventListener("resize",this.resizeHandler,{passive:!0})}dispose(){this.resizeObserver.disconnect(),this.intersectionObserver.disconnect(),window.removeEventListener("scroll",this.scrollHandler),window.removeEventListener("resize",this.resizeHandler)}attach(canvas){this.dispose(),this.resizeObserver.observe(canvas),this.intersectionObserver.observe(canvas),this.scrollHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),this.resizeHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),window.addEventListener("scroll",this.scrollHandler,{passive:!0}),window.addEventListener("resize",this.resizeHandler,{passive:!0})}publishPositionUpdate(rect){this._observers.notify(rect)}onPositionUpdate(observer,options){this._observers.subscribe(observer,options)}}function getTrueRect(rect,computedStyle){const paddingLeft=parseFloat(computedStyle.paddingLeft),paddingTop=parseFloat(computedStyle.paddingTop),paddingRight=parseFloat(computedStyle.paddingRight),paddingBottom=parseFloat(computedStyle.paddingBottom),borderLeft=parseFloat(computedStyle.borderLeftWidth),borderTop=parseFloat(computedStyle.borderTopWidth),borderRight=parseFloat(computedStyle.borderRightWidth),borderBottom=parseFloat(computedStyle.borderBottomWidth),trueLeft=rect.left+paddingLeft+borderLeft,trueTop=rect.top+paddingTop+borderTop,trueWidth=rect.width-paddingLeft-paddingRight-borderLeft-borderRight,trueHeight=rect.height-paddingTop-paddingBottom-borderTop-borderBottom;return new DOMRect(trueLeft,trueTop,trueWidth,trueHeight)}function rectChanged(r1,r2){return r1.top!==r2.top||r1.left!==r2.left||r1.width!==r2.width||r1.height!==r2.height}class DummyCanvasOperator{constructor(){this.width=0,this.height=0,this.position={x:0,y:0},this.setCursor=NO_OP}}class CanvasCacheInWebWorker{constructor(postMessageFunction){this._width=0,this._height=0,this._position={x:0,y:0},this._postMessageFunction=postMessageFunction}set width(width){this._width=width}set height(height){this._height=height}set position(position){this._position=position}get width(){return this._width}get height(){return this._height}get position(){return this._position}setCursor(style){this._postMessageFunction({type:"setCursor",style:style})}}class CanvasProxy{constructor(canvas,canvasPositionDimensionPublisher=new CanvasPositionDimensionPublisher(canvas)){const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));this._width=trueRect.width,this._height=trueRect.height,this._position={x:trueRect.left,y:trueRect.top},this._canvas=canvas,this._canvasPositionDimensionPublisher=canvasPositionDimensionPublisher,this._canvasPositionDimensionPublisher.onPositionUpdate((rect=>{this._width=rect.width,this._height=rect.height,this._position={x:rect.left,y:rect.top}}))}get width(){return this._width}get height(){return this._height}get position(){return this._position}setCursor(style){this._canvas.style.cursor=style}attach(canvas){this._canvasPositionDimensionPublisher.attach(canvas),this._canvas=canvas;const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));this._width=trueRect.width,this._height=trueRect.height,this._position={x:trueRect.left,y:trueRect.top}}}class CanvasProxyWorkerRelay{constructor(canvas,webWorker,canvasDiemsionPublisher){const boundingRect=canvas.getBoundingClientRect();this._canvas=canvas,this._webWorker=webWorker;const trueRect=getTrueRect(boundingRect,window.getComputedStyle(canvas));this._width=trueRect.width,this._height=trueRect.height,this._position={x:trueRect.left,y:trueRect.top},this._webWorker.postMessage({type:"setCanvasDimensions",width:boundingRect.width,height:boundingRect.height,position:{x:boundingRect.left,y:boundingRect.top}}),canvasDiemsionPublisher.onPositionUpdate((rect=>{this._width=rect.width,this._height=rect.height,this._position={x:rect.left,y:rect.top},this._webWorker.postMessage({type:"updateCanvasDimensions",width:rect.width,height:rect.height,position:{x:rect.left,y:rect.top}})}))}get width(){return this._width}get height(){return this._height}get position(){return this._position}setCursor(style){this._canvas.style.cursor=style}}class DummyKmtInputContext{constructor(){this.alignCoordinateSystem=!1,this.canvas=new DummyCanvasOperator,this.initialCursorPosition={x:0,y:0}}notifyOnPan(delta){}notifyOnZoom(zoomAmount,anchorPoint){}notifyOnRotate(deltaRotation){}setInitialCursorPosition(position){}cleanup(){}setup(){}}class ObservableInputTracker{constructor(canvasOperator,inputPublisher){this._alignCoordinateSystem=!0,this._canvasOperator=canvasOperator,this._inputPublisher=inputPublisher,this._initialCursorPosition={x:0,y:0}}get alignCoordinateSystem(){return this._alignCoordinateSystem}get canvas(){return this._canvasOperator}get initialCursorPosition(){return this._initialCursorPosition}set alignCoordinateSystem(value){this._alignCoordinateSystem=value}notifyOnPan(delta){this._inputPublisher.notifyPan(delta)}notifyOnZoom(zoomAmount,anchorPoint){this._inputPublisher.notifyZoom(zoomAmount,anchorPoint)}notifyOnRotate(deltaRotation){this._inputPublisher.notifyRotate(deltaRotation)}setInitialCursorPosition(position){this._initialCursorPosition=position}cleanup(){}setup(){}}function convertFromWindow2ViewPort(point,canvas){const canvasBoundingRect=canvas.getBoundingClientRect(),cameraCenterInWindow={x:canvasBoundingRect.left+(canvasBoundingRect.right-canvasBoundingRect.left)/2,y:canvasBoundingRect.top+(canvasBoundingRect.bottom-canvasBoundingRect.top)/2};return PointCal.subVector(point,cameraCenterInWindow)}function convertFromWindow2ViewPortWithCanvasOperator(point,canvasOperator){const cameraCenterInWindow={x:canvasOperator.position.x+canvasOperator.width/2,y:canvasOperator.position.y+canvasOperator.height/2};return PointCal.subVector(point,cameraCenterInWindow)}function convertFromWindow2ViewPortCanvasOperator(point,canvasOperator){const cameraCenterInWindow={x:canvasOperator.position.x+canvasOperator.width/2,y:canvasOperator.position.y+canvasOperator.height/2};return PointCal.subVector(point,cameraCenterInWindow)}class KmtIdleState extends TemplateState$1{constructor(){super(),this._guards={isIdle:()=>!0},this._eventGuards={},this._eventReactions={spacebarDown:{action:this.spacebarDownHandler,defaultTargetState:"READY_TO_PAN_VIA_SPACEBAR"},scroll:{action:this.scrollHandler,defaultTargetState:"IDLE"},scrollWithCtrl:{action:this.scrollWithCtrlHandler,defaultTargetState:"IDLE"},middlePointerDown:{action:this.middlePointerDownHandler,defaultTargetState:"READY_TO_PAN_VIA_SCROLL_WHEEL"}}}get eventReactions(){return this._eventReactions}scrollHandler(context,payload){const delta=Object.assign({},payload);context.alignCoordinateSystem||(delta.deltaY=-delta.deltaY),context.notifyOnPan({x:delta.deltaX,y:delta.deltaY})}scrollWithCtrlHandler(context,payload){let scrollSensitivity=.005;Math.abs(payload.deltaY)>100&&(scrollSensitivity=5e-4);const zoomAmount=payload.deltaY*scrollSensitivity,anchorPoint=convertFromWindow2ViewPortCanvasOperator({x:payload.x,y:payload.y},context.canvas);context.alignCoordinateSystem||(anchorPoint.y=-anchorPoint.y),context.notifyOnZoom(-5*zoomAmount,anchorPoint)}spacebarDownHandler(context,payload){context.canvas.setCursor("grab")}middlePointerDownHandler(context,payload){context.setInitialCursorPosition({x:payload.x,y:payload.y}),context.canvas.setCursor("grabbing")}}class ReadyToSelectState extends TemplateState$1{constructor(){super(),this.leftPointerMove=((context,payload)=>{const viewportPoint=convertFromWindow2ViewPort({x:payload.x,y:payload.y},context.canvas);context.setSelectionEndPoint(viewportPoint),context.toggleSelectionBox(!0)}).bind(this),this._eventReactions={leftPointerUp:{action:()=>"IDLE",defaultTargetState:"IDLE"},leftPointerMove:{action:this.leftPointerMove,defaultTargetState:"SELECTING"}}}get eventReactions(){return this._eventReactions}}class ReadyToPanViaSpaceBarState extends TemplateState$1{constructor(){super(),this._eventReactions={spacebarUp:{action:this.spacebarUpHandler,defaultTargetState:"IDLE"},leftPointerDown:{action:this.leftPointerDownHandler,defaultTargetState:"INITIAL_PAN"}}}get eventReactions(){return this._eventReactions}leftPointerDownHandler(context,payload){context.setInitialCursorPosition({x:payload.x,y:payload.y}),context.canvas.setCursor("grabbing")}spacebarUpHandler(context,payload){context.canvas.setCursor("default")}}class InitialPanState extends TemplateState$1{constructor(){super(),this._eventReactions={leftPointerUp:{action:this.leftPointerUpHandler,defaultTargetState:"READY_TO_PAN_VIA_SPACEBAR"},leftPointerMove:{action:this.leftPointerMoveHandler,defaultTargetState:"PAN"},spacebarUp:{action:()=>"IDLE",defaultTargetState:"IDLE"},leftPointerDown:{action:()=>"PAN",defaultTargetState:"PAN"}}}get eventReactions(){return this._eventReactions}leftPointerMoveHandler(context,payload){const delta={x:context.initialCursorPosition.x-payload.x,y:context.initialCursorPosition.y-payload.y};context.alignCoordinateSystem||(delta.y=-delta.y),context.notifyOnPan(delta),context.setInitialCursorPosition({x:payload.x,y:payload.y})}leftPointerUpHandler(context,payload){context.canvas.setCursor("grab")}}class ReadyToPanViaScrollWheelState extends TemplateState$1{constructor(){super(),this._eventReactions={middlePointerUp:{action:this.middlePointerUpHandler,defaultTargetState:"IDLE"},middlePointerMove:{action:this.middlePointerMoveHandler,defaultTargetState:"PAN_VIA_SCROLL_WHEEL"}}}get eventReactions(){return this._eventReactions}middlePointerMoveHandler(context,payload){context.canvas.setCursor("grabbing")}middlePointerUpHandler(context,payload){context.canvas.setCursor("default")}}class PanState extends TemplateState$1{constructor(){super(),this._eventReactions={leftPointerUp:{action:this.leftPointerUpHandler,defaultTargetState:"READY_TO_PAN_VIA_SPACEBAR"},leftPointerMove:{action:this.leftPointerMoveHandler,defaultTargetState:"PAN"},spacebarUp:{action:this.spacebarUpHandler,defaultTargetState:"IDLE"}}}get eventReactions(){return this._eventReactions}leftPointerMoveHandler(context,payload){const delta={x:context.initialCursorPosition.x-payload.x,y:context.initialCursorPosition.y-payload.y};context.alignCoordinateSystem||(delta.y=-delta.y),context.notifyOnPan(delta),context.setInitialCursorPosition({x:payload.x,y:payload.y})}spacebarUpHandler(context,payload){context.canvas.setCursor("default")}leftPointerUpHandler(context,payload){context.canvas.setCursor("grab")}}class PanViaScrollWheelState extends TemplateState$1{constructor(){super(...arguments),this._eventReactions={middlePointerUp:{action:this.middlePointerUpHandler,defaultTargetState:"IDLE"},middlePointerMove:{action:this.middlePointerMoveHandler,defaultTargetState:"PAN_VIA_SCROLL_WHEEL"}}}get eventReactions(){return this._eventReactions}middlePointerMoveHandler(context,payload){const delta={x:context.initialCursorPosition.x-payload.x,y:context.initialCursorPosition.y-payload.y};context.alignCoordinateSystem||(delta.y=-delta.y),context.notifyOnPan(delta),context.setInitialCursorPosition({x:payload.x,y:payload.y})}middlePointerUpHandler(context,payload){context.canvas.setCursor("default")}}class KmtEmptyState extends TemplateState$1{constructor(){super()}get eventReactions(){return{}}}function createKmtInputStateMachine(context){const states={IDLE:new KmtIdleState,READY_TO_PAN_VIA_SPACEBAR:new ReadyToPanViaSpaceBarState,INITIAL_PAN:new InitialPanState,PAN:new PanState,READY_TO_PAN_VIA_SCROLL_WHEEL:new ReadyToPanViaScrollWheelState,PAN_VIA_SCROLL_WHEEL:new PanViaScrollWheelState};return new TemplateStateMachine$1(states,"IDLE",context)}class KmtInputStateMachineWebWorkerProxy extends TemplateStateMachine$1{constructor(webworker){super({IDLE:new KmtEmptyState,READY_TO_PAN_VIA_SPACEBAR:new KmtEmptyState,INITIAL_PAN:new KmtEmptyState,PAN:new KmtEmptyState,READY_TO_PAN_VIA_SCROLL_WHEEL:new KmtEmptyState,PAN_VIA_SCROLL_WHEEL:new KmtEmptyState},"IDLE",new DummyKmtInputContext),this._webworker=webworker}happens(event,payload){return this._webworker.postMessage({type:"kmtInputStateMachine",event:event,payload:payload}),"IDLE"}}class IdleState extends TemplateState{constructor(){super(...arguments),this._eventReactions={touchstart:{action:this.touchstart,defaultTargetState:"IDLE"},touchend:{action:this.touchend,defaultTargetState:"IDLE"}},this._guards={touchPointsCount:(context=>2===context.getCurrentTouchPointsCount()).bind(this)},this._eventGuards={touchstart:[{guard:"touchPointsCount",target:"PENDING"}],touchend:[{guard:"touchPointsCount",target:"PENDING"}]}}get eventReactions(){return this._eventReactions}touchstart(context,payload){context.addTouchPoints(payload.points)}touchend(context,payload){context.removeTouchPoints(payload.points.map((p=>p.ident)))}}class PendingState extends TemplateState{constructor(){super(...arguments),this._eventReactions={touchstart:{action:this.touchstart,defaultTargetState:"IDLE"},touchend:{action:this.touchend,defaultTargetState:"IDLE"},touchmove:{action:this.touchmove,defaultTargetState:"IN_PROGRESS"}}}get eventReactions(){return this._eventReactions}touchstart(context,payload){context.addTouchPoints(payload.points)}touchend(context,payload){context.removeTouchPoints(payload.points.map((p=>p.ident)))}touchmove(context,payload){const idents=payload.points.map((p=>p.ident)),initialPositions=context.getInitialTouchPointsPositions(idents),currentPositions=payload.points,initialStartAndEndDistance=PointCal.distanceBetweenPoints(initialPositions[0],initialPositions[1]),currentStartAndEndDistance=PointCal.distanceBetweenPoints(currentPositions[0],currentPositions[1]),midPoint=PointCal.linearInterpolation(initialPositions[0],initialPositions[1],.5),currentMidPoint=PointCal.linearInterpolation(currentPositions[0],currentPositions[1],.5),midPointDelta=PointCal.subVector(midPoint,currentMidPoint),cameraCenterInWindow={x:context.canvas.position.x+context.canvas.width/2,y:context.canvas.position.y+context.canvas.height/2},midPointInViewPort=PointCal.subVector(midPoint,cameraCenterInWindow);let panZoom=Math.abs(currentStartAndEndDistance-initialStartAndEndDistance)>PointCal.distanceBetweenPoints(midPoint,currentMidPoint)?"ZOOMING":"PANNING";switch(context.updateTouchPoints(currentPositions),panZoom){case"ZOOMING":context.notifyOnZoom(.005*(currentStartAndEndDistance-initialStartAndEndDistance),midPointInViewPort);break;case"PANNING":context.notifyOnPan(midPointDelta);break;default:console.warn("Unknown panZoom state",panZoom)}}}class InProgressState extends TemplateState{constructor(){super(...arguments),this._eventReactions={touchmove:{action:this.touchmove,defaultTargetState:"IN_PROGRESS"},touchend:{action:this.touchend,defaultTargetState:"IDLE"},touchstart:{action:()=>"IDLE",defaultTargetState:"IDLE"}}}get eventReactions(){return this._eventReactions}touchmove(context,payload){const idents=payload.points.map((p=>p.ident)),initialPositions=context.getInitialTouchPointsPositions(idents),currentPositions=payload.points,initialStartAndEndDistance=PointCal.distanceBetweenPoints(initialPositions[0],initialPositions[1]),currentStartAndEndDistance=PointCal.distanceBetweenPoints(currentPositions[0],currentPositions[1]),midPoint=PointCal.linearInterpolation(initialPositions[0],initialPositions[1],.5),currentMidPoint=PointCal.linearInterpolation(currentPositions[0],currentPositions[1],.5),midPointDelta=PointCal.subVector(midPoint,currentMidPoint),cameraCenterInWindow={x:context.canvas.position.x+context.canvas.width/2,y:context.canvas.position.y+context.canvas.height/2},midPointInViewPort=PointCal.subVector(midPoint,cameraCenterInWindow);let panZoom=Math.abs(currentStartAndEndDistance-initialStartAndEndDistance)>PointCal.distanceBetweenPoints(midPoint,currentMidPoint)?"ZOOMING":"PANNING";switch(context.updateTouchPoints(currentPositions),panZoom){case"ZOOMING":context.alignCoordinateSystem||(midPointInViewPort.y=-midPointInViewPort.y),context.notifyOnZoom(.005*-(initialStartAndEndDistance-currentStartAndEndDistance),midPointInViewPort);break;case"PANNING":context.alignCoordinateSystem||(midPointDelta.y=-midPointDelta.y),context.notifyOnPan(midPointDelta);break;default:console.warn("Unknown panZoom state",panZoom)}}touchend(context,payload){context.removeTouchPoints(payload.points.map((p=>p.ident)))}}function createTouchInputStateMachine(context){return new TemplateStateMachine({IDLE:new IdleState,PENDING:new PendingState,IN_PROGRESS:new InProgressState},"IDLE",context)}class TouchInputTracker{constructor(canvas,inputPublisher){this._touchPointsMap=new Map,this._canvas=canvas,this._inputPublisher=inputPublisher,this._alignCoordinateSystem=!0}addTouchPoints(points){points.forEach((point=>{this._touchPointsMap.set(point.ident,Object.assign({},point))}))}removeTouchPoints(identifiers){identifiers.forEach((ident=>{this._touchPointsMap.has(ident)&&this._touchPointsMap.delete(ident)}))}getCurrentTouchPointsCount(){return this._touchPointsMap.size}getInitialTouchPointsPositions(idents){const res=[];return idents.forEach((ident=>{if(this._touchPointsMap.has(ident)){const point=this._touchPointsMap.get(ident);point&&res.push(point)}})),res}updateTouchPoints(pointsMoved){pointsMoved.forEach((point=>{this._touchPointsMap.has(point.ident)&&this._touchPointsMap.set(point.ident,Object.assign({},point))}))}notifyOnPan(delta){this._inputPublisher.notifyPan(delta)}notifyOnZoom(zoomAmount,anchorPoint){this._inputPublisher.notifyZoom(zoomAmount,anchorPoint)}get alignCoordinateSystem(){return this._alignCoordinateSystem}set alignCoordinateSystem(value){this._alignCoordinateSystem=value}get canvas(){return this._canvas}cleanup(){}setup(){}}class VanillaKMTEventParser{constructor(canvas,kmtInputStateMachine){this._canvas=canvas,this.bindFunctions(),this._abortController=new AbortController,this._stateMachine=kmtInputStateMachine,this._keyfirstPressed=new Map}get disabled(){return this._disabled}set disabled(value){this._disabled=value}get stateMachine(){return this._stateMachine}addEventListeners(signal){this._canvas.addEventListener("pointerdown",this.pointerDownHandler,{signal:signal}),this._canvas.addEventListener("pointerup",this.pointerUpHandler,{signal:signal}),this._canvas.addEventListener("pointermove",this.pointerMoveHandler,{signal:signal}),this._canvas.addEventListener("wheel",this.scrollHandler,{signal:signal}),window.addEventListener("keydown",this.keypressHandler,{signal:signal}),window.addEventListener("keyup",this.keyupHandler,{signal:signal})}setUp(){this.addEventListeners(this._abortController.signal)}tearDown(){this._abortController.abort(),this._abortController=new AbortController}bindFunctions(){this.pointerDownHandler=this.pointerDownHandler.bind(this),this.pointerUpHandler=this.pointerUpHandler.bind(this),this.pointerMoveHandler=this.pointerMoveHandler.bind(this),this.scrollHandler=this.scrollHandler.bind(this),this.keypressHandler=this.keypressHandler.bind(this),this.keyupHandler=this.keyupHandler.bind(this)}pointerDownHandler(e){this._disabled||(0!==e.button||"mouse"!==e.pointerType?1!==e.button||"mouse"!==e.pointerType||this.stateMachine.happens("middlePointerDown",{x:e.clientX,y:e.clientY}):this.stateMachine.happens("leftPointerDown",{x:e.clientX,y:e.clientY}))}pointerUpHandler(e){this._disabled||(0!==e.button||"mouse"!==e.pointerType?1!==e.button||"mouse"!==e.pointerType||this.stateMachine.happens("middlePointerUp",{x:e.clientX,y:e.clientY}):this.stateMachine.happens("leftPointerUp",{x:e.clientX,y:e.clientY}))}pointerMoveHandler(e){this._disabled||(1!==e.buttons||"mouse"!==e.pointerType?4!==e.buttons||"mouse"!==e.pointerType||this.stateMachine.happens("middlePointerMove",{x:e.clientX,y:e.clientY}):this.stateMachine.happens("leftPointerMove",{x:e.clientX,y:e.clientY}))}scrollHandler(e){this._disabled||(e.preventDefault(),e.ctrlKey?this.stateMachine.happens("scrollWithCtrl",{x:e.clientX,y:e.clientY,deltaX:e.deltaX,deltaY:e.deltaY}):this.stateMachine.happens("scroll",{deltaX:e.deltaX,deltaY:e.deltaY}))}keypressHandler(e){this._keyfirstPressed.has(e.key)||(this._keyfirstPressed.set(e.key,!0)," "===e.key&&(e.preventDefault(),this.stateMachine.happens("spacebarDown",{})))}keyupHandler(e){this._keyfirstPressed.has(e.key)&&this._keyfirstPressed.delete(e.key)," "===e.key&&this.stateMachine.happens("spacebarUp",{})}attach(canvas){this.tearDown(),this._canvas=canvas,this.setUp()}}class VanillaTouchEventParser{constructor(canvas,touchInputStateMachine){this._panDisabled=!1,this._zoomDisabled=!1,this._rotateDisabled=!1,this._canvas=canvas,this._disabled=!1,this.touchSM=touchInputStateMachine,this._abortController=new AbortController,this.bindListeners()}get touchStateMachine(){return this.touchSM}bindListeners(){this.touchstartHandler=this.touchstartHandler.bind(this),this.touchendHandler=this.touchendHandler.bind(this),this.touchcancelHandler=this.touchcancelHandler.bind(this),this.touchmoveHandler=this.touchmoveHandler.bind(this)}enableStrategy(){this._disabled=!1}disableStrategy(){this._disabled=!0}setUp(){this._canvas.addEventListener("touchstart",this.touchstartHandler,{signal:this._abortController.signal}),this._canvas.addEventListener("touchend",this.touchendHandler,{signal:this._abortController.signal}),this._canvas.addEventListener("touchcancel",this.touchcancelHandler,{signal:this._abortController.signal}),this._canvas.addEventListener("touchmove",this.touchmoveHandler,{signal:this._abortController.signal})}tearDown(){this._abortController.abort(),this._abortController=new AbortController}get disabled(){return this._disabled}get alignCoordinateSystem(){return this._touchInputTracker.alignCoordinateSystem}set alignCoordinateSystem(alignCoordinateSystem){this._touchInputTracker.alignCoordinateSystem=alignCoordinateSystem}get panDisabled(){return this._panDisabled}set panDisabled(panDisabled){this._panDisabled=panDisabled}get zoomDisabled(){return this._zoomDisabled}set zoomDisabled(zoomDisabled){this._zoomDisabled=zoomDisabled}get rotateDisabled(){return this._rotateDisabled}set rotateDisabled(rotateDisabled){this._rotateDisabled=rotateDisabled}touchstartHandler(e){if(this._disabled)return;const pointsAdded=[];for(let i=0;i<e.changedTouches.length;i++)pointsAdded.push({ident:e.changedTouches[i].identifier,x:e.changedTouches[i].clientX,y:e.changedTouches[i].clientY});this.touchSM.happens("touchstart",{points:pointsAdded}),e.preventDefault()}touchcancelHandler(e){if(this._disabled)return;const pointsRemoved=[];for(let i=0;i<e.changedTouches.length;i++)pointsRemoved.push({ident:e.changedTouches[i].identifier,x:e.changedTouches[i].clientX,y:e.changedTouches[i].clientY});this.touchSM.happens("touchend",{points:pointsRemoved})}touchendHandler(e){if(this._disabled)return;const pointsRemoved=[];for(let i=0;i<e.changedTouches.length;i++)pointsRemoved.push({ident:e.changedTouches[i].identifier,x:e.changedTouches[i].clientX,y:e.changedTouches[i].clientY});this.touchSM.happens("touchend",{points:pointsRemoved})}touchmoveHandler(e){if(this._disabled)return;e.preventDefault();const pointsMoved=[];for(let i=0;i<e.targetTouches.length;i++)pointsMoved.push({ident:e.targetTouches[i].identifier,x:e.targetTouches[i].clientX,y:e.targetTouches[i].clientY});this.touchSM.happens("touchmove",{points:pointsMoved})}attach(canvas){this.tearDown(),this._canvas=canvas,this.setUp()}}function createHandlerChain(...handlers){const normalizedHandlers=Array.isArray(handlers[0])?handlers[0]:handlers;return(value,...args)=>normalizedHandlers.reduce(((acc,handler)=>handler(acc,...args)),value)}function convert2WorldSpaceWRT(targetPosition,interestPoint,viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation){let cameraFrameCenter={x:viewPortWidth/2,y:viewPortHeight/2},delta2Point=PointCal.subVector(interestPoint,cameraFrameCenter);return delta2Point=PointCal.multiplyVectorByScalar(delta2Point,1/cameraZoomLevel),delta2Point=PointCal.rotatePoint(delta2Point,cameraRotation),PointCal.addVector(targetPosition,delta2Point)}function convert2WorldSpaceAnchorAtCenter(point,cameraPosition,cameraZoomLevel,cameraRotation){const scaledBack=PointCal.multiplyVectorByScalar(point,1/cameraZoomLevel),rotatedBack=PointCal.rotatePoint(scaledBack,cameraRotation);return PointCal.addVector(rotatedBack,cameraPosition)}function convert2ViewPortSpaceAnchorAtCenter(point,cameraPosition,cameraZoomLevel,cameraRotation){const withOffset=PointCal.subVector(point,cameraPosition),scaled=PointCal.multiplyVectorByScalar(withOffset,cameraZoomLevel);return PointCal.rotatePoint(scaled,-cameraRotation)}function withinBoundaries(point,boundaries){if(null==boundaries)return!0;let leftSide=!1,rightSide=!1,topSide=!1,bottomSide=!1;return(null==boundaries.max||null==boundaries.max.x||point.x<=boundaries.max.x)&&(rightSide=!0),(null==boundaries.min||null==boundaries.min.x||point.x>=boundaries.min.x)&&(leftSide=!0),(null==boundaries.max||null==boundaries.max.y||point.y<=boundaries.max.y)&&(topSide=!0),(null==boundaries.min||null==boundaries.min.y||point.y>=boundaries.min.y)&&(bottomSide=!0),leftSide&&rightSide&&topSide&&bottomSide}function clampPoint(point,boundaries){if(withinBoundaries(point,boundaries)||null==boundaries)return point;let manipulatePoint={x:point.x,y:point.y},limit=boundaries.min;return null!=limit&&(null!=limit.x&&(manipulatePoint.x=Math.max(manipulatePoint.x,limit.x)),null!=limit.y&&(manipulatePoint.y=Math.max(manipulatePoint.y,limit.y))),limit=boundaries.max,null!=limit&&(null!=limit.x&&(manipulatePoint.x=Math.min(manipulatePoint.x,limit.x)),null!=limit.y&&(manipulatePoint.y=Math.min(manipulatePoint.y,limit.y))),manipulatePoint}function clampPointEntireViewPort(point,viewPortWidth,viewPortHeight,boundaries,cameraZoomLevel,cameraRotation){if(null==boundaries)return point;let topLeftCorner=convert2WorldSpaceWRT(point,{x:0,y:viewPortHeight},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),bottomLeftCorner=convert2WorldSpaceWRT(point,{x:0,y:0},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),topRightCorner=convert2WorldSpaceWRT(point,{x:viewPortWidth,y:viewPortHeight},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),bottomRightCorner=convert2WorldSpaceWRT(point,{x:viewPortWidth,y:0},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),topLeftCornerClamped=clampPoint(topLeftCorner,boundaries),topRightCornerClamped=clampPoint(topRightCorner,boundaries),bottomLeftCornerClamped=clampPoint(bottomLeftCorner,boundaries),bottomRightCornerClamped=clampPoint(bottomRightCorner,boundaries),diffs=[PointCal.subVector(topLeftCornerClamped,topLeftCorner),PointCal.subVector(topRightCornerClamped,topRightCorner),PointCal.subVector(bottomLeftCornerClamped,bottomLeftCorner),PointCal.subVector(bottomRightCornerClamped,bottomRightCorner)],maxXDiff=Math.abs(diffs[0].x),maxYDiff=Math.abs(diffs[0].y),delta=diffs[0];return diffs.forEach((diff=>{Math.abs(diff.x)>maxXDiff&&(maxXDiff=Math.abs(diff.x),delta.x=diff.x),Math.abs(diff.y)>maxYDiff&&(maxYDiff=Math.abs(diff.y),delta.y=diff.y)})),PointCal.addVector(point,delta)}function restrictPanToHandler(destination,camera,config){let delta=PointCal.subVector(destination,camera.position);if(delta=convertDeltaToComplyWithRestriction(delta,camera,config),0===delta.x&&0===delta.y)return destination;return PointCal.addVector(camera.position,delta)}function restrictPanByHandler(delta,camera,config){return delta=convertDeltaToComplyWithRestriction(delta,camera,config)}function clampToHandler(destination,camera,config){if(!config.clampTranslation)return destination;let actualDest=clampPoint(destination,camera.boundaries);return config.limitEntireViewPort&&(actualDest=clampPointEntireViewPort(destination,camera.viewPortWidth,camera.viewPortHeight,camera.boundaries,camera.zoomLevel,camera.rotation)),actualDest}function clampByHandler(delta,camera,config){if(!config.clampTranslation)return delta;let actualDelta=PointCal.subVector(clampPoint(PointCal.addVector(camera.position,delta),camera.boundaries),camera.position);return config.limitEntireViewPort&&(actualDelta=PointCal.subVector(clampPointEntireViewPort(PointCal.addVector(camera.position,delta),camera.viewPortWidth,camera.viewPortHeight,camera.boundaries,camera.zoomLevel,camera.rotation),camera.position)),actualDelta}function convertDeltaToComplyWithRestriction(delta,camera,config){if(config.restrictXTranslation&&config.restrictYTranslation)return{x:0,y:0};if(config.restrictRelativeXTranslation&&config.restrictRelativeYTranslation)return{x:0,y:0};if(config.restrictXTranslation&&(delta.x=0),config.restrictYTranslation&&(delta.y=0),config.restrictRelativeXTranslation){const upDirection=PointCal.rotatePoint({x:0,y:1},camera.rotation),value=PointCal.dotProduct(upDirection,delta);delta=PointCal.multiplyVectorByScalar(upDirection,value)}if(config.restrictRelativeYTranslation){const rightDirection=PointCal.rotatePoint({x:1,y:0},camera.rotation),value=PointCal.dotProduct(rightDirection,delta);delta=PointCal.multiplyVectorByScalar(rightDirection,value)}return delta}function clampZoomLevel(zoomLevel,zoomLevelLimits){return zoomLevelWithinLimits(zoomLevel,zoomLevelLimits)||void 0===zoomLevelLimits||(zoomLevelLimits.max&&(zoomLevel=Math.min(zoomLevelLimits.max,zoomLevel)),zoomLevelLimits.min&&(zoomLevel=Math.max(zoomLevelLimits.min,zoomLevel))),zoomLevel}function zoomLevelWithinLimits(zoomLevel,zoomLevelLimits){return void 0===zoomLevelLimits||!(zoomLevel<=0||void 0!==zoomLevelLimits&&(void 0!==zoomLevelLimits.max&&zoomLevelLimits.max<zoomLevel||void 0!==zoomLevelLimits.min&&zoomLevelLimits.min>zoomLevel))}function clampZoomToHandler(destination,camera,config){return config.clampZoom?clampZoomLevel(destination,camera.zoomBoundaries):destination}function clampZoomByHandler(delta,camera,config){if(!config.clampZoom)return delta;let targetZoom=camera.zoomLevel+delta;return targetZoom=clampZoomLevel(targetZoom,camera.zoomBoundaries),delta=targetZoom-camera.zoomLevel}function restrictZoomToHandler(destination,camera,config){return config.restrictZoom?camera.zoomLevel:destination}function restrictZoomByHandler(delta,camera,config){return config.restrictZoom?0:delta}class CameraUpdatePublisher{constructor(){this.pan=new Observable$1,this.zoom=new Observable$1,this.rotate=new Observable$1,this.all=new Observable$1}notifyPan(event,cameraState){this.pan.notify(event,cameraState),this.all.notify({type:"pan",diff:event.diff},cameraState)}notifyZoom(event,cameraState){this.zoom.notify(event,cameraState),this.all.notify({type:"zoom",deltaZoomAmount:event.deltaZoomAmount},cameraState)}notifyRotate(event,cameraState){this.rotate.notify(event,cameraState),this.all.notify({type:"rotate",deltaRotation:event.deltaRotation},cameraState)}on(eventName,callback,options){switch(eventName){case"pan":return this.pan.subscribe(callback,options);case"zoom":return this.zoom.subscribe(callback,options);case"rotate":return this.rotate.subscribe(callback,options);case"all":return this.all.subscribe(callback,options);default:throw new Error(`Invalid event name: ${eventName}`)}}}function clampRotation(rotation,rotationLimits){if(rotationWithinLimits(rotation,rotationLimits)||void 0===rotationLimits)return rotation;rotation=normalizeAngleZero2TwoPI(rotation);const angleSpanFromStart=angleSpan(rotationLimits.start,rotation),angleSpanFromEnd=angleSpan(rotationLimits.end,rotation);if(rotationLimits.ccw&&(angleSpanFromStart<0||angleSpanFromEnd>0)||!rotationLimits.ccw&&(angleSpanFromStart>0||angleSpanFromEnd<0)){if(Math.abs(angleSpanFromStart)===Math.abs(angleSpanFromEnd))return rotationLimits.startAsTieBreaker?rotationLimits.start:rotationLimits.end;return Math.abs(angleSpanFromStart)<Math.abs(angleSpanFromEnd)?rotationLimits.start:rotationLimits.end}return rotation}function rotationWithinLimits(rotation,rotationLimits){if(void 0===rotationLimits)return!0;if(normalizeAngleZero2TwoPI(rotationLimits.start)===normalizeAngleZero2TwoPI(rotationLimits.end))return!0;if(normalizeAngleZero2TwoPI(rotationLimits.start+.01)===normalizeAngleZero2TwoPI(rotationLimits.end+.01))return!0;const normalizedRotation=normalizeAngleZero2TwoPI(rotation),angleSpanFromStart=angleSpan(rotationLimits.start,normalizedRotation),angleSpanFromEnd=angleSpan(rotationLimits.end,normalizedRotation);return!(rotationLimits.ccw&&(angleSpanFromStart<0||angleSpanFromEnd>0)||!rotationLimits.ccw&&(angleSpanFromStart>0||angleSpanFromEnd<0))}function normalizeAngleZero2TwoPI(angle){return angle=((angle%=2*Math.PI)+2*Math.PI)%(2*Math.PI)}function angleSpan(from,to){from=normalizeAngleZero2TwoPI(from);let angleDiff=(to=normalizeAngleZero2TwoPI(to))-from;return angleDiff>Math.PI&&(angleDiff=-(2*Math.PI-angleDiff)),angleDiff<-Math.PI&&(angleDiff+=2*Math.PI),angleDiff}class BaseCamera{constructor(viewPortWidth=1e3,viewPortHeight=1e3,position={x:0,y:0},rotation=0,zoomLevel=1,boundaries={min:{x:-1e4,y:-1e4},max:{x:1e4,y:1e4}},zoomLevelBoundaries={min:.1,max:10},rotationBoundaries=void 0){this._position=position,this._zoomLevel=zoomLevel,this._rotation=rotation,this._viewPortHeight=viewPortHeight,this._viewPortWidth=viewPortWidth,this._zoomBoundaries=zoomLevelBoundaries,this._rotationBoundaries=rotationBoundaries,this._boundaries=boundaries}get boundaries(){return this._boundaries}set boundaries(boundaries){this._boundaries=boundaries}get viewPortWidth(){return this._viewPortWidth}set viewPortWidth(width){this._viewPortWidth=width}get viewPortHeight(){return this._viewPortHeight}set viewPortHeight(height){this._viewPortHeight=height}get position(){return this._position}setPosition(destination){if(!withinBoundaries(destination,this._boundaries))return!1;const diff=PointCal.subVector(destination,this._position);return!(PointCal.magnitude(diff)<1e-9&&PointCal.magnitude(diff)<1/this._zoomLevel)&&(this._position=destination,!0)}get zoomLevel(){return this._zoomLevel}get zoomBoundaries(){return this._zoomBoundaries}set zoomBoundaries(zoomBoundaries){if(void 0!==zoomBoundaries&&void 0!==zoomBoundaries.min&&void 0!==zoomBoundaries.max&&zoomBoundaries.min>zoomBoundaries.max){let temp=zoomBoundaries.max;zoomBoundaries.max=zoomBoundaries.min,zoomBoundaries.min=temp}this._zoomBoundaries=zoomBoundaries}setMaxZoomLevel(maxZoomLevel){return null==this._zoomBoundaries&&(this._zoomBoundaries={min:void 0,max:void 0}),!(null!=this._zoomBoundaries.min&&this._zoomBoundaries.min>maxZoomLevel||this._zoomLevel>maxZoomLevel)&&(this._zoomBoundaries.max=maxZoomLevel,!0)}setMinZoomLevel(minZoomLevel){return null==this._zoomBoundaries&&(this._zoomBoundaries={min:void 0,max:void 0}),!(null!=this._zoomBoundaries.max&&this._zoomBoundaries.max<minZoomLevel)&&(this._zoomBoundaries.min=minZoomLevel,this._zoomLevel<minZoomLevel&&(this._zoomLevel=minZoomLevel),!0)}setZoomLevel(zoomLevel){return!!zoomLevelWithinLimits(zoomLevel,this._zoomBoundaries)&&((void 0===this._zoomBoundaries||void 0===this._zoomBoundaries.max||clampZoomLevel(zoomLevel,this._zoomBoundaries)!=this._zoomBoundaries.max||this._zoomLevel!=this._zoomBoundaries.max)&&((void 0===this._zoomBoundaries||void 0===this._zoomBoundaries.min||clampZoomLevel(zoomLevel,this._zoomBoundaries)!=this._zoomBoundaries.min||this._zoomLevel!=this._zoomBoundaries.min)&&(this._zoomLevel=zoomLevel,!0)))}get rotation(){return this._rotation}get rotationBoundaries(){return this._rotationBoundaries}set rotationBoundaries(rotationBoundaries){if(void 0!==rotationBoundaries&&void 0!==rotationBoundaries.start&&void 0!==rotationBoundaries.end&&rotationBoundaries.start>rotationBoundaries.end){let temp=rotationBoundaries.end;rotationBoundaries.end=rotationBoundaries.start,rotationBoundaries.start=temp}this._rotationBoundaries=rotationBoundaries}getTransform(devicePixelRatio,alignCoorindate){if(void 0!==this.currentCachedTransform&&this.currentCachedTransform.devicePixelRatio===devicePixelRatio&&this.currentCachedTransform.alignCoorindate===alignCoorindate&&this.currentCachedTransform.position.x===this._position.x&&this.currentCachedTransform.position.y===this._position.y&&this.currentCachedTransform.rotation===this._rotation&&this.currentCachedTransform.zoomLevel===this._zoomLevel&&this.currentCachedTransform.viewPortWidth===this._viewPortWidth&&this.currentCachedTransform.viewPortHeight===this._viewPortHeight)return Object.assign(Object.assign({},this.currentCachedTransform.transform),{cached:!0});const tx=devicePixelRatio*this._viewPortWidth/2,ty=devicePixelRatio*this._viewPortHeight/2,tx2=-this._position.x,ty2=alignCoorindate?-this._position.y:this._position.y,s=devicePixelRatio,s2=this._zoomLevel,θ=alignCoorindate?-this._rotation:this._rotation,sin=Math.sin(θ),cos=Math.cos(θ),a=s2*s*cos,b=s2*s*sin,c=-s*s2*sin,d=s2*s*cos,e=s*s2*cos*tx2-s*s2*sin*ty2+tx,f=s*s2*sin*tx2+s*s2*cos*ty2+ty;return this.currentCachedTransform={transform:{a:a,b:b,c:c,d:d,e:e,f:f},position:this._position,rotation:this._rotation,zoomLevel:this._zoomLevel,alignCoorindate:alignCoorindate,devicePixelRatio:devicePixelRatio,viewPortWidth:this._viewPortWidth,viewPortHeight:this._viewPortHeight},{a:a,b:b,c:c,d:d,e:e,f:f,cached:!1}}setUsingTransformationMatrix(transformationMatrix){const decomposed=function(transformMatrix,devicePixelRatio,canvasWidth,canvasHeight){const a=transformMatrix.a,b=transformMatrix.b;transformMatrix.c,transformMatrix.d;const tx=transformMatrix.e,ty=transformMatrix.f,rotation=-Math.atan2(b,a),zoom=Math.sqrt(a*a+b*b)/devicePixelRatio;let reverse=[tx,ty];reverse=[reverse[0]/devicePixelRatio,reverse[1]/devicePixelRatio],reverse=[reverse[0]-canvasWidth/2,reverse[1]-canvasHeight/2];const cos_r=Math.cos(rotation),sin_r=Math.sin(rotation);return reverse=[cos_r*reverse[0]-sin_r*reverse[1],sin_r*reverse[0]+cos_r*reverse[1]],reverse=[reverse[0]/zoom,reverse[1]/zoom],{position:{x:-reverse[0],y:-reverse[1]},zoom:zoom,rotation:rotation}}(transformationMatrix,this._viewPortWidth,this._viewPortHeight,this._zoomLevel);this.setPosition(decomposed.position),this.setRotation(decomposed.rotation),this.setZoomLevel(decomposed.zoom)}setRotation(rotation){return!!rotationWithinLimits(rotation,this._rotationBoundaries)&&(rotation=normalizeAngleZero2TwoPI(rotation),(void 0===this._rotationBoundaries||void 0===this._rotationBoundaries.end||clampRotation(rotation,this._rotationBoundaries)!=this._rotationBoundaries.end||this._rotation!=this._rotationBoundaries.end)&&((void 0===this._rotationBoundaries||void 0===this.rotationBoundaries.start||clampRotation(rotation,this._rotationBoundaries)!=this._rotationBoundaries.start||this._rotation!=this._rotationBoundaries.start)&&(this._rotation=rotation,!0)))}getCameraOriginInWindow(centerInWindow){return centerInWindow}convertFromViewPort2WorldSpace(point){return convert2WorldSpaceAnchorAtCenter(point,this._position,this._zoomLevel,this._rotation)}convertFromWorld2ViewPort(point){return convert2ViewPortSpaceAnchorAtCenter(point,this._position,this._zoomLevel,this._rotation)}invertFromWorldSpace2ViewPort(point){let cameraFrameCenter={x:this.viewPortWidth/2,y:this._viewPortHeight/2},delta2Point=PointCal.subVector(point,this._position);return delta2Point=PointCal.rotatePoint(delta2Point,-this._rotation),delta2Point=PointCal.multiplyVectorByScalar(delta2Point,this._zoomLevel),PointCal.addVector(cameraFrameCenter,delta2Point)}setHorizontalBoundaries(min,max){if(min>max){let temp=max;max=min,min=temp}null==this._boundaries&&(this._boundaries={min:{x:void 0,y:void 0},max:{x:void 0,y:void 0}}),this._boundaries.min.x=min,this._boundaries.max.x=max}setVerticalBoundaries(min,max){if(min>max){let temp=max;max=min,min=temp}null==this._boundaries&&(this._boundaries={min:{x:void 0,y:void 0},max:{x:void 0,y:void 0}}),this._boundaries.min.y=min,this._boundaries.max.y=max}}const DEFAULT_BOARD_CAMERA_ZOOM_BOUNDARIES={min:.1,max:10},DEFAULT_BOARD_CAMERA_BOUNDARIES={min:{x:-1e4,y:-1e4},max:{x:1e4,y:1e4}};class DefaultBoardCamera{constructor(viewPortWidth=1e3,viewPortHeight=1e3,position={x:0,y:0},rotation=0,zoomLevel=1,boundaries=DEFAULT_BOARD_CAMERA_BOUNDARIES,zoomLevelBoundaries=DEFAULT_BOARD_CAMERA_ZOOM_BOUNDARIES,rotationBoundaries=undefined){this._baseCamera=new BaseCamera(viewPortWidth,viewPortHeight,position,rotation,zoomLevel,boundaries,zoomLevelBoundaries,rotationBoundaries),this._observer=new CameraUpdatePublisher}get boundaries(){return this._baseCamera.boundaries}set boundaries(boundaries){this._baseCamera.boundaries=boundaries}get viewPortWidth(){return this._baseCamera.viewPortWidth}set viewPortWidth(width){this._baseCamera.viewPortWidth=width}get viewPortHeight(){return this._baseCamera.viewPortHeight}set viewPortHeight(height){this._baseCamera.viewPortHeight=height}get position(){return this._baseCamera.position}setPosition(destination){const currentPosition=Object.assign({},this._baseCamera.position);return!!this._baseCamera.setPosition(destination)&&(this._observer.notifyPan({diff:PointCal.subVector(destination,currentPosition)},{position:this._baseCamera.position,rotation:this._baseCamera.rotation,zoomLevel:this._baseCamera.zoomLevel}),!0)}get zoomLevel(){return this._baseCamera.zoomLevel}get zoomBoundaries(){return this._baseCamera.zoomBoundaries}set zoomBoundaries(zoomBoundaries){this._baseCamera.zoomBoundaries=zoomBoundaries}setMaxZoomLevel(maxZoomLevel){const currentZoomLevel=this._baseCamera.zoomLevel;return!!this._baseCamera.setMaxZoomLevel(maxZoomLevel)&&(this._observer.notifyZoom({deltaZoomAmount:maxZoomLevel-currentZoomLevel},{position:this._baseCamera.position,rotation:this._baseCamera.rotation,zoomLevel:this._baseCamera.zoomLevel}),!0)}setMinZoomLevel(minZoomLevel){return!!this._baseCamera.setMinZoomLevel(minZoomLevel)}setZoomLevel(zoomLevel){return!!this._baseCamera.setZoomLevel(zoomLevel)}get rotation(){return this._baseCamera.rotation}get rotationBoundaries(){return this._baseCamera.rotationBoundaries}set rotationBoundaries(rotationBoundaries){this._baseCamera.rotationBoundaries=rotationBoundaries}getTransform(devicePixelRatio,alignCoorindate){return this._baseCamera.getTransform(devicePixelRatio,alignCoorindate)}setRotation(rotation){const currentRotation=this._baseCamera.rotation;return!!this._baseCamera.setRotation(rotation)&&(this._observer.notifyRotate({deltaRotation:rotation-currentRotation},{position:this._baseCamera.position,rotation:this._baseCamera.rotation,zoomLevel:this._baseCamera.zoomLevel}),!0)}getCameraOriginInWindow(centerInWindow){return centerInWindow}convertFromViewPort2WorldSpace(point){return convert2WorldSpaceAnchorAtCenter(point,this._baseCamera.position,this._baseCamera.zoomLevel,this._baseCamera.rotation)}convertFromWorld2ViewPort(point){return convert2ViewPortSpaceAnchorAtCenter(point,this._baseCamera.position,this._baseCamera.zoomLevel,this._baseCamera.rotation)}invertFromWorldSpace2ViewPort(point){let cameraFrameCenter={x:this._baseCamera.viewPortWidth/2,y:this._baseCamera.viewPortHeight/2},delta2Point=PointCal.subVector(point,this._baseCamera.position);return delta2Point=PointCal.rotatePoint(delta2Point,-this._baseCamera.rotation),delta2Point=PointCal.multiplyVectorByScalar(delta2Point,this._baseCamera.zoomLevel),PointCal.addVector(cameraFrameCenter,delta2Point)}setHorizontalBoundaries(min,max){if(min>max){let temp=max;max=min,min=temp}null==this._baseCamera.boundaries&&(this._baseCamera.boundaries={min:{x:void 0,y:void 0},max:{x:void 0,y:void 0}}),this._baseCamera.boundaries.min.x=min,this._baseCamera.boundaries.max.x=max}setVerticalBoundaries(min,max){if(min>max){let temp=max;max=min,min=temp}null==this._baseCamera.boundaries&&(this._baseCamera.boundaries={min:{x:void 0,y:void 0},max:{x:void 0,y:void 0}}),this._baseCamera.boundaries.min.y=min,this._baseCamera.boundaries.max.y=max}on(eventName,callback,options){return this._observer.on(eventName,callback,options)}}function clampRotateByHandler(delta,camera,config){if(!config.clampRotation)return delta;const clampedRotation=clampRotation(normalizeAngleZero2TwoPI(camera.rotation+delta),camera.rotationBoundaries);return angleSpan(camera.rotation,clampedRotation)}function restrictRotateByHandler(delta,camera,config){return config.restrictRotation?0:delta}function clampRotateToHandler(targetRotation,camera,config){if(!config.clampRotation)return targetRotation;return clampRotation(targetRotation,camera.rotationBoundaries)}function restrictRotateToHandler(targetRotation,camera,config){return config.restrictRotation?camera.rotation:targetRotation}class DefaultCameraRig{constructor(config,camera=new DefaultBoardCamera){this._panBy=createHandlerChain(restrictPanByHandler,clampByHandler),this._panTo=createHandlerChain(restrictPanToHandler,clampToHandler),this._zoomTo=createHandlerChain(clampZoomToHandler,restrictZoomToHandler),this._zoomBy=createHandlerChain(clampZoomByHandler,restrictZoomByHandler),this._rotateBy=createHandlerChain(restrictRotateByHandler,clampRotateByHandler),this._rotateTo=createHandlerChain(restrictRotateToHandler,clampRotateToHandler),this._config=Object.assign(Object.assign({},config),{restrictRotation:!1,clampRotation:!0}),this._camera=camera}zoomToAt(targetZoom,at){let originalAnchorInWorld=this._camera.convertFromViewPort2WorldSpace(at);const transformTarget=this._zoomTo(targetZoom,this._camera,this._config);this._camera.setZoomLevel(transformTarget);let anchorInWorldAfterZoom=this._camera.convertFromViewPort2WorldSpace(at);const cameraPositionDiff=PointCal.subVector(originalAnchorInWorld,anchorInWorldAfterZoom),transformedCameraPositionDiff=this._panBy(cameraPositionDiff,this._camera,this._config);this._camera.setPosition(PointCal.addVector(this._camera.position,transformedCameraPositionDiff))}zoomByAt(delta,at){let originalAnchorInWorld=this._camera.convertFromViewPort2WorldSpace(at);const transformedDelta=this._zoomBy(delta,this._camera,this._c