@vertexvis/viewer 0.22.1-testing.0 → 0.22.1-testing.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/cjs/{entities-a0db2d78.js → entities-9fad8808.js} +2 -2
  2. package/dist/cjs/{entities-a0db2d78.js.map → entities-9fad8808.js.map} +1 -1
  3. package/dist/cjs/index.cjs.js +5 -4
  4. package/dist/cjs/index.cjs.js.map +1 -1
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/mapper-ac34f608.js +27 -0
  7. package/dist/cjs/mapper-ac34f608.js.map +1 -0
  8. package/dist/cjs/{queries-d31d23d4.js → queries-ea895dd6.js} +34 -3
  9. package/dist/cjs/queries-ea895dd6.js.map +1 -0
  10. package/dist/cjs/{scene_view_api_pb-0c5fdc13.js → scene_view_api_pb-61f663af.js} +605 -1
  11. package/dist/cjs/scene_view_api_pb-61f663af.js.map +1 -0
  12. package/dist/cjs/{scene_view_api_pb_service-4f9e3f90.js → scene_view_api_pb_service-bd6f25d0.js} +42 -2
  13. package/dist/cjs/scene_view_api_pb_service-bd6f25d0.js.map +1 -0
  14. package/dist/cjs/vertex-viewer-measurement-distance.cjs.entry.js +1 -1
  15. package/dist/cjs/vertex-viewer-measurement-line_2.cjs.entry.js +1 -1
  16. package/dist/cjs/vertex-viewer-measurement-precise.cjs.entry.js +3 -3
  17. package/dist/cjs/vertex-viewer-pin-group.cjs.entry.js +2 -2
  18. package/dist/cjs/vertex-viewer.cjs.entry.js +5 -4
  19. package/dist/cjs/vertex-viewer.cjs.entry.js.map +1 -1
  20. package/dist/cjs/viewer.cjs.js +1 -1
  21. package/dist/collection/components/viewer/viewer.js +25 -0
  22. package/dist/collection/components/viewer/viewer.js.map +1 -1
  23. package/dist/collection/index.js +1 -0
  24. package/dist/collection/index.js.map +1 -1
  25. package/dist/collection/lib/pmi/controller.js +39 -0
  26. package/dist/collection/lib/pmi/controller.js.map +1 -0
  27. package/dist/collection/lib/pmi/index.js +6 -0
  28. package/dist/collection/lib/pmi/index.js.map +1 -0
  29. package/dist/collection/lib/pmi/mapper.js +9 -0
  30. package/dist/collection/lib/pmi/mapper.js.map +1 -0
  31. package/dist/collection/lib/pmi/types.js +5 -0
  32. package/dist/collection/lib/pmi/types.js.map +1 -0
  33. package/dist/collection/testing/pmi.js +20 -0
  34. package/dist/collection/testing/pmi.js.map +1 -0
  35. package/dist/components/index.js +1 -1
  36. package/dist/components/mapper2.js +7 -3
  37. package/dist/components/mapper2.js.map +1 -1
  38. package/dist/components/queries.js +32 -2
  39. package/dist/components/queries.js.map +1 -1
  40. package/dist/components/scene_view_api_pb.js +604 -0
  41. package/dist/components/scene_view_api_pb.js.map +1 -1
  42. package/dist/components/scene_view_api_pb_service.js +40 -0
  43. package/dist/components/scene_view_api_pb_service.js.map +1 -1
  44. package/dist/components/vertex-viewer.js +3 -1
  45. package/dist/components/vertex-viewer.js.map +1 -1
  46. package/dist/esm/{entities-632f31f3.js → entities-9d4e336b.js} +2 -2
  47. package/dist/esm/{entities-632f31f3.js.map → entities-9d4e336b.js.map} +1 -1
  48. package/dist/esm/index.js +4 -4
  49. package/dist/esm/index.mjs +4 -4
  50. package/dist/esm/loader.js +1 -1
  51. package/dist/esm/loader.mjs +1 -1
  52. package/dist/esm/mapper-b3a6eca5.js +23 -0
  53. package/dist/esm/mapper-b3a6eca5.js.map +1 -0
  54. package/dist/esm/{queries-40a25625.js → queries-f2b5a440.js} +34 -4
  55. package/dist/esm/queries-f2b5a440.js.map +1 -0
  56. package/dist/esm/{scene_view_api_pb-1d91cc93.js → scene_view_api_pb-c030fd23.js} +605 -1
  57. package/dist/esm/scene_view_api_pb-c030fd23.js.map +1 -0
  58. package/dist/esm/{scene_view_api_pb_service-9f20d437.js → scene_view_api_pb_service-65caee11.js} +42 -2
  59. package/dist/esm/scene_view_api_pb_service-65caee11.js.map +1 -0
  60. package/dist/esm/vertex-viewer-measurement-distance.entry.js +1 -1
  61. package/dist/esm/vertex-viewer-measurement-line_2.entry.js +1 -1
  62. package/dist/esm/vertex-viewer-measurement-precise.entry.js +3 -3
  63. package/dist/esm/vertex-viewer-pin-group.entry.js +2 -2
  64. package/dist/esm/vertex-viewer.entry.js +5 -4
  65. package/dist/esm/vertex-viewer.entry.js.map +1 -1
  66. package/dist/esm/viewer.js +1 -1
  67. package/dist/types/components/viewer/viewer.d.ts +7 -0
  68. package/dist/types/components.d.ts +11 -0
  69. package/dist/types/index.d.ts +1 -0
  70. package/dist/types/lib/pmi/controller.d.ts +16 -0
  71. package/dist/types/lib/pmi/index.d.ts +2 -0
  72. package/dist/types/lib/pmi/mapper.d.ts +4 -0
  73. package/dist/types/lib/pmi/types.d.ts +10 -0
  74. package/dist/types/testing/pmi.d.ts +5 -0
  75. package/dist/viewer/index.esm.js +1 -1
  76. package/dist/viewer/index.esm.js.map +1 -1
  77. package/dist/viewer/p-187f783f.entry.js +5 -0
  78. package/dist/viewer/p-187f783f.entry.js.map +1 -0
  79. package/dist/viewer/p-32bff740.js +5 -0
  80. package/dist/viewer/p-32bff740.js.map +1 -0
  81. package/dist/viewer/{p-9d0c84ab.entry.js → p-4b7b629a.entry.js} +2 -2
  82. package/dist/viewer/p-8af6917b.js +5 -0
  83. package/dist/viewer/p-8af6917b.js.map +1 -0
  84. package/dist/viewer/{p-34dce39f.js → p-90bbb5f6.js} +2 -2
  85. package/dist/viewer/{p-9094c563.entry.js → p-9de90d0e.entry.js} +2 -2
  86. package/dist/viewer/{p-b9965b9b.entry.js → p-b3257f48.entry.js} +2 -2
  87. package/dist/viewer/{p-076e9e65.entry.js → p-d10f7459.entry.js} +2 -2
  88. package/dist/viewer/p-d36d5971.js +5 -0
  89. package/dist/viewer/p-d36d5971.js.map +1 -0
  90. package/dist/viewer/p-f0c0cf0b.js +5 -0
  91. package/dist/viewer/p-f0c0cf0b.js.map +1 -0
  92. package/dist/viewer/viewer.esm.js +1 -1
  93. package/dist/viewer/viewer.esm.js.map +1 -1
  94. package/package.json +8 -8
  95. package/dist/cjs/mapper-f168a1a5.js +0 -22
  96. package/dist/cjs/mapper-f168a1a5.js.map +0 -1
  97. package/dist/cjs/queries-d31d23d4.js.map +0 -1
  98. package/dist/cjs/scene_view_api_pb-0c5fdc13.js.map +0 -1
  99. package/dist/cjs/scene_view_api_pb_service-4f9e3f90.js.map +0 -1
  100. package/dist/esm/mapper-826430a2.js +0 -19
  101. package/dist/esm/mapper-826430a2.js.map +0 -1
  102. package/dist/esm/queries-40a25625.js.map +0 -1
  103. package/dist/esm/scene_view_api_pb-1d91cc93.js.map +0 -1
  104. package/dist/esm/scene_view_api_pb_service-9f20d437.js.map +0 -1
  105. package/dist/viewer/p-2800111a.js +0 -5
  106. package/dist/viewer/p-2800111a.js.map +0 -1
  107. package/dist/viewer/p-2924ed4a.entry.js +0 -5
  108. package/dist/viewer/p-2924ed4a.entry.js.map +0 -1
  109. package/dist/viewer/p-9f190847.js +0 -5
  110. package/dist/viewer/p-9f190847.js.map +0 -1
  111. package/dist/viewer/p-a297836a.js +0 -5
  112. package/dist/viewer/p-a297836a.js.map +0 -1
  113. package/dist/viewer/p-aeaafe7f.js +0 -5
  114. package/dist/viewer/p-aeaafe7f.js.map +0 -1
  115. /package/dist/viewer/{p-9d0c84ab.entry.js.map → p-4b7b629a.entry.js.map} +0 -0
  116. /package/dist/viewer/{p-34dce39f.js.map → p-90bbb5f6.js.map} +0 -0
  117. /package/dist/viewer/{p-9094c563.entry.js.map → p-9de90d0e.entry.js.map} +0 -0
  118. /package/dist/viewer/{p-b9965b9b.entry.js.map → p-b3257f48.entry.js.map} +0 -0
  119. /package/dist/viewer/{p-076e9e65.entry.js.map → p-d10f7459.entry.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["src/lib/types/stencilBuffer.ts","src/lib/types/typeGuards.ts","src/testing/utils.ts","src/lib/mappers/annotation.ts","src/lib/annotations/controller.ts","src/lib/interactions/flyToPartKeyInteraction.ts","src/lib/interactions/interactionApi.ts","src/lib/interactions/interactionApiOrthographic.ts","src/lib/interactions/interactionApiPerspective.ts","src/lib/interactions/flyToPositionKeyInteraction.ts","src/lib/interactions/mouseInteractions.ts","src/lib/interactions/mouseInteractionHandler.ts","src/lib/window.ts","src/lib/interactions/multiTouchInteractionHandler.ts","src/lib/interactions/multiPointerInteractionHandler.ts","src/lib/interactions/pointerInteractionHandler.ts","src/lib/interactions/tapInteractionHandler.ts","src/lib/interactions/touchInteractionHandler.ts","src/lib/meters.ts","src/lib/rendering/imageLoaders.ts","src/lib/rendering/canvas.ts","src/lib/rendering/utils.ts","src/lib/rendering/timing.ts","src/lib/storage.ts","../../node_modules/fast-deep-equal/index.js","src/lib/stream/stream.ts","src/components/viewer/utils.ts","src/components/viewer/viewer.css?tag=vertex-viewer&encapsulation=shadow","src/components/viewer/viewer.tsx"],"names":["STENCIL_BUFFER_EMPTY_VALUE","STENCIL_BUFFER_FEATURE_VALUE","StencilBufferManager","[object Object]","viewer","this","handleInteractionStarted","invalidateStencilBuffer","pendingInteractionFinished","Promise","resolve","pendingInteractionFinishedResolver","handleInteractionFinished","_a","call","undefined","pendingStencilBuffer","addEventListener","isReady","isSceneReady","scene","hasStencil","crossSectioning","current","sectionPlanes","length","featureLines","camera","frame","stream","res","getStencilBuffer","includeDepthBuffer","stencilBuffer","sBytes","depthBuffer","dBytes","imageAttributes","fromPbStencilBufferOrThrow","stencilPng","depthPng","all","decodePng","Uint8Array","StencilBuffer","fromPng","DepthBuffer","fetch","latest","imageAttr","imageBytes","pixelBytes","imageChannels","png","data","Error","channels","pt","width","height","imageRect","offset","Point","subtract","scale","imageScale","pixel","x","y","index","Math","floor","value","getValue","radius","predicate","diameter","topLeft","create","pixels","i","add","distance","push","sorted","sort","a","b","closest","isPromise","obj","Function","delay","milliseconds","setTimeout","fromPbAnnotationSet","M","defineMapper","compose","input","toObject","read","mapRequiredProp","fromPbUuid2l","fromPbTimestamp","mapProp","fromPbStringValue","id","createdAt","modifiedAt","name","suppliedId","fromPbAnnotationSetOrThrow","ifInvalidThrow","fromPbAnnotation","callout","fromPbCalloutAnnotationData","customJson","fromPbCustomAnnotationData","fromPbAnnotationOrThrow","fromPbVector3f","position","icon","primaryColor","accentColor","type","requiredProp","json","JSON","parse","jsonType","jsonData","AnnotationController","client","jwtProvider","deviceIdProvider","onStateChange","EventDispatcher","requestUnary","async","handler","deviceId","meta","createMetadata","req","CreateSceneViewAnnotationSetRequest","setId","Uuid","setHex","setSceneAnnotationSetId","createSceneViewAnnotationSet","connection","dispose","pollingIntervalInMs","disconnect","controller","pollAnnotationState","abort","opts","sets","fetchAnnotationSetsAsArray","annotations","fetchAnnotationsAsArray","state","reduce","set","Object","assign","signal","aborted","updateState","DeleteSceneViewAnnotationSetRequest","deleteSceneViewAnnotationSet","AbortController","poll","delayMs","Async","requestPaged","cursor","ListSceneViewAnnotationSetsRequest","page","Pager","setCursor","setLimit","setPage","listSceneViewAnnotationSets","nextCursor","next","asArray","fetchAnnotationSets","flatMap","getSceneAnnotationSetsList","map","setIdLong","UUID","toMsbLsb","Uuid2l","setMsb","msb","setLsb","lsb","ListSceneAnnotationsRequest","listSceneAnnotations","fetchAnnotations","ann","getSceneAnnotationsList","emit","FlyToPartKeyInteraction","configProvider","imageScaleProvider","e","altKey","shiftKey","hitResult","hitItems","point","hits","flyTo","itemId","animation","duration","toProtoDuration","durationMs","console","debug","InteractionApi","cursors","getConfig","getScene","getFrame","getViewport","tapEmitter","doubleTapEmitter","longPressEmitter","interactionStartedEmitter","interactionFinishedEmitter","cameraChangedEmitter","tap","bind","doubleTap","longPress","emitTapEvent","priority","viewport","transformPointToWorldSpace","featureMap","framePt","transformPointToFrame","getEntityType","EntityType","NO_GEOMETRY","transformPointToRay","image","keyDetails","buttons","isInteracting","sceneLoadingPromise","currentCamera","beginInteraction","args","t","renderOptions","boundingBox","toFrameCamera","_b","render","transformCamera","axis","Vector3","normalize","lookAt","angleInRadians","Angle","toRadians","rotateAroundAxis","center","currentAngle","toDegrees","fromPoints","angleDelta","lastAngle","screenPt","panData","startingCamera","direction","ray","fallbackPlane","Plane","fromNormalAndCoplanarPoint","fallback","Ray","intersectPlane","warn","hitPt","getWorldPoint","hitPlane","movePt","delta","update","moveBy","viewAll","upVector","up","directionVector","crossX","cross","crossY","mouseToWorld","z","rotationAxis","epsilonX","epsilonY","angle","abs","worldRotationPoint","worldCenter","BoundingBox","vv","updated","rotateAroundAxisAtPoint","signedDistanceToBoundingBoxCenter","magnitude","viewVector","v","epsilon","newCamera","degreesLocalX","degreesLocalY","normalizedUp","normalizedViewVector","xVector","yVector","updatedLookAtX","rotateAboutAxis","updatedLookAtY","zoomData","resetLastAngle","endInteraction","isTouch","pixelThreshold","isCoarseInputDevice","coarsePointerThreshold","finePointerThreshold","window","devicePixelRatio","raycaster","ctrlKey","metaKey","matchMedia","matches","fallbackPoint","hasDepth","hitTest","InteractionApiOrthographic","super","normalizedUpVector","throttledDelta","d","xvec","yvec","updatedLookAt","rotationPoint","orthographicZoomData","startingScreenPt","frameCam","dir","fallbackPt","relativeDelta","fovHeight","max","projectedLookAt","projectPoint","diff","rotationAxisDirection","newLookAt","updateLookAtRelativeToBoundingBoxCenter","CAMERA_MIN_ZOOM_SCALAR","InteractionApiPerspective","u","tan","fovY","cam","isPastHitPlane","keepCurrent","computeZoomDistances","viewVectorRay","origin","at","boundingBoxScalar","min","toArray","lengths","scaledDelta","localX","localZ","translationX","translationY","translationZ","translation","negate","pointRay","config","minDistance","useMinimumPerspectiveZoomDistance","computeZoomMinimumDistance","expectedDistance","actualDistance","expectedPosition","expectedViewVector","expectedIntersection","minDistanceEpsilon","xLength","yLength","zLength","maxLength","absDotX","dot","right","absDotY","absDotZ","back","scaledLengthX","scaledLengthY","scaledLengthZ","relevanceLengthX","relevanceLengthY","relevanceLengthZ","FlyToPositionKeyInteraction","sceneProvider","hitPoint","hit","getLookAtPoint","FrameCamera.toProtobuf","hex","isOrthographic","MouseInteraction","currentPosition","event","canvasPosition","api","element","RotateInteraction","screenX","screenY","rotateCamera","endDrag","RotatePointInteraction","startingPosition","rotateCameraAtPoint","ZoomInteraction","interactionConfigProvider","didTransformBegin","clientX","clientY","rect","getBoundingClientRect","getMouseClientPosition","startPt","zoomCameraToPoint","stopInteractionTimer","operateWithTimer","zoomCamera","getDirectionalDelta","startInteractionTimer","reverseMouseWheelDirection","mouseWheelInteractionEndDebounce","interactionTimer","getInteractionDelay","clearTimeout","f","resetInteractionTimer","PanInteraction","canvasRect","panCameraToScreenPoint","TwistInteraction","offsetX","offsetY","twistCamera","PivotInteraction","pivotCamera","MouseInteractionHandler","BaseInteractionHandler","rotateInteraction","rotatePointInteraction","zoomInteraction","interactions","panInteraction","twistInteraction","pivotInteraction","requestAnimationFrame","callback","MultiTouchInteractionHandler","previousFirstPoints","previousSecondPoints","interactionApi","point1","point2","slice","changes","result","previousFirstPoint","firstPoint","previousSecondPoint","secondPoint","deltas","computeDelta","zooms","computeZoom","angles","computeAngle","r","zoom","_c","panCameraByDelta","_d","previousPoint1","previousPoint2","previousToCurrent","Matrix2","atan2","determinant","MultiPointerInteractionHandler","touchPoints","handlePointerDown","handlePointerMove","handlePointerUp","removeEventListener","initialize","pointerId","keys","beginTwoPointTouch","handleTwoPointTouchMove","endTwoPointTouch","PointerInteractionHandler","MultiElementInteractionHandler","Set","downEvent","handleDownEvent","handleMouseWheel","passive","downPosition","size","disableIndividualInteractions","delete","TapInteractionHandler","upEvent","moveEvent","handleDown","handleUp","handleMove","handleTouchStart","handleTouchMove","handleTouchEnd","handlePointerEnd","clearPositions","restartDoubleTapTimer","clearDoubleTapTimer","restartLongPressTimer","clearLongPressTimer","setPointerPositions","touches","pointerDownPosition","eventKeys","threshold","longPressTimer","doubleTapTimer","secondPointerDownPosition","emitter","pointerUpPosition","emittedPosition","getCanvasPosition","canvasBounds","canvasOffset","left","top","firstPointerDownPosition","clearInteractionTimer","events","doubleTapThreshold","longPressThreshold","interactionDelay","restartInteractionTimer","PointerEvent","pointerType","TouchInteractionHandler","preventDefault","touch1","currentPosition1","handleOnePointTouchMove","touch","TimingMeter","perf","performance","measures","nextId","clearMeasures","target","mark","begin","finally","end","timings","getEntriesByName","clearMeasurements","measurements","takeMeasurements","measure","clearMarks","paintTime","loadImageBytesAsImageElement","imageData","reject","blob","Blob","blobUrl","URL","createObjectURL","Image","revokeObjectURL","ImageLoadError","src","loadImageBytesAsImageBitmap","bitmap","createImageBitmap","close","loadImageBytes","REPORTING_INTERVAL_MS","drawImage","calculateDrawRect","canvas","clearRect","canvasDimensions","reportTimings","meter","measureCanvasRenderer","renderer","logFrameRate","intervalMs","timer","renderCount","fpsFrameCount","fpsHistory","start","setInterval","clearTimer","clearInterval","avgFps","num","createCanvasRenderer","accumulatedCorrelationIds","addCorrelationIds","frameWithCorrelationIds","copy","correlationIds","filter","includes","loadFrame","lastLoadedFrameNumber","sequenceNumber","drawFrame","lastDrawnFrameNumber","beforeDraw","load","draw","predicatePassing","then","ifRequestId","reqId","request","requestId","ifDrawFrame","MUTE_WARNING_SECONDS","calculateSendToReceiveDuration","clockProvider","muteWarning","sentAt","clock","receivedAt","remoteTime","Date","now","durationInMs","protoToDate","getTime","toISOString","knownRemoteTime","acknowledgeFrameRequests","sendToReceiveDuration","_","sentAtTime","replyResult","StorageKeys","upsertStorageEntry","key","values","storage","localStorage","existing","getItem","setItem","stringify","getStorageEntry","item","fastDeepEqual","equal","constructor","Array","isArray","RegExp","source","flags","valueOf","prototype","toString","hasOwnProperty","ViewerStream","StreamApi","ws","loggingEnabled","stateChanged","dimensions","Dimensions","streamAttributes","enableTemporalRefinement","frameBgColor","Color","parseConfig","options","tokenRefreshOffsetInSeconds","offlineThresholdInSeconds","loadTimeoutInSeconds","_e","urn","clientId","loadIfDisconnected","loadIfConnectingOrConnected","fields","deepEqual","ifState","updateDimensions","getDimensions","updateStream","toPbStreamAttributesOrThrow","closeAndReconnect","resource","pResource","subResource","pSubResource","LoadableResource.fromUrn","hasResourceChanged","Objects","isEqual","hasSubResourceChanged","isConnecting","isConnected","suppliedIdQuery","queries","find","q","payload","sceneViewStateId","sceneViewStateSuppliedId","loadSceneViewState","connectWithNewStream","CustomError","message","error","StreamRequestError","openWebsocketStream","requestNewStream","requestReconnectStream","maxRetries","Number","POSITIVE_INFINITY","requestStream","descriptor","getWebsocketDescriptor","getWebsocketUri","url","settings","getStreamSettings","retry","connect","delaysInMs","WS_RECONNECT_DELAYS","catch","WebsocketConnectionError","requestNewOrExistingStream","pendingClock","requestClock","streamId","sceneId","sceneViewId","onRequest","msg","fromPbFrameOrThrow","worldOrientation","depthBufferBytes","temporalRefinementCorrelationId","fallbackDepthBufferBytes","reconnect","reconnectWhenNeeded","refreshToken","refreshTokenWhenExpired","token","waitForFrame","knownLocalTime","fromPbStartStreamResponseOrThrow","startStream","streamKey","frameBackgroundColor","toPbColorOrThrow","clientSupportsTemporalRefinement","sessionId","fromPbReconnectResponseOrThrow","fromPbSyncTimeResponseOrThrow","syncTime","requestTime","currentDateAsProtoTimestamp","SynchronizedClock","whenDisconnected","onClose","whenRequested","isReconnectMsg","gracefulReconnection","whenOffline","reconnectWhenOffline","startTimer","ms","remainingTimeInMs","newToken","fromPbRefreshTokenResponseOrThrow","restartTimer","delayInSec","handleOnline","handleOffline","connectToExistingStream","timeoutInSeconds","disposable","timeout","SceneRenderError","area","listener","on","Mapper","toPbStreamAttributes","toPbRGBi","EXPERIMENTAL_frameDelivery","rateLimitingEnabled","throttleFrameDelivery","EXPERIMENTAL_adaptiveRendering","enabled","adaptiveRendering","EXPERIMENTAL_qualityOfService","uri","Uri","protocols","appendPath","parseAndAddParams","network","renderingHost","DEFAULT_VIEWER_SCENE_WAIT_MS","getElementBoundingClientRect","getElementPropertyValue","property","styles","getComputedStyle","getPropertyValue","viewerCss","Viewer","hostRef","configEnv","cameraControls","cameraType","keyboardControls","rotateAroundTapPoint","phantom","opacity","noDefaultLights","experimentalRenderingOptions","resizeDebounce","hostElement","Viewport","fromDimensions","stateMap","cursorManager","CursorManager","streamState","interactionHandlers","defaultInteractionHandlerDisposables","tapKeyInteractions","defaultTapKeyInteractions","internalFrameDrawnDispatcher","handleElementResize","updateResolvedConfig","calculateComponentDimensions","resizeObserver","ResizeObserver","registerSlotChangeListeners","getResolvedConfig","SceneViewAPIClient","sceneViewHost","annotationStateChanged","WebSocketClientImpl","logWsMessages","addStreamListeners","modelViews","ModelViewController","updateStreamAttributes","onChanged","handleCursorChanged","createInteractionApi","canvasContainerElement","observe","initializeDefaultInteractionHandlers","injectViewerApi","h","Host","ref","viewerContainerElement","class","style","cssCursor","onContextMenu","classnames","enable-pointer-events ","canvasElement","interactionTarget","errorMessage","frameDrawn","interactionHandler","initializeInteractionHandler","indexOf","splice","keyInteraction","baseInteractionHandler","unload","initializeDefaultCameraInteractionHandlers","initializeDefaultKeyboardInteractionHandlers","setPrimaryInteractionType","updatedCameraType","previousCameraType","updateCameraType","updateEnableTemporalRefinement","EXPERIMENTAL_annotationPollingIntervalInMs","getStreamAttributes","getBackgroundColor","getDeviceId","sceneReady","ViewerInitializationError","context","getContext","createScene","detail","forEach","fn","status","connectionChange","entries","dimensionsHaveChanged","contentRect","resizeTimer","isResizing","isResizeUpdate","recalculateComponentDimensions","mutationObserver","MutationObserver","childList","subtree","styleObserver","syncViewerStyles","attributes","attributeFilter","queryChildren","el","from","querySelectorAll","children","node","nodeName","startsWith","elements","backgroundColor","maxPixelCount","bounds","getBounds","measuredViewport","trimmedViewport","scaleFit","hostDimensions","getCanvasDimensions","getState","receiveToPaintDuration","getStream","recordPerformance","streamListeners","s","handleStreamStateChanged","previous","handleConnecting","handleConnected","handleConnectionFailed","handleDisconnected","emitConnectionChange","canvasRenderer","reportPerformance","jwt","deviceIdChange","getId","updateFrame","dimensionschange","previousFrame","SceneViewSummary.copySummaryIfInvalid","updateInteractionApi","updateCanvasDimensions","frameDimensions","frameReceived","hasChanged","sceneChanged","drawnFrame","updateViewerBackground","dispatchFrameDrawn","writeDOM","setProperty","toHexString","initializeDefaultTapInteractionHandler","interaction","clearDefaultCameraInteractionHandlers","baseDisposable","registerInteractionHandler","multiPointerDisposable","touchDisposable","clearDefaultKeyboardInteractions","setDefaultKeyboardControls","flyToPart","getImageScale","flyToPosition","registerTapKeyInteraction","tapHandlerDisposable","tapInteractionHandler","InteractionHandlerError","ComponentInitializationError","isPerspective","doubletap","longpress","interactionStarted","interactionFinished","cameraChanged","getActiveCursor","waitForConnectedState","Scene","imageBackground","viewerBackground","propertyColor","fromCss","letterboxFrames","depthBuffers","getDepthBufferStreamAttributesValue","featureHighlighting","featureMaps","frames","sceneComparison","selectionHighlighting","hasChangedFromPerspective","hasChangedFromOrthographic","cameraTypeChanged","replaceCamera","FrameCamera.toOrthographic","FrameCamera.toPerspective","resolvedConfig","getRequiredProp","DEVICE_ID","entry","onStateChanged","errorMsg","getter"],"mappings":"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","sourcesContent":["import { Point } from '@vertexvis/geometry';\nimport type { DecodedPng } from 'fast-png';\n\nimport { decodePng } from '../../workers/png-decoder-pool';\nimport { fromPbStencilBufferOrThrow } from '../mappers';\nimport { DepthBuffer } from './depthBuffer';\nimport { FrameImageLike } from './frame';\nimport { ImageAttributesLike } from './frame';\n\n/**\n * A value that represents if a pixel does not contain a stencil value.\n */\nexport const STENCIL_BUFFER_EMPTY_VALUE = 0;\n\n/**\n * A value that represents if a pixel contains a feature.\n */\nexport const STENCIL_BUFFER_FEATURE_VALUE = 255;\n\n/**\n * The `StencilBufferManager` manages the stencil buffer state for the viewer.\n * Stencil buffers are represented as images and contain additional information\n * related to the rendered frame. Examples of information contained within a\n * stencil buffer include: cross section and feature edge positions.\n *\n * This class contains methods for fetching a stencil buffer for the currently\n * rendered frame, as well as helpers that components can use to get an\n * up-to-date stencil buffer after any interactions are performed.\n */\nexport class StencilBufferManager {\n private pendingStencilBuffer?: Promise<StencilBuffer | undefined>;\n private pendingInteractionFinished?: Promise<void>;\n private pendingInteractionFinishedResolver?: () => void;\n\n /**\n * Constructs a new stencil buffer manager.\n *\n * **Note:** This class is only intended to be constructed by a viewer.\n *\n * @param viewer The viewer for this manager.\n */\n public constructor(private viewer: HTMLVertexViewerElement) {\n viewer.addEventListener(\n 'interactionStarted',\n this.handleInteractionStarted\n );\n viewer.addEventListener(\n 'interactionFinished',\n this.handleInteractionFinished\n );\n viewer.addEventListener('frameReceived', () => {\n this.invalidateStencilBuffer();\n });\n }\n\n /**\n * Fetches a stencil buffer for the last rendered frame. Returns `undefined`\n * if the last frame does not have stencil information.\n */\n public async fetch(): Promise<StencilBuffer | undefined> {\n const isReady = await this.viewer.isSceneReady();\n const scene = isReady ? await this.viewer.scene() : undefined;\n const hasStencil =\n scene != null\n ? scene.crossSectioning().current().sectionPlanes.length > 0 ||\n this.viewer.featureLines != null\n : false;\n const camera = this.viewer.frame?.scene.camera;\n\n if (hasStencil && this.viewer.stream != null && camera != null) {\n const res = await this.viewer.stream.getStencilBuffer({\n includeDepthBuffer: true,\n });\n const {\n stencilBuffer: sBytes,\n depthBuffer: dBytes,\n imageAttributes,\n } = fromPbStencilBufferOrThrow(res);\n\n const [stencilPng, depthPng] = await Promise.all([\n decodePng(new Uint8Array(sBytes)),\n decodePng(new Uint8Array(dBytes)),\n ]);\n\n return StencilBuffer.fromPng(\n stencilPng,\n imageAttributes,\n sBytes,\n DepthBuffer.fromPng(depthPng, camera, imageAttributes)\n );\n } else return undefined;\n }\n\n /**\n * Returns a promise that resolves with the last generated stencil buffer, or\n * fetches a new stencil buffer if the frame has changed since the last\n * stencil buffer was fetched. Because the stencil buffer is cached by the\n * manager, this method can be called multiple times without performing a\n * network request.\n *\n * @see {@link StencilBufferManager.latestAfterInteraction} to wait for\n * requesting a stencil buffer after an interaction has finished.\n */\n public latest(): Promise<StencilBuffer | undefined> {\n if (this.pendingStencilBuffer == null) {\n this.pendingStencilBuffer = this.fetch();\n }\n return this.pendingStencilBuffer;\n }\n\n /**\n * Returns a promise that resolves with the latest stencil buffer, once any\n * interaction is being performed. If no interaction is being performed, then\n * the promise will resolve immediately with the latest stencil buffer.\n *\n * This method is useful for components to fetch the most up-to-date stencil\n * buffer. Because the stencil buffer is cached by the manager, components can\n * call this method multiple times without performing a network request.\n *\n * @see {@link StencilBufferManager.latest} - used internally by this method.\n */\n public async latestAfterInteraction(): Promise<StencilBuffer | undefined> {\n await this.pendingInteractionFinished;\n return this.latest();\n }\n\n private handleInteractionStarted = (): void => {\n this.invalidateStencilBuffer();\n\n this.pendingInteractionFinished = new Promise((resolve) => {\n this.pendingInteractionFinishedResolver = resolve;\n });\n };\n\n private handleInteractionFinished = (): void => {\n this.pendingInteractionFinishedResolver?.();\n this.pendingInteractionFinished = undefined;\n this.pendingInteractionFinishedResolver = undefined;\n };\n\n private invalidateStencilBuffer = (): void => {\n this.pendingStencilBuffer = undefined;\n };\n}\n\n/**\n * Represents a stencil buffer that is managed by `StencilBufferManager`.\n *\n * @see {@link StencilBufferManager} for fetching a stencil buffer.\n */\nexport class StencilBuffer implements FrameImageLike {\n /**\n * Constructor.\n *\n * @param imageAttr The attributes of the stencil image.\n * @param imageBytes The original bytes for the image of the stencil buffer.\n * @param pixelBytes The PNG pixel data of the stencil buffer.\n * @param imageChannels The number of color channels.\n * @param depthBuffer The depth buffer associated with this stencil buffer.\n */\n public constructor(\n public readonly imageAttr: ImageAttributesLike,\n public readonly imageBytes: Uint8Array,\n public readonly pixelBytes: Uint8Array,\n public readonly imageChannels: number,\n public readonly depthBuffer: DepthBuffer\n ) {}\n\n /**\n * Constructs a new stencil buffer from a decoded PNG.\n *\n * @param png The decoded PNG.\n * @param imageAttr The attributes of the stencil image.\n * * @param imageBytes The original bytes for the image of the stencil buffer.\n * @param depthBuffer The depth buffer associated with this stencil buffer.\n */\n public static fromPng(\n png: Pick<DecodedPng, 'data' | 'channels'>,\n imageAttr: ImageAttributesLike,\n imageBytes: Uint8Array,\n depthBuffer: DepthBuffer\n ): StencilBuffer {\n if (!(png.data instanceof Uint8Array)) {\n throw new Error('Expected stencil PNG to have depth of 8-bit');\n } else if (png.channels !== 1) {\n throw new Error('Expected stencil PNG to have 1 color channel');\n } else {\n return new StencilBuffer(\n imageAttr,\n imageBytes,\n png.data,\n png.channels,\n depthBuffer\n );\n }\n }\n\n /**\n * Returns the color at the given frame position.\n *\n * @param pt A position within the frame.\n * @returns A color at the given position, or `undefined` if the color matches\n * the stencil buffer's empty color.\n * @see {@link Viewport.transformPointToFrame} to convert a viewport position\n * to frame position.\n */\n public getValue(pt: Point.Point): number {\n const { width, height } = this.imageAttr.imageRect;\n const offset = Point.subtract(pt, this.imageAttr.imageRect);\n const scale = 1 / this.imageAttr.imageScale;\n const pixel = Point.scale(offset, scale, scale);\n\n if (pixel.x >= 0 && pixel.y >= 0 && pixel.x < width && pixel.y < height) {\n const index = Math.floor(pixel.x) + Math.floor(pixel.y) * width;\n const value = this.pixelBytes[index];\n return value;\n } else return 0;\n }\n\n /**\n * Performs a hit test of the given point. Returns `true` if the point hits a\n * pixel in the stencil.\n *\n * @param pt A point within the stencil's frame.\n * @returns `true` if the point hits a pixel in the stencil, `false`\n * otherwise.\n */\n public hitTest(pt: Point.Point): boolean {\n return this.getValue(pt) !== STENCIL_BUFFER_EMPTY_VALUE;\n }\n\n /**\n * Returns the colored pixel nearest to the given `pt`. This method is useful\n * for performing snapping operations. An optional predicate can be provided\n * to filter the pixels that are evaluated.\n *\n * @param pt A position within the frame.\n * @param radius The radius around `pt` to evaluate.\n * @param predicate An optional predicate. If unspecified, any non-black\n * pixels are considered.\n * @returns A point within radius that matches the given predicate.\n * @see {@link Viewport.transformPointToFrame} to convert a viewport position\n * to frame position.\n */\n public snapToNearestPixel(\n pt: Point.Point,\n radius: number,\n predicate: (value: number) => boolean = () => true\n ): Point.Point {\n const diameter = radius * 2;\n const topLeft = Point.create(pt.x - radius, pt.y - radius);\n\n const pixels: Point.Point[] = [];\n\n for (let i = 0; i < diameter * diameter; i++) {\n const x = i % diameter;\n const y = Math.floor(i / diameter);\n const pixel = Point.add(topLeft, { x, y });\n\n if (Point.distance(pixel, pt) <= radius) {\n const value = this.getValue(pixel);\n if (value === STENCIL_BUFFER_FEATURE_VALUE && predicate(value)) {\n pixels.push(pixel);\n }\n }\n }\n\n const sorted = pixels.sort(\n (a, b) => Point.distance(a, pt) - Point.distance(b, pt)\n );\n const closest = sorted[0];\n return closest != null\n ? Point.create(Math.floor(closest.x) + 0.5, Math.floor(closest.y) + 0.5)\n : pt;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nasync function debugStencilBuffer(imageBytes: Uint8Array): Promise<void> {\n const blob = new Blob([imageBytes]);\n const bitmap = await createImageBitmap(blob);\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('2d');\n\n canvas.width = bitmap.width;\n canvas.height = bitmap.height;\n\n context?.drawImage(bitmap, 0, 0);\n\n console.log(canvas.toDataURL());\n}\n","export function isPromise<T>(obj: any): obj is Promise<T> {\n return (\n obj != null &&\n obj['then'] instanceof Function &&\n obj['catch'] instanceof Function &&\n // NOTE: Should be removed if we do not target ES2018.\n obj['finally'] instanceof Function\n );\n}\n","export function delay(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n","import type {\n CalloutAnnotationData,\n CustomAnnotationData,\n SceneAnnotation,\n SceneAnnotationSet,\n} from '@vertexvis/scene-view-protos/core/protos/scene_annotations_pb';\nimport { Mapper as M } from '@vertexvis/utils';\n\nimport { ViewerIconName } from '../../components/viewer-icon/viewer-icon';\nimport type {\n Annotation,\n AnnotationData,\n AnnotationSet,\n} from '../annotations/annotation';\nimport { fromPbTimestamp, fromPbUuid2l } from './corePb';\nimport { fromPbVector3f } from './geometry';\nimport { fromPbStringValue } from './scalar';\n\nexport const fromPbAnnotationSet: M.Func<SceneAnnotationSet, AnnotationSet> =\n M.defineMapper(\n M.compose(\n (input) => input.toObject(),\n M.read(\n M.mapRequiredProp('id', fromPbUuid2l),\n M.mapRequiredProp('createdAt', fromPbTimestamp),\n M.mapRequiredProp('modifiedAt', fromPbTimestamp),\n M.mapProp('name', fromPbStringValue),\n M.mapProp('suppliedId', fromPbStringValue)\n )\n ),\n ([id, createdAt, modifiedAt, name, suppliedId]) => ({\n id,\n createdAt,\n modifiedAt,\n name,\n suppliedId,\n })\n );\n\nexport const fromPbAnnotationSetOrThrow = M.ifInvalidThrow(fromPbAnnotationSet);\n\nexport const fromPbAnnotation: M.Func<SceneAnnotation, Annotation> =\n M.defineMapper(\n M.compose(\n (input) => input.toObject(),\n M.read(\n M.mapRequiredProp('id', fromPbUuid2l),\n M.mapRequiredProp('createdAt', fromPbTimestamp),\n M.mapRequiredProp('modifiedAt', fromPbTimestamp),\n M.mapProp('suppliedId', fromPbStringValue),\n M.mapRequiredProp('data', (data) => {\n if (data.callout != null) {\n return fromPbCalloutAnnotationData(data.callout);\n } else if (data.customJson != null) {\n return fromPbCustomAnnotationData(data.customJson);\n } else {\n throw new Error('Undefined or unknown annotation data.');\n }\n })\n )\n ),\n ([id, createdAt, modifiedAt, suppliedId, data]) => ({\n id,\n createdAt,\n modifiedAt,\n suppliedId,\n data,\n })\n );\n\nexport const fromPbAnnotationOrThrow = M.ifInvalidThrow(fromPbAnnotation);\n\nconst fromPbCalloutAnnotationData: M.Func<\n CalloutAnnotationData.AsObject,\n AnnotationData\n> = M.defineMapper(\n M.read(\n M.mapRequiredProp('position', fromPbVector3f),\n M.mapProp('icon', fromPbStringValue),\n M.mapProp('primaryColor', fromPbStringValue),\n M.mapProp('accentColor', fromPbStringValue)\n ),\n ([position, icon, primaryColor, accentColor]) => ({\n type: 'callout',\n position,\n icon: icon as ViewerIconName,\n primaryColor,\n accentColor,\n })\n);\n\nconst fromPbCustomAnnotationData: M.Func<\n CustomAnnotationData.AsObject,\n AnnotationData\n> = M.defineMapper(\n M.read(\n M.requiredProp('type'),\n M.mapRequiredProp('jsonData', (json) => JSON.parse(json))\n ),\n ([jsonType, jsonData]) => ({ type: 'custom', jsonType, jsonData })\n);\n","import { Uuid } from '@vertexvis/scene-tree-protos/core/protos/uuid_pb';\nimport { Pager } from '@vertexvis/scene-view-protos/core/protos/paging_pb';\nimport { Uuid2l } from '@vertexvis/scene-view-protos/core/protos/uuid_pb';\nimport {\n CreateSceneViewAnnotationSetRequest,\n DeleteSceneViewAnnotationSetRequest,\n ListSceneAnnotationsRequest,\n ListSceneAnnotationsResponse,\n ListSceneViewAnnotationSetsRequest,\n ListSceneViewAnnotationSetsResponse,\n} from '@vertexvis/scene-view-protos/sceneview/protos/scene_view_api_pb';\nimport { SceneViewAPIClient } from '@vertexvis/scene-view-protos/sceneview/protos/scene_view_api_pb_service';\nimport { Disposable, EventDispatcher, UUID } from '@vertexvis/utils';\nimport { Async } from '@vertexvis/utils';\n\nimport { delay } from '../../testing/utils';\nimport {\n createMetadata,\n JwtProvider,\n requestPaged,\n requestUnary,\n} from '../grpc';\nimport {\n fromPbAnnotationOrThrow,\n fromPbAnnotationSetOrThrow,\n} from '../mappers/annotation';\nimport { Annotation, AnnotationSet } from './annotation';\n\nexport interface AnnotationState {\n annotations: Record<AnnotationSet['id'], Annotation[]>;\n}\n\n/**\n * The controller for managing the annotations of a scene and scene view.\n */\nexport class AnnotationController {\n /**\n * A dispatcher that emits an event whenever the state of the annotations has\n * changed. The annotation state includes the annotation sets that are active\n * and the annotations that belong to each set.\n */\n public onStateChange = new EventDispatcher<AnnotationState>();\n\n private state?: AnnotationState;\n\n private connection?: Disposable;\n\n public constructor(\n private client: SceneViewAPIClient,\n private jwtProvider: JwtProvider,\n private deviceIdProvider: () => string | undefined\n ) {}\n\n /**\n * Activates an annotation set for the current session. This method will emit\n * an event on `onStateChange` when the annotation set has been added, and\n * return a promise the resolves with the new annotation state.\n *\n * @param id The ID of the annotation set.\n * @returns A promise that resolves with the new annotation state.\n */\n public async addAnnotationSet(id: UUID.UUID): Promise<AnnotationState> {\n await requestUnary(async (handler) => {\n const deviceId = this.deviceIdProvider();\n const meta = await createMetadata(this.jwtProvider, deviceId);\n\n const req = new CreateSceneViewAnnotationSetRequest();\n\n const setId = new Uuid();\n setId.setHex(id);\n req.setSceneAnnotationSetId(setId);\n\n this.client.createSceneViewAnnotationSet(req, meta, handler);\n });\n\n return this.fetch();\n }\n\n /**\n * Stops the automatic retrieval of annotation state.\n */\n public disconnect(): void {\n if (this.connection != null) {\n this.connection.dispose();\n this.connection = undefined;\n }\n }\n\n /**\n * Starts the automatic retrieval of annotation state. When a new annotation\n * state is retrieved, an event will be emitted on `onStateChange`.\n *\n * @param pollingIntervalInMs The interval to poll for a new annotation state.\n */\n public connect(pollingIntervalInMs = 10000): void {\n this.disconnect();\n\n const controller = this.pollAnnotationState(pollingIntervalInMs);\n this.connection = { dispose: () => controller.abort() };\n }\n\n /**\n * Performs a manual fetch of the annotation state. This method will emit an\n * event on `onStateChange` when the annotation set has been added, and return\n * a promise the resolves with the new annotation state.\n *\n * @param opts Options to configure the fetch behavior. If an abort signal is\n * given, then this will not emit an change event if the signal is aborted.\n * @returns A promise that resolves with the new annotation state.\n */\n public async fetch(\n opts: {\n signal?: AbortSignal;\n } = {}\n ): Promise<AnnotationState> {\n const sets = await this.fetchAnnotationSetsAsArray();\n const annotations = await this.fetchAnnotationsAsArray(sets);\n\n const state = (await Promise.all(annotations)).reduce(\n (state, [set, annotations]) => ({\n annotations: { ...state.annotations, [set.id]: annotations },\n }),\n { annotations: {} } as AnnotationState\n );\n\n if (opts.signal == null || !opts.signal.aborted) {\n this.updateState(state);\n }\n\n return state;\n }\n\n /**\n * Deactivates an annotation set for the current session. This method will\n * emit an event on `onStateChange` when the annotation set has been added,\n * and return a promise the resolves with the new annotation state.\n *\n * @param id The ID of the annotation set.\n * @returns A promise that resolves with the new annotation state.\n */\n public async removeAnnotationSet(id: UUID.UUID): Promise<AnnotationState> {\n await requestUnary(async (handler) => {\n const deviceId = this.deviceIdProvider();\n const meta = await createMetadata(this.jwtProvider, deviceId);\n const req = new DeleteSceneViewAnnotationSetRequest();\n\n const setId = new Uuid();\n setId.setHex(id);\n req.setSceneAnnotationSetId(setId);\n\n this.client.deleteSceneViewAnnotationSet(req, meta, handler);\n });\n\n return this.fetch();\n }\n\n private pollAnnotationState(pollingIntervalInMs: number): AbortController {\n const controller = new AbortController();\n\n const poll = async (delayMs: number): Promise<void> => {\n await this.fetch({ signal: controller.signal });\n\n if (!controller.signal.aborted) {\n await delay(delayMs);\n await poll(delayMs);\n }\n };\n\n Async.abort(controller.signal, poll(pollingIntervalInMs));\n return controller;\n }\n\n private fetchAnnotationSets(): AsyncGenerator<\n ListSceneViewAnnotationSetsResponse,\n void\n > {\n return requestPaged(\n (cursor) => async (handler) => {\n const deviceId = this.deviceIdProvider();\n const meta = await createMetadata(this.jwtProvider, deviceId);\n\n const req = new ListSceneViewAnnotationSetsRequest();\n\n if (cursor != null) {\n const page = new Pager();\n page.setCursor(cursor);\n page.setLimit(100);\n req.setPage(page);\n }\n\n this.client.listSceneViewAnnotationSets(req, meta, handler);\n },\n (res) => res.toObject().nextCursor?.next\n );\n }\n\n private async fetchAnnotationSetsAsArray(): Promise<AnnotationSet[]> {\n return (await Async.asArray(this.fetchAnnotationSets()))\n .flatMap((res) => res.getSceneAnnotationSetsList())\n .map((set) => fromPbAnnotationSetOrThrow(set));\n }\n\n private fetchAnnotations(\n setId: UUID.UUID\n ): AsyncGenerator<ListSceneAnnotationsResponse, void> {\n return requestPaged(\n (cursor) => async (handler) => {\n const deviceId = this.deviceIdProvider();\n const meta = await createMetadata(this.jwtProvider, deviceId);\n\n const setIdLong = UUID.toMsbLsb(setId);\n\n const id = new Uuid2l();\n id.setMsb(setIdLong.msb);\n id.setLsb(setIdLong.lsb);\n\n const req = new ListSceneAnnotationsRequest();\n req.setSceneAnnotationSetId(id);\n\n if (cursor != null) {\n const page = new Pager();\n page.setCursor(cursor);\n page.setLimit(100);\n req.setPage(page);\n }\n\n this.client.listSceneAnnotations(req, meta, handler);\n },\n (res) => res.toObject().nextCursor?.next\n );\n }\n\n private fetchAnnotationsAsArray(\n sets: AnnotationSet[]\n ): Promise<[AnnotationSet, Annotation[]][]> {\n const annotations = sets.map(async (set) => {\n const annotations = (await Async.asArray(this.fetchAnnotations(set.id)))\n .flatMap((ann) => ann.getSceneAnnotationsList())\n .map((ann) => fromPbAnnotationOrThrow(ann));\n return [set, annotations] as [AnnotationSet, Annotation[]];\n });\n\n return Promise.all(annotations);\n }\n\n private updateState(state: AnnotationState): void {\n this.state = state;\n this.onStateChange.emit(state);\n }\n}\n","import { Point } from '@vertexvis/geometry';\nimport { StreamApi, toProtoDuration } from '@vertexvis/stream-api';\n\nimport { ConfigProvider } from '../config';\nimport { ImageScaleProvider } from '../scenes';\nimport { KeyInteraction } from './keyInteraction';\nimport { TapEventDetails } from './tapEventDetails';\n\nexport class FlyToPartKeyInteraction\n implements KeyInteraction<TapEventDetails>\n{\n public constructor(\n private stream: StreamApi,\n private configProvider: ConfigProvider,\n private imageScaleProvider: ImageScaleProvider\n ) {}\n\n public predicate(e: TapEventDetails): boolean {\n return e.altKey && !e.shiftKey;\n }\n\n public async fn(e: TapEventDetails): Promise<void> {\n const scale = this.imageScaleProvider();\n const hitResult = await this.stream.hitItems(\n {\n point: Point.scale(e.position, scale?.x || 1, scale?.y || 1),\n },\n true\n );\n\n if (\n hitResult.hitItems?.hits != null &&\n hitResult.hitItems.hits.length > 0\n ) {\n await this.stream.flyTo({\n itemId: hitResult.hitItems.hits[0].itemId,\n animation: {\n duration: toProtoDuration(this.configProvider().animation.durationMs),\n },\n });\n } else {\n console.debug(\n `No hit results found for fly to part [position={x: ${e.position.x}, y: ${e.position.y}}]`\n );\n }\n }\n}\n","import { EventEmitter } from '@stencil/core';\nimport { vertexvis } from '@vertexvis/frame-streaming-protos';\nimport {\n Angle,\n BoundingBox,\n Plane,\n Point,\n Ray,\n Vector3,\n} from '@vertexvis/geometry';\nimport { StreamApi } from '@vertexvis/stream-api';\nimport { Disposable } from '@vertexvis/utils';\n\nimport { ReceivedFrame } from '../..';\nimport { Cursor, CursorManager } from '../cursors';\nimport { Camera, CameraRenderOptions, Scene } from '../scenes';\nimport {\n DepthBuffer,\n EntityType,\n FrameCameraBase,\n Interactions,\n Viewport,\n} from '../types';\nimport { TapEventDetails, TapEventKeys } from './tapEventDetails';\n\nexport type SceneProvider = () => Promise<Scene>;\n\nexport type InteractionConfigProvider = () => Interactions.InteractionConfig;\n\nexport type CameraTransform<\n T extends Camera = Camera,\n R extends Camera = Camera\n> = (data: {\n camera: T;\n viewport: Viewport;\n scale: Point.Point;\n boundingBox: BoundingBox.BoundingBox;\n frame: ReceivedFrame;\n depthBuffer?: DepthBuffer;\n}) => R;\n\nexport interface PanData {\n hitPt: Vector3.Vector3;\n hitPlane: Plane.Plane;\n startingCamera: FrameCameraBase;\n}\n\nexport interface ZoomData {\n hitPt: Vector3.Vector3;\n hitPlane: Plane.Plane;\n}\n\n/**\n * The `InteractionApi` provides methods that API developers can use to modify\n * the internal state of an interaction.\n */\nexport abstract class InteractionApi<T extends Camera = Camera> {\n protected currentCamera?: Camera;\n private sceneLoadingPromise?: Promise<Scene>;\n private lastAngle: Angle.Angle | undefined;\n private worldRotationPoint?: Vector3.Vector3;\n\n protected panData?: PanData;\n protected zoomData?: ZoomData;\n\n public constructor(\n protected stream: StreamApi,\n private cursors: CursorManager,\n protected getConfig: InteractionConfigProvider,\n protected getScene: SceneProvider,\n protected getFrame: () => ReceivedFrame | undefined,\n public getViewport: () => Viewport,\n private tapEmitter: EventEmitter<TapEventDetails>,\n private doubleTapEmitter: EventEmitter<TapEventDetails>,\n private longPressEmitter: EventEmitter<TapEventDetails>,\n private interactionStartedEmitter: EventEmitter<void>,\n private interactionFinishedEmitter: EventEmitter<void>,\n private cameraChangedEmitter: EventEmitter<FrameCameraBase | undefined>\n ) {\n this.tap = this.tap.bind(this);\n this.doubleTap = this.doubleTap.bind(this);\n this.longPress = this.longPress.bind(this);\n this.emitTapEvent = this.emitTapEvent.bind(this);\n }\n\n /**\n * Displays a cursor over the viewer with the given priority. Cursors with\n * higher priority will take precedence over cursors with lower priorities if\n * there's more than a single cursor added.\n *\n * @param cursor The cursor to add.\n * @param priority The priority of the cursor.\n * @returns A `Disposable` that can be used to remove the cursor.\n */\n public addCursor(cursor: Cursor, priority?: number): Disposable {\n return this.cursors.add(cursor, priority);\n }\n\n /**\n * Returns a 3D point in world space for the given 2D point in viewport space.\n *\n * @param point A point in 2D viewport space to transform.\n * @returns A 3D point in world space.\n */\n public async getWorldPointFromViewport(\n point: Point.Point\n ): Promise<Vector3.Vector3 | undefined> {\n const viewport = this.getViewport();\n const frame = this.getFrame();\n\n if (frame == null) {\n throw new Error('Cannot get world point. Frame is undefined.');\n }\n\n const depthBuffer = await frame.depthBuffer();\n return depthBuffer != null\n ? viewport.transformPointToWorldSpace(point, depthBuffer, 0.5)\n : undefined;\n }\n\n /**\n * Returns the entity at the given point in viewport space.\n *\n * @param point A point in viewport space.\n * @returns The entity that was found.\n */\n public async getEntityTypeAtPoint(point: Point.Point): Promise<EntityType> {\n const viewport = this.getViewport();\n const featureMap = await this.getFrame()?.featureMap();\n\n if (featureMap != null) {\n const framePt = viewport.transformPointToFrame(point, featureMap);\n return featureMap.getEntityType(framePt);\n } else {\n return EntityType.NO_GEOMETRY;\n }\n }\n\n /**\n * Generates a ray from the given point, in viewport coordinates.\n *\n * @param point A point in viewport coordinates.\n * @returns A ray representing the direction of the point in world\n * coordinates.\n */\n public getRayFromPoint(point: Point.Point): Ray.Ray {\n const viewport = this.getViewport();\n const frame = this.getFrame();\n\n if (frame != null) {\n return viewport.transformPointToRay(\n point,\n frame.image,\n frame.scene.camera\n );\n } else throw new Error('Cannot get camera. Frame is undefined.');\n }\n\n /**\n * Emits a tap event with the provided position relative to the viewer\n * canvas, along with the set of modifier keys held (if applicable).\n *\n * @param position An {x, y} coordinate marking the position of the tap.\n * @param keyDetails A set of pressed keyboard keys that you want to include\n * in the tap event.\n */\n public async tap(\n position: Point.Point,\n keyDetails: Partial<TapEventKeys> = {},\n buttons = 0\n ): Promise<void> {\n this.emitTapEvent(this.tapEmitter.emit, position, keyDetails, buttons);\n }\n\n public async doubleTap(\n position: Point.Point,\n keyDetails: Partial<TapEventKeys> = {},\n buttons = 0\n ): Promise<void> {\n this.emitTapEvent(\n this.doubleTapEmitter.emit,\n position,\n keyDetails,\n buttons\n );\n }\n\n public async longPress(\n position: Point.Point,\n keyDetails: Partial<TapEventKeys> = {},\n buttons = 0\n ): Promise<void> {\n this.emitTapEvent(\n this.longPressEmitter.emit,\n position,\n keyDetails,\n buttons\n );\n }\n\n /**\n * Marks the start of an interaction. This method must be called before\n * performing any additional interaction operations. Use `endInteraction()` to\n * mark the end of an interaction.\n */\n public async beginInteraction(): Promise<void> {\n if (!this.isInteracting()) {\n this.interactionStartedEmitter.emit();\n this.sceneLoadingPromise = this.getScene();\n this.currentCamera = (await this.sceneLoadingPromise).camera();\n this.sceneLoadingPromise = undefined;\n await this.stream.beginInteraction();\n }\n }\n\n /**\n * Invokes a function to transform the scene's camera and request a new image\n * for the updated scene.\n *\n * @param t A function to transform the camera. Function will be passed the\n * camera and scene viewport and is expected to return an updated camera.\n */\n public async transformCamera(t: CameraTransform<T>): Promise<void>;\n public async transformCamera(\n t: CameraTransform<T>,\n renderOptions?: CameraRenderOptions\n ): Promise<void>;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public async transformCamera(...args: any[]): Promise<void> {\n const t = args[0];\n const renderOptions = args[1];\n\n if (this.isInteracting()) {\n const scene = await this.getScene();\n const viewport = this.getViewport();\n const frame = this.getFrame();\n const depthBuffer = await frame?.depthBuffer();\n\n this.currentCamera =\n this.currentCamera != null && viewport != null && frame != null\n ? t({\n camera: this.currentCamera,\n viewport,\n scale: scene.scale(),\n boundingBox: scene.boundingBox(),\n frame,\n depthBuffer,\n })\n : undefined;\n\n this.cameraChangedEmitter.emit(this.currentCamera?.toFrameCamera());\n\n await this.currentCamera?.render(renderOptions);\n }\n }\n\n /**\n * Performs a twist operation of the scene's camera, and requests a new image\n * for the updated scene.\n *\n * @param delta A position delta `{x, y}` in the 2D coordinate space of the\n * viewer or the angle to twist the camera by around the view vector.\n */\n public async twistCamera(delta: number): Promise<void>;\n public async twistCamera(delta: Point.Point): Promise<void>;\n public async twistCamera(...args: any[]): Promise<void> {\n return this.transformCamera(({ camera, viewport }) => {\n const axis = Vector3.normalize(\n Vector3.subtract(camera.lookAt, camera.position)\n );\n\n if (args.length === 1 && typeof args[0] === 'number') {\n const angleInRadians = Angle.toRadians(-args[0]);\n return camera.rotateAroundAxis(angleInRadians, axis);\n } else if (args.length === 1) {\n const center = Point.create(viewport.width / 2, viewport.height / 2);\n const currentAngle = Angle.toDegrees(Angle.fromPoints(center, args[0]));\n const angleDelta =\n this.lastAngle != null ? currentAngle - this.lastAngle : 0;\n\n this.lastAngle = currentAngle;\n const axis = Vector3.normalize(\n Vector3.subtract(camera.lookAt, camera.position)\n );\n const angleInRadians = Angle.toRadians(-angleDelta);\n return camera.rotateAroundAxis(angleInRadians, axis);\n }\n return camera;\n });\n }\n\n /**\n * Moves the camera's position and look at to the given screen coordinate.\n *\n * If the screen coordinate intersects with an object, the camera will track\n * the hit point so the mouse position is always under the mouse.\n *\n * If the screen coordinate doesn't intersect with an object, then ???.\n *\n * @param screenPt A point in screen coordinates.\n */\n public async panCameraToScreenPoint(screenPt: Point.Point): Promise<void> {\n return this.transformCamera(({ camera, frame, viewport, depthBuffer }) => {\n // Capture the starting state of the pan.\n if (this.panData == null) {\n const startingCamera = camera.toFrameCamera();\n const direction = startingCamera.direction;\n\n const ray = viewport.transformPointToRay(\n screenPt,\n frame.image,\n startingCamera\n );\n const fallbackPlane = Plane.fromNormalAndCoplanarPoint(\n direction,\n camera.lookAt\n );\n const fallback = Ray.intersectPlane(ray, fallbackPlane);\n if (fallback == null) {\n console.warn(\n 'Cannot determine fallback for pan. Ray does not intersect plane.'\n );\n return camera;\n }\n\n // Create a plane for the hit point that will be used to determine the\n // delta of future mouse movements to the original hit point. Fallback\n // to a plane placed at the look at point, in case there's no hit.\n const hitPt =\n depthBuffer != null\n ? this.getWorldPoint(screenPt, depthBuffer, fallback)\n : fallback;\n const hitPlane = Plane.fromNormalAndCoplanarPoint(direction, hitPt);\n\n this.panData = { hitPt, hitPlane, startingCamera };\n }\n\n if (this.panData != null) {\n const { hitPt, hitPlane, startingCamera } = this.panData;\n\n // Use a ray that originates at the screen and intersects with the hit\n // plane to determine the move distance.\n const ray = viewport.transformPointToRay(\n screenPt,\n frame.image,\n startingCamera\n );\n const movePt = Ray.intersectPlane(ray, hitPlane);\n\n if (movePt != null) {\n const delta = Vector3.subtract(hitPt, movePt);\n return camera.update(startingCamera).moveBy(delta);\n }\n }\n return camera;\n });\n }\n\n /**\n * Performs a view all operation for the scene's bounding box, and requests a\n * new image for the updated scene.\n */\n public async viewAll(): Promise<void> {\n await (await this.getScene()).camera().viewAll().render();\n }\n\n /**\n * Performs a rotate operation of the scene around the camera's look at point,\n * and requests a new image for the updated scene.\n *\n * @param delta A position delta `{x, y}` in the 2D coordinate space of the\n * viewer.\n */\n public async rotateCamera(delta: Point.Point): Promise<void> {\n return this.transformCamera(({ camera, viewport, boundingBox }) => {\n const upVector = Vector3.normalize(camera.up);\n const directionVector = Vector3.normalize(\n Vector3.subtract(camera.lookAt, camera.position)\n );\n const crossX = Vector3.cross(upVector, directionVector);\n const crossY = Vector3.cross(directionVector, crossX);\n\n const mouseToWorld = Vector3.normalize({\n x: delta.x * crossX.x + delta.y * crossY.x,\n y: delta.x * crossX.y + delta.y * crossY.y,\n z: delta.x * crossX.z + delta.y * crossY.z,\n });\n\n const rotationAxis = Vector3.cross(mouseToWorld, directionVector);\n\n // The 9.5 multiplier was chosen to match the desired rotation speed\n const epsilonX = (9.5 * delta.x) / viewport.width;\n const epsilonY = (9.5 * delta.y) / viewport.height;\n const angle = Math.abs(epsilonX) + Math.abs(epsilonY);\n\n return camera.rotateAroundAxis(angle, rotationAxis);\n });\n }\n\n public async rotateCameraAtPoint(\n delta: Point.Point,\n point: Point.Point\n ): Promise<void> {\n return this.transformCamera(\n ({ camera, viewport, boundingBox, depthBuffer }) => {\n if (this.worldRotationPoint == null) {\n const worldCenter = BoundingBox.center(boundingBox);\n this.worldRotationPoint =\n depthBuffer != null\n ? this.getWorldPoint(point, depthBuffer, worldCenter)\n : camera.lookAt;\n }\n\n const upVector = Vector3.normalize(camera.up);\n const vv = Vector3.normalize(\n Vector3.subtract(camera.lookAt, camera.position)\n );\n\n const crossX = Vector3.cross(upVector, vv);\n const crossY = Vector3.cross(vv, crossX);\n\n const mouseToWorld = Vector3.normalize({\n x: delta.x * crossX.x + delta.y * crossY.x,\n y: delta.x * crossX.y + delta.y * crossY.y,\n z: delta.x * crossX.z + delta.y * crossY.z,\n });\n\n const rotationAxis = Vector3.cross(mouseToWorld, vv);\n\n // The 9.5 multiplier was chosen to match the desired rotation speed\n const epsilonX = (9.5 * delta.x) / viewport.width;\n const epsilonY = (9.5 * delta.y) / viewport.height;\n const angle = Math.abs(epsilonX) + Math.abs(epsilonY);\n\n const updated = camera.rotateAroundAxisAtPoint(\n angle,\n this.worldRotationPoint,\n rotationAxis\n );\n\n return updated.update({\n // Scale the lookAt point to the same length as the distance to the\n // center of the bounding box to maintain zoom and pan behavior.\n lookAt: Vector3.add(\n Vector3.scale(\n Math.abs(camera.signedDistanceToBoundingBoxCenter()) /\n Vector3.magnitude(updated.viewVector),\n updated.viewVector\n ),\n updated.position\n ),\n });\n }\n );\n }\n\n /**\n * Performs a zoom operation of the scene's camera, and requests a new image\n * for the updated scene.\n *\n * @param delta The distance to zoom. Positive values zoom in and negative\n * values zoom out.\n */\n public async zoomCamera(delta: number): Promise<void> {\n return this.transformCamera(({ camera, viewport }) => {\n const vv = camera.viewVector;\n const v = Vector3.normalize(vv);\n\n const distance = Vector3.magnitude(vv);\n const epsilon = (3 * distance * delta) / viewport.height;\n\n const position = Vector3.add(camera.position, Vector3.scale(epsilon, v));\n const newCamera = camera.update({ position });\n return newCamera;\n });\n }\n\n /**\n * Performs a pivot operation of the scene's camera, updating the lookAt\n * while maintaining the position, and requests a new image for the\n * updated scene.\n *\n * @param degreesLocalX The angle to rotate the lookAt point around the local x-axis\n * @param degreesLocalY The angle to rotate the lookAt point around the local y-axis\n */\n public async pivotCamera(\n degreesLocalX: number,\n degreesLocalY: number\n ): Promise<void> {\n return this.transformCamera(({ camera }) => {\n const { position, up, lookAt } = camera;\n const normalizedUp = Vector3.normalize(up);\n const normalizedViewVector = Vector3.normalize(camera.viewVector);\n const xVector = Vector3.cross(normalizedUp, normalizedViewVector);\n const yVector = Vector3.cross(normalizedViewVector, xVector);\n\n const updatedLookAtX = Vector3.rotateAboutAxis(\n Angle.toRadians(degreesLocalX),\n lookAt,\n xVector,\n position\n );\n const updatedLookAtY = Vector3.rotateAboutAxis(\n Angle.toRadians(degreesLocalY),\n updatedLookAtX,\n yVector,\n position\n );\n\n return camera.update({ ...camera, lookAt: updatedLookAtY });\n });\n }\n\n /**\n * Marks the end of an interaction.\n */\n public async endInteraction(): Promise<void> {\n await this.sceneLoadingPromise;\n\n if (this.isInteracting()) {\n this.currentCamera = undefined;\n this.worldRotationPoint = undefined;\n this.panData = undefined;\n this.zoomData = undefined;\n this.resetLastAngle();\n\n this.interactionFinishedEmitter.emit();\n await this.stream.endInteraction();\n }\n }\n\n /**\n * resets the last recorded angle for a twist op\n */\n public resetLastAngle(): void {\n this.lastAngle = undefined;\n }\n\n /**\n * Indicates if the API is in an interacting state.\n */\n public isInteracting(): boolean {\n return this.currentCamera != null;\n }\n\n /**\n * Returns the pixel threshold that should be used to detect\n * movement based on the type of pointer input being coarse or fine.\n * This threshold is based on the configured `coarsePointerThreshold`\n * or the `finePointerThreshold` respectively.\n *\n * @param isTouch - Whether the event is a touch or not, if false or\n * undefined, a media query will be used to determine pointer type\n * @returns The pixel threshold.\n */\n public pixelThreshold(isTouch?: boolean): number {\n const pixelThreshold = this.isCoarseInputDevice(isTouch)\n ? this.getConfig().coarsePointerThreshold\n : this.getConfig().finePointerThreshold;\n\n return pixelThreshold * window.devicePixelRatio;\n }\n\n /**\n * Performs a hit test at the given point and returns a list of hit results\n * indicating any scene items that exist at the given point.\n *\n * @param pt A point, in viewport coordinates.\n * @returns A promise that resolves with the list of hit results.\n */\n public async hitItems(\n pt: Point.Point\n ): Promise<vertexvis.protobuf.stream.IHit[]> {\n const res = await (await this.getScene()).raycaster().hitItems(pt);\n return res?.hits ?? [];\n }\n\n private emitTapEvent(\n emit: (details: TapEventDetails) => void,\n position: Point.Point,\n keyDetails: Partial<TapEventKeys> = {},\n buttons = 0\n ): void {\n const {\n altKey = false,\n ctrlKey = false,\n metaKey = false,\n shiftKey = false,\n } = keyDetails;\n emit({\n position,\n altKey,\n ctrlKey,\n metaKey,\n shiftKey,\n buttons,\n });\n }\n\n private isCoarseInputDevice(isTouch?: boolean): boolean {\n return isTouch || window.matchMedia('(pointer: coarse)').matches;\n }\n\n protected getWorldPoint(\n point: Point.Point,\n depthBuffer: DepthBuffer,\n fallbackPoint: Vector3.Vector3\n ): Vector3.Vector3 {\n const viewport = this.getViewport();\n const framePt = viewport.transformPointToFrame(point, depthBuffer);\n const hasDepth = depthBuffer.hitTest(framePt);\n return hasDepth\n ? viewport.transformPointToWorldSpace(point, depthBuffer)\n : fallbackPoint;\n }\n\n /**\n * Performs a pan operation of the scene's camera, and requests a new image\n * for the updated scene.\n *\n * @param delta A position delta `{x, y}` in the 2D coordinate space of the\n * viewer.\n */\n public abstract panCameraByDelta(delta: Point.Point): Promise<void>;\n\n public abstract zoomCameraToPoint(\n point: Point.Point,\n delta: number\n ): Promise<void>;\n}\n","import { EventEmitter } from '@stencil/core';\nimport { BoundingBox, Plane, Point, Ray, Vector3 } from '@vertexvis/geometry';\nimport { StreamApi } from '@vertexvis/stream-api';\n\nimport { ReceivedFrame } from '../..';\nimport { CursorManager } from '../cursors';\nimport { updateLookAtRelativeToBoundingBoxCenter } from '../rendering/vectors';\nimport { OrthographicCamera } from '../scenes';\nimport { DepthBuffer, FrameCameraBase, Viewport } from '../types';\nimport { ZoomData } from './interactionApi';\nimport {\n InteractionApi,\n InteractionConfigProvider,\n SceneProvider,\n} from './interactionApi';\nimport { TapEventDetails } from './tapEventDetails';\n\ninterface OrthographicZoomData extends ZoomData {\n startingScreenPt: Point.Point;\n}\n\nexport class InteractionApiOrthographic extends InteractionApi<OrthographicCamera> {\n private orthographicZoomData?: OrthographicZoomData;\n\n public constructor(\n stream: StreamApi,\n cursors: CursorManager,\n getConfig: InteractionConfigProvider,\n getScene: SceneProvider,\n getFrame: () => ReceivedFrame | undefined,\n getViewport: () => Viewport,\n tapEmitter: EventEmitter<TapEventDetails>,\n doubleTapEmitter: EventEmitter<TapEventDetails>,\n longPressEmitter: EventEmitter<TapEventDetails>,\n interactionStartedEmitter: EventEmitter<void>,\n interactionFinishedEmitter: EventEmitter<void>,\n cameraChangedEmitter: EventEmitter<FrameCameraBase | undefined>\n ) {\n super(\n stream,\n cursors,\n getConfig,\n getScene,\n getFrame,\n getViewport,\n tapEmitter,\n doubleTapEmitter,\n longPressEmitter,\n interactionStartedEmitter,\n interactionFinishedEmitter,\n cameraChangedEmitter\n );\n }\n\n /**\n * Returns a 3D point in world space for the given 2D point in viewport space.\n *\n * @param point A point in 2D viewport space to transform.\n * @returns A 3D point in world space.\n */\n public async getWorldPointFromViewport(\n point: Point.Point\n ): Promise<Vector3.Vector3 | undefined> {\n const viewport = this.getViewport();\n const frame = this.getFrame();\n\n if (frame == null) {\n throw new Error('Cannot get world point. Frame is undefined.');\n }\n\n const depthBuffer = await frame.depthBuffer();\n return depthBuffer != null\n ? viewport.transformPointToWorldSpace(point, depthBuffer, 0.5)\n : undefined;\n }\n\n /**\n * Performs a pan operation of the scene's camera, and requests a new image\n * for the updated scene.\n *\n * @param delta A position delta `{x, y}` in the 2D coordinate space of the\n * viewer.\n */\n public async panCameraByDelta(delta: Point.Point): Promise<void> {\n return this.transformCamera(({ camera, viewport }) => {\n const viewVector = camera.viewVector;\n const normalizedUpVector = Vector3.normalize(camera.up);\n const normalizedViewVector = Vector3.normalize(viewVector);\n\n const throttledDelta = Point.scale(delta, 0.5, 0.5);\n const d = Vector3.magnitude(viewVector);\n const epsilonX = (throttledDelta.x * d) / viewport.width;\n const epsilonY = (throttledDelta.y * d) / viewport.height;\n\n const xvec = Vector3.cross(normalizedUpVector, normalizedViewVector);\n const yvec = Vector3.cross(normalizedViewVector, xvec);\n const offset = Vector3.add(\n Vector3.scale(epsilonX, xvec),\n Vector3.scale(epsilonY, yvec)\n );\n\n return camera.moveBy(offset);\n });\n }\n\n /**\n * Moves the camera's position and look at to the given screen coordinate.\n *\n * If the screen coordinate intersects with an object, the camera will track\n * the hit point so the mouse position is always under the mouse.\n *\n * If the screen coordinate doesn't intersect with an object, then ???.\n *\n * @param screenPt A point in screen coordinates.\n */\n public async panCameraToScreenPoint(screenPt: Point.Point): Promise<void> {\n return this.transformCamera(({ camera, frame, viewport, boundingBox }) => {\n // Capture the starting state of the pan.\n if (this.panData == null) {\n const startingCamera = camera.toFrameCamera();\n const direction = startingCamera.direction;\n\n const ray = viewport.transformPointToRay(\n screenPt,\n frame.image,\n startingCamera\n );\n const hitPlane = Plane.fromNormalAndCoplanarPoint(\n direction,\n camera.lookAt\n );\n const hitPt = Ray.intersectPlane(ray, hitPlane);\n if (hitPt == null) {\n console.warn(\n 'Cannot determine fallback for pan. Ray does not intersect plane.'\n );\n return camera;\n }\n\n this.panData = { hitPt, hitPlane, startingCamera };\n }\n\n if (this.panData != null) {\n const { hitPt, hitPlane, startingCamera } = this.panData;\n\n // Use a ray that originates at the screen and intersects with the hit\n // plane to determine the move distance.\n const ray = viewport.transformPointToRay(\n screenPt,\n frame.image,\n startingCamera\n );\n const movePt = Ray.intersectPlane(ray, hitPlane);\n\n if (movePt != null) {\n const delta = Vector3.subtract(hitPt, movePt);\n\n // rotationPoint should match lookAt after a pan interaction\n const updatedLookAt = Vector3.add(startingCamera.lookAt, delta);\n return camera.update({\n lookAt: updatedLookAt,\n rotationPoint: updatedLookAt,\n });\n }\n }\n return camera;\n });\n }\n\n public async zoomCameraToPoint(\n point: Point.Point,\n delta: number\n ): Promise<void> {\n return this.transformCamera(\n ({ camera, viewport, frame, depthBuffer, boundingBox }) => {\n if (\n this.orthographicZoomData == null ||\n Point.distance(point, this.orthographicZoomData.startingScreenPt) > 2\n ) {\n const frameCam = camera.toFrameCamera();\n const dir = frameCam.direction;\n const ray = viewport.transformPointToRay(\n point,\n frame.image,\n frameCam\n );\n\n const fallbackPlane = Plane.fromNormalAndCoplanarPoint(\n dir,\n frameCam.lookAt\n );\n const fallbackPt = Ray.intersectPlane(ray, fallbackPlane);\n if (fallbackPt == null) {\n console.warn(\n 'Cannot determine fallback point for zoom. Ray does not intersect plane.'\n );\n return camera;\n }\n\n const hitPt =\n depthBuffer != null\n ? this.getWorldPoint(point, depthBuffer, fallbackPt)\n : fallbackPt;\n const hitPlane = Plane.fromNormalAndCoplanarPoint(dir, hitPt);\n this.orthographicZoomData = {\n hitPt,\n hitPlane,\n startingScreenPt: point,\n };\n }\n\n if (this.orthographicZoomData != null) {\n const { hitPt, hitPlane } = this.orthographicZoomData;\n\n // The 4 multiplier was chosen to match the desired zoom speed\n const relativeDelta =\n 4 * (camera.fovHeight / viewport.height) * delta;\n const fovHeight = Math.max(1, camera.fovHeight - relativeDelta);\n const projectedLookAt = Plane.projectPoint(hitPlane, camera.lookAt);\n const diff = Vector3.scale(\n (camera.fovHeight - fovHeight) / camera.fovHeight,\n Vector3.subtract(hitPt, projectedLookAt)\n );\n\n // rotationPoint should match lookAt after a zoom interaction\n const updatedLookAt = Vector3.add(camera.lookAt, diff);\n return camera.update({\n lookAt: updatedLookAt,\n rotationPoint: updatedLookAt,\n fovHeight: Math.max(1, camera.fovHeight - relativeDelta),\n });\n }\n return camera;\n }\n );\n }\n\n /**\n * Performs a rotate operation of the scene around the camera's look at point,\n * and requests a new image for the updated scene.\n *\n * @param delta A position delta `{x, y}` in the 2D coordinate space of the\n * viewer.\n */\n public async rotateCamera(delta: Point.Point): Promise<void> {\n return this.transformCamera(({ camera, viewport, boundingBox }) => {\n const upVector = Vector3.normalize(camera.up);\n const directionVector = Vector3.normalize(\n Vector3.subtract(camera.lookAt, camera.position)\n );\n\n const crossX = Vector3.cross(upVector, directionVector);\n const crossY = Vector3.cross(directionVector, crossX);\n\n const mouseToWorld = Vector3.normalize({\n x: delta.x * crossX.x + delta.y * crossY.x,\n y: delta.x * crossX.y + delta.y * crossY.y,\n z: delta.x * crossX.z + delta.y * crossY.z,\n });\n\n const rotationAxisDirection = Vector3.cross(\n mouseToWorld,\n directionVector\n );\n\n // The 9.5 multiplier was chosen to match the desired rotation speed\n const epsilonX = (9.5 * delta.x) / viewport.width;\n const epsilonY = (9.5 * delta.y) / viewport.height;\n const angle = Math.abs(epsilonX) + Math.abs(epsilonY);\n\n const rotationPoint =\n camera.rotationPoint != null && camera.rotationPoint?.x != null\n ? camera.rotationPoint\n : camera.lookAt;\n const updated = camera.rotateAroundAxisAtPoint(\n angle,\n rotationPoint,\n rotationAxisDirection\n );\n\n // Update the lookAt point to take the center of the model into account\n // This change helps ensure that the lookAt point is consistent between\n // the SDK and back-end system such that the calculated depth buffer is correct.\n const newLookAt = updateLookAtRelativeToBoundingBoxCenter(\n updated.lookAt,\n updated.viewVector,\n BoundingBox.center(boundingBox)\n );\n\n // Update only the lookAt point. The rotationPoint should remain\n // constant until a different type of interaction is performed.\n return updated.update({\n lookAt: newLookAt,\n });\n });\n }\n\n protected getWorldPoint(\n point: Point.Point,\n depthBuffer: DepthBuffer,\n fallbackPoint: Vector3.Vector3\n ): Vector3.Vector3 {\n const viewport = this.getViewport();\n const framePt = viewport.transformPointToFrame(point, depthBuffer);\n const hasDepth = depthBuffer.hitTest(framePt);\n return hasDepth\n ? viewport.transformPointToWorldSpace(point, depthBuffer)\n : fallbackPoint;\n }\n}\n","import { EventEmitter } from '@stencil/core';\nimport { BoundingBox, Plane, Point, Ray, Vector3 } from '@vertexvis/geometry';\nimport { StreamApi } from '@vertexvis/stream-api';\n\nimport { ReceivedFrame } from '../..';\nimport { CursorManager } from '../cursors';\nimport { PerspectiveCamera } from '../scenes';\nimport { FrameCameraBase, Viewport } from '../types';\nimport {\n InteractionApi,\n InteractionConfigProvider,\n SceneProvider,\n ZoomData,\n} from './interactionApi';\nimport { TapEventDetails } from './tapEventDetails';\n\ninterface ZoomPositionData {\n position: Vector3.Vector3;\n distance: number;\n isPastHitPlane: boolean;\n keepCurrent: boolean;\n}\n\nconst CAMERA_MIN_ZOOM_SCALAR = 0.2;\n\nexport class InteractionApiPerspective extends InteractionApi<PerspectiveCamera> {\n public constructor(\n stream: StreamApi,\n cursors: CursorManager,\n getConfig: InteractionConfigProvider,\n getScene: SceneProvider,\n getFrame: () => ReceivedFrame | undefined,\n getViewport: () => Viewport,\n tapEmitter: EventEmitter<TapEventDetails>,\n doubleTapEmitter: EventEmitter<TapEventDetails>,\n longPressEmitter: EventEmitter<TapEventDetails>,\n interactionStartedEmitter: EventEmitter<void>,\n interactionFinishedEmitter: EventEmitter<void>,\n cameraChangedEmitter: EventEmitter<FrameCameraBase | undefined>\n ) {\n super(\n stream,\n cursors,\n getConfig,\n getScene,\n getFrame,\n getViewport,\n tapEmitter,\n doubleTapEmitter,\n longPressEmitter,\n interactionStartedEmitter,\n interactionFinishedEmitter,\n cameraChangedEmitter\n );\n }\n\n /**\n * Performs a pan operation of the scene's camera, and requests a new image\n * for the updated scene.\n *\n * @param delta A position delta `{x, y}` in the 2D coordinate space of the\n * viewer.\n */\n public async panCameraByDelta(delta: Point.Point): Promise<void> {\n return this.transformCamera(({ camera, viewport }) => {\n const vv = camera.viewVector;\n\n const u = Vector3.normalize(camera.up);\n const v = Vector3.normalize(vv);\n\n const throttledDelta = Point.scale(delta, 0.25, 0.25);\n const d = Vector3.magnitude(vv) * Math.tan(camera.fovY ?? 45);\n const epsilonX = (throttledDelta.x * d) / viewport.width;\n const epsilonY = (throttledDelta.y / viewport.width) * d;\n\n const xvec = Vector3.cross(u, v);\n const yvec = Vector3.cross(v, xvec);\n\n const offset = Vector3.add(\n Vector3.scale(epsilonX, xvec),\n Vector3.scale(epsilonY, yvec)\n );\n\n return camera.moveBy(offset);\n });\n }\n\n public async zoomCameraToPoint(\n point: Point.Point,\n delta: number\n ): Promise<void> {\n return this.transformCamera(\n ({ camera, viewport, frame, depthBuffer, boundingBox }) => {\n const cam = frame.scene.camera;\n const dir = cam.direction;\n\n const frameCam = camera.toFrameCamera();\n const ray = viewport.transformPointToRay(point, frame.image, frameCam);\n\n if (this.zoomData == null) {\n const fallbackPlane = Plane.fromNormalAndCoplanarPoint(\n dir,\n cam.lookAt\n );\n const fallbackPt = Ray.intersectPlane(ray, fallbackPlane);\n if (fallbackPt == null) {\n console.warn(\n 'Cannot determine fallback point for zoom. Ray does not intersect plane.'\n );\n return camera;\n }\n\n const hitPt =\n depthBuffer != null\n ? this.getWorldPoint(point, depthBuffer, fallbackPt)\n : fallbackPt;\n const hitPlane = Plane.fromNormalAndCoplanarPoint(dir, hitPt);\n this.zoomData = { hitPt, hitPlane };\n }\n\n if (this.zoomData != null) {\n const { hitPlane } = this.zoomData;\n const { position, distance, isPastHitPlane, keepCurrent } =\n this.computeZoomDistances(\n delta,\n camera,\n viewport,\n boundingBox,\n ray,\n this.zoomData\n );\n\n if (isPastHitPlane && !keepCurrent) {\n const viewVectorRay = Ray.create({\n origin: position,\n direction: Vector3.normalize(camera.viewVector),\n });\n\n return camera.update({\n position,\n lookAt: Ray.at(viewVectorRay, distance),\n });\n } else if (!keepCurrent) {\n return camera.update({\n position,\n lookAt: Plane.projectPoint(hitPlane, position),\n });\n }\n }\n return camera;\n }\n );\n }\n\n public walk(delta: Vector3.Vector3): void {\n this.transformCamera(({ camera, boundingBox }) => {\n const { position, up, lookAt } = camera;\n\n const normalizedUp = Vector3.normalize(up);\n const normalizedViewVector = Vector3.normalize(camera.viewVector);\n\n const boundingBoxScalar = Math.min(\n ...Vector3.toArray(BoundingBox.lengths(boundingBox))\n );\n const scaledDelta = Vector3.scale(boundingBoxScalar, delta);\n const localX = Vector3.cross(normalizedUp, normalizedViewVector);\n const localZ = Vector3.cross(localX, normalizedUp);\n\n const translationX = Vector3.scale(\n scaledDelta.x,\n Vector3.normalize(localX)\n );\n const translationY = Vector3.scale(\n scaledDelta.y,\n Vector3.normalize(normalizedUp)\n );\n const translationZ = Vector3.scale(\n scaledDelta.z,\n Vector3.normalize(localZ)\n );\n const translation = Vector3.negate(\n Vector3.add(translationX, translationY, translationZ)\n );\n\n return camera.update({\n ...camera,\n position: Vector3.add(position, translation),\n lookAt: Vector3.add(lookAt, translation),\n });\n });\n }\n\n private computeZoomDistances(\n delta: number,\n camera: PerspectiveCamera,\n viewport: Viewport,\n boundingBox: BoundingBox.BoundingBox,\n pointRay: Ray.Ray,\n zoomData: ZoomData\n ): ZoomPositionData {\n const config = this.getConfig();\n const { hitPt, hitPlane } = zoomData;\n const minDistance = config.useMinimumPerspectiveZoomDistance\n ? this.computeZoomMinimumDistance(camera, boundingBox)\n : -1;\n const expectedDistance = Vector3.distance(camera.position, hitPt);\n const actualDistance = Math.max(minDistance, expectedDistance);\n const epsilon = (6 * actualDistance * delta) / viewport.height;\n\n const expectedPosition = Ray.at(pointRay, epsilon);\n const expectedViewVector = Ray.create({\n origin: expectedPosition,\n direction: Vector3.normalize(camera.viewVector),\n });\n const expectedIntersection = Ray.intersectPlane(\n expectedViewVector,\n hitPlane\n );\n\n if (\n expectedIntersection == null &&\n config.useMinimumPerspectiveZoomDistance\n ) {\n const minDistanceEpsilon = (6 * minDistance * delta) / viewport.height;\n const position = Ray.at(pointRay, minDistanceEpsilon);\n\n return {\n position,\n distance: minDistance,\n isPastHitPlane: true,\n keepCurrent: false,\n };\n } else if (expectedIntersection == null) {\n return {\n position: camera.position,\n distance: actualDistance,\n isPastHitPlane: true,\n keepCurrent: true,\n };\n }\n\n return {\n position: expectedPosition,\n distance: actualDistance,\n isPastHitPlane: false,\n keepCurrent: false,\n };\n }\n\n private computeZoomMinimumDistance(\n camera: PerspectiveCamera,\n boundingBox: BoundingBox.BoundingBox\n ): number {\n const xLength = Math.abs(boundingBox.min.x) + Math.abs(boundingBox.max.x);\n const yLength = Math.abs(boundingBox.min.y) + Math.abs(boundingBox.max.y);\n const zLength = Math.abs(boundingBox.min.z) + Math.abs(boundingBox.max.z);\n const maxLength = Math.max(xLength, yLength, zLength);\n\n const absDotX = Math.abs(\n Vector3.dot(Vector3.normalize(camera.viewVector), Vector3.right())\n );\n const absDotY = Math.abs(\n Vector3.dot(Vector3.normalize(camera.viewVector), Vector3.up())\n );\n const absDotZ = Math.abs(\n Vector3.dot(Vector3.normalize(camera.viewVector), Vector3.back())\n );\n\n const scaledLengthX = xLength * absDotX;\n const scaledLengthY = yLength * absDotY;\n const scaledLengthZ = zLength * absDotZ;\n\n const relevanceLengthX = maxLength / xLength;\n const relevanceLengthY = maxLength / yLength;\n const relevanceLengthZ = maxLength / zLength;\n\n return (\n ((scaledLengthX + scaledLengthY + scaledLengthZ) /\n (relevanceLengthX + relevanceLengthY + relevanceLengthZ)) *\n CAMERA_MIN_ZOOM_SCALAR\n );\n }\n}\n","import { BoundingBox, Point, Vector3 } from '@vertexvis/geometry';\nimport { StreamApi, toProtoDuration } from '@vertexvis/stream-api';\n\nimport { ConfigProvider } from '../config';\nimport { updateLookAtRelativeToBoundingBoxCenter } from '../rendering/vectors';\nimport { ImageScaleProvider, Scene } from '../scenes';\nimport { FrameCamera } from '../types';\nimport { KeyInteraction } from './keyInteraction';\nimport { TapEventDetails } from './tapEventDetails';\n\ntype SceneProvider = () => Promise<Scene>;\n\nexport class FlyToPositionKeyInteraction\n implements KeyInteraction<TapEventDetails>\n{\n public constructor(\n private stream: StreamApi,\n private configProvider: ConfigProvider,\n private imageScaleProvider: ImageScaleProvider,\n private sceneProvider: SceneProvider\n ) {}\n\n public predicate(e: TapEventDetails): boolean {\n return e.altKey && e.shiftKey;\n }\n\n public async fn(e: TapEventDetails): Promise<void> {\n const scale = this.imageScaleProvider();\n const hitResult = await this.stream.hitItems(\n {\n point: Point.scale(e.position, scale?.x || 1, scale?.y || 1),\n },\n true\n );\n\n if (\n hitResult.hitItems?.hits != null &&\n hitResult.hitItems.hits.length > 0 &&\n hitResult.hitItems.hits[0].hitPoint != null\n ) {\n const scene = await this.sceneProvider();\n const camera = (await this.sceneProvider()).camera();\n const hit = hitResult.hitItems.hits[0];\n\n if (\n hit.hitPoint != null &&\n hit.hitPoint.x != null &&\n hit.hitPoint.y != null &&\n hit.hitPoint.z != null\n ) {\n const hitPoint = Vector3.create(\n hit.hitPoint.x,\n hit.hitPoint.y,\n hit.hitPoint.z\n );\n const newLookAt = await this.getLookAtPoint(\n scene,\n hitPoint,\n camera.viewVector\n );\n\n await this.stream.flyTo({\n camera: FrameCamera.toProtobuf(\n camera\n .update({\n lookAt: newLookAt,\n rotationPoint: newLookAt,\n })\n .toFrameCamera()\n ),\n animation: {\n duration: toProtoDuration(\n this.configProvider().animation.durationMs\n ),\n },\n });\n } else {\n console.debug(\n `No hit position found for fly to position [position={x: ${e.position.x}, y: ${e.position.y}}, hit-id={${hit.itemId?.hex}}]`\n );\n }\n } else {\n console.debug(\n `No hit results found for fly to position [position={x: ${e.position.x}, y: ${e.position.y}}]`\n );\n }\n }\n\n protected getLookAtPoint(\n scene: Scene,\n hitPoint: Vector3.Vector3,\n viewVector: Vector3.Vector3\n ): Vector3.Vector3 {\n if (scene.isOrthographic()) {\n // Update the lookAt point to take the center of the model into account\n // This change helps ensure that the lookAt point is consistent between\n // the SDK and back-end system such that the calculated depth buffer is correct.\n return updateLookAtRelativeToBoundingBoxCenter(\n hitPoint,\n viewVector,\n BoundingBox.center(scene.boundingBox())\n );\n } else {\n // For perspective, just return the hit point\n return hitPoint;\n }\n }\n}\n","import { Point } from '@vertexvis/geometry';\n\nimport { getMouseClientPosition } from '../dom';\nimport { InteractionType } from './baseInteractionHandler';\nimport { InteractionApi, InteractionConfigProvider } from './interactionApi';\n\nexport abstract class MouseInteraction {\n protected currentPosition: Point.Point | undefined;\n\n protected abstract type: InteractionType;\n\n public setPosition(position?: Point.Point): void {\n this.currentPosition = position;\n }\n\n public getPosition(): Point.Point | undefined {\n return this.currentPosition;\n }\n\n public getType(): InteractionType {\n return this.type;\n }\n\n public beginDrag(\n event: MouseEvent,\n canvasPosition: Point.Point,\n api: InteractionApi,\n element: HTMLElement\n ): void {\n // noop\n }\n\n public drag(event: MouseEvent, api: InteractionApi): void {\n // noop\n }\n\n public endDrag(event: MouseEvent, api: InteractionApi): void {\n if (this.currentPosition != null) {\n api.endInteraction();\n this.currentPosition = undefined;\n }\n }\n\n public zoom(delta: number, api: InteractionApi): void {\n // noop\n }\n}\n\nexport class RotateInteraction extends MouseInteraction {\n public type: InteractionType = 'rotate';\n\n public beginDrag(\n event: MouseEvent,\n canvasPosition: Point.Point,\n api: InteractionApi\n ): void {\n if (this.currentPosition == null) {\n this.currentPosition = Point.create(event.screenX, event.screenY);\n api.beginInteraction();\n }\n }\n\n public drag(event: MouseEvent, api: InteractionApi): void {\n if (this.currentPosition != null) {\n const position = Point.create(event.screenX, event.screenY);\n const delta = Point.subtract(position, this.currentPosition);\n\n api.rotateCamera(delta);\n this.currentPosition = position;\n }\n }\n\n public endDrag(event: MouseEvent, api: InteractionApi): void {\n super.endDrag(event, api);\n }\n}\n\nexport class RotatePointInteraction extends MouseInteraction {\n public type: InteractionType = 'rotate-point';\n\n private startingPosition?: Point.Point;\n\n public beginDrag(\n event: MouseEvent,\n canvasPosition: Point.Point,\n api: InteractionApi\n ): void {\n if (this.currentPosition == null) {\n this.currentPosition = Point.create(event.screenX, event.screenY);\n this.startingPosition = canvasPosition;\n api.beginInteraction();\n }\n }\n\n public drag(event: MouseEvent, api: InteractionApi): void {\n if (this.currentPosition != null && this.startingPosition != null) {\n const position = Point.create(event.screenX, event.screenY);\n const delta = Point.subtract(position, this.currentPosition);\n\n api.rotateCameraAtPoint(delta, this.startingPosition);\n this.currentPosition = position;\n }\n }\n\n public endDrag(event: MouseEvent, api: InteractionApi): void {\n super.endDrag(event, api);\n }\n}\n\nexport class ZoomInteraction extends MouseInteraction {\n public type: InteractionType = 'zoom';\n\n private didTransformBegin = false;\n private interactionTimer: number | undefined;\n private startPt?: Point.Point;\n\n public constructor(\n private interactionConfigProvider: InteractionConfigProvider\n ) {\n super();\n }\n\n public beginDrag(\n event: MouseEvent,\n canvasPosition: Point.Point,\n api: InteractionApi,\n element: HTMLElement\n ): void {\n if (this.currentPosition == null) {\n this.currentPosition = Point.create(event.clientX, event.clientY);\n const rect = element.getBoundingClientRect();\n const point = getMouseClientPosition(event, rect);\n this.startPt = point;\n api.beginInteraction();\n }\n }\n\n public drag(event: MouseEvent, api: InteractionApi): void {\n if (this.currentPosition != null) {\n const position = Point.create(event.clientX, event.clientY);\n const delta = Point.subtract(position, this.currentPosition);\n\n if (this.startPt != null) {\n api.zoomCameraToPoint(this.startPt, delta.y);\n this.currentPosition = position;\n }\n }\n }\n\n public endDrag(event: MouseEvent, api: InteractionApi): void {\n super.endDrag(event, api);\n this.stopInteractionTimer();\n this.didTransformBegin = false;\n this.startPt = undefined;\n }\n\n public zoom(delta: number, api: InteractionApi): void {\n this.operateWithTimer(api, () =>\n api.zoomCamera(this.getDirectionalDelta(delta))\n );\n }\n\n public zoomToPoint(\n pt: Point.Point,\n delta: number,\n api: InteractionApi\n ): void {\n this.operateWithTimer(api, () =>\n api.zoomCameraToPoint(pt, this.getDirectionalDelta(delta))\n );\n }\n\n private beginInteraction(api: InteractionApi): void {\n this.didTransformBegin = true;\n api.beginInteraction();\n }\n\n private endInteraction(api: InteractionApi): void {\n this.didTransformBegin = false;\n api.endInteraction();\n }\n\n private resetInteractionTimer(api: InteractionApi): void {\n this.stopInteractionTimer();\n this.startInteractionTimer(api);\n }\n\n private getDirectionalDelta(delta: number): number {\n return this.interactionConfigProvider().reverseMouseWheelDirection\n ? -delta\n : delta;\n }\n\n private getInteractionDelay(): number {\n return this.interactionConfigProvider().mouseWheelInteractionEndDebounce;\n }\n\n private startInteractionTimer(api: InteractionApi): void {\n this.interactionTimer = window.setTimeout(() => {\n this.interactionTimer = undefined;\n this.endInteraction(api);\n }, this.getInteractionDelay());\n }\n\n private stopInteractionTimer(): void {\n if (this.interactionTimer != null) {\n window.clearTimeout(this.interactionTimer);\n this.interactionTimer = undefined;\n }\n }\n\n private operateWithTimer(\n api: InteractionApi,\n f: () => void | Promise<void>\n ): void {\n if (!this.didTransformBegin) {\n this.beginInteraction(api);\n }\n\n this.resetInteractionTimer(api);\n f();\n }\n}\n\nexport class PanInteraction extends MouseInteraction {\n public type: InteractionType = 'pan';\n\n private canvasRect?: DOMRect;\n\n public beginDrag(\n event: MouseEvent,\n canvasPosition: Point.Point,\n api: InteractionApi,\n element: HTMLElement\n ): void {\n if (this.currentPosition == null) {\n this.currentPosition = Point.create(event.screenX, event.screenY);\n this.canvasRect = element.getBoundingClientRect();\n api.beginInteraction();\n }\n }\n\n public drag(event: MouseEvent, api: InteractionApi): void {\n if (this.currentPosition != null && this.canvasRect != null) {\n const position = getMouseClientPosition(event, this.canvasRect);\n api.panCameraToScreenPoint(position);\n this.currentPosition = position;\n }\n }\n\n public endDrag(event: MouseEvent, api: InteractionApi): void {\n super.endDrag(event, api);\n }\n}\n\nexport class TwistInteraction extends MouseInteraction {\n public type: InteractionType = 'twist';\n\n private canvasRect?: DOMRect;\n\n public beginDrag(\n event: MouseEvent,\n canvasPosition: Point.Point,\n api: InteractionApi,\n element: HTMLElement\n ): void {\n this.currentPosition = Point.create(event.offsetX, event.offsetY);\n this.canvasRect = element.getBoundingClientRect();\n api.beginInteraction();\n }\n\n public drag(event: MouseEvent, api: InteractionApi): void {\n const position = getMouseClientPosition(event, this.canvasRect);\n this.currentPosition = position;\n\n api.twistCamera(position);\n }\n\n public endDrag(event: MouseEvent, api: InteractionApi): void {\n super.endDrag(event, api);\n }\n}\n\nexport class PivotInteraction extends MouseInteraction {\n public type: InteractionType = 'pivot';\n\n public beginDrag(\n event: MouseEvent,\n canvasPosition: Point.Point,\n api: InteractionApi\n ): void {\n if (this.currentPosition == null) {\n this.currentPosition = Point.create(event.screenX, event.screenY);\n api.beginInteraction();\n }\n }\n\n public drag(event: MouseEvent, api: InteractionApi): void {\n if (this.currentPosition != null) {\n const position = Point.create(event.screenX, event.screenY);\n const delta = Point.subtract(position, this.currentPosition);\n\n api.pivotCamera(-0.25 * delta.y, 0.25 * delta.x);\n this.currentPosition = position;\n }\n }\n\n public endDrag(event: MouseEvent, api: InteractionApi): void {\n super.endDrag(event, api);\n }\n}\n","import { ConfigProvider } from '../config';\nimport { BaseInteractionHandler } from './baseInteractionHandler';\nimport {\n PanInteraction,\n PivotInteraction,\n RotateInteraction,\n RotatePointInteraction,\n TwistInteraction,\n ZoomInteraction,\n} from './mouseInteractions';\n\nexport class MouseInteractionHandler extends BaseInteractionHandler {\n public constructor(\n getConfig: ConfigProvider,\n rotateInteraction = new RotateInteraction(),\n rotatePointInteraction = new RotatePointInteraction(),\n zoomInteraction = new ZoomInteraction(() => getConfig().interactions),\n panInteraction = new PanInteraction(),\n twistInteraction = new TwistInteraction(),\n pivotInteraction = new PivotInteraction()\n ) {\n super(\n 'mousedown',\n 'mouseup',\n 'mousemove',\n rotateInteraction,\n rotatePointInteraction,\n zoomInteraction,\n panInteraction,\n twistInteraction,\n pivotInteraction,\n getConfig\n );\n }\n}\n","export function requestAnimationFrame(callback: VoidFunction): void {\n window.requestAnimationFrame(callback);\n}\n","import { Angle, Matrix2, Point } from '@vertexvis/geometry';\n\nimport { requestAnimationFrame } from '../window';\nimport { InteractionApi } from './interactionApi';\nimport { InteractionHandler } from './interactionHandler';\n\nexport abstract class MultiTouchInteractionHandler\n implements InteractionHandler\n{\n protected element?: HTMLElement;\n protected interactionApi?: InteractionApi;\n\n private previousFirstPoints: Point.Point[] = [];\n private previousSecondPoints: Point.Point[] = [];\n\n public initialize(element: HTMLElement, api: InteractionApi): void {\n this.element = element;\n this.interactionApi = api;\n }\n\n public dispose(): void {\n this.element = undefined;\n }\n\n protected beginTwoPointTouch(point1: Point.Point, point2: Point.Point): void {\n this.previousFirstPoints = [...this.previousFirstPoints, point1];\n this.previousSecondPoints = [...this.previousSecondPoints, point2];\n }\n\n protected handleTwoPointTouchMove(\n point1: Point.Point,\n point2: Point.Point\n ): void {\n this.previousFirstPoints = [...this.previousFirstPoints, point1];\n this.previousSecondPoints = [...this.previousSecondPoints, point2];\n\n // Process updates to touch points on animation frame callbacks to batch\n // the processing. Because each event can potentially only represent a single\n // touch point moving, two opposing angles can be computed sequentially. This\n // results in a wobbling effect if those angles are both sent, and this batched\n // processing helps to reduce that effect.\n requestAnimationFrame(() => {\n if (\n this.previousFirstPoints.length > 1 &&\n this.previousSecondPoints.length > 1 &&\n this.previousFirstPoints.length === this.previousSecondPoints.length\n ) {\n const previousFirstPoints = this.previousFirstPoints;\n const previousSecondPoints = this.previousSecondPoints;\n\n this.previousFirstPoints = this.previousFirstPoints.slice(-1);\n this.previousSecondPoints = this.previousSecondPoints.slice(-1);\n\n const changes = previousFirstPoints.reduce<{\n deltas: Point.Point[];\n zooms: number[];\n angles: number[];\n }>(\n (result, previousFirstPoint, i) => {\n if (i < previousFirstPoints.length - 1) {\n const firstPoint = previousFirstPoints[i + 1];\n const previousSecondPoint = previousSecondPoints[i];\n const secondPoint = previousSecondPoints[i + 1];\n\n return {\n deltas: [\n ...result.deltas,\n this.computeDelta(\n previousFirstPoint,\n previousSecondPoint,\n firstPoint,\n secondPoint\n ),\n ],\n zooms: [\n ...result.zooms,\n this.computeZoom(\n previousFirstPoint,\n previousSecondPoint,\n firstPoint,\n secondPoint\n ),\n ],\n angles: [\n ...result.angles,\n this.computeAngle(\n previousFirstPoint,\n previousSecondPoint,\n firstPoint,\n secondPoint\n ),\n ],\n };\n }\n return result;\n },\n {\n deltas: [],\n zooms: [],\n angles: [],\n }\n );\n\n const delta = changes.deltas.reduce(\n (r, d) => Point.add(r, d),\n Point.create()\n );\n const zoom = changes.zooms.reduce((z, d) => z + d, 0);\n const angle = changes.angles.reduce((a, d) => a + d, 0);\n\n const center = Point.create(\n (previousFirstPoints[previousFirstPoints.length - 1].x +\n previousSecondPoints[previousSecondPoints.length - 1].x) /\n 2,\n (previousFirstPoints[previousFirstPoints.length - 1].y +\n previousSecondPoints[previousSecondPoints.length - 1].y) /\n 2\n );\n\n this.interactionApi?.beginInteraction();\n this.interactionApi?.zoomCameraToPoint(center, zoom);\n this.interactionApi?.panCameraByDelta(delta);\n this.interactionApi?.twistCamera(angle);\n }\n });\n }\n\n protected endTwoPointTouch(): void {\n this.previousFirstPoints = [];\n this.previousSecondPoints = [];\n }\n\n private computeDelta(\n previousPoint1: Point.Point,\n previousPoint2: Point.Point,\n point1: Point.Point,\n point2: Point.Point\n ): Point.Point {\n return Point.add(\n Point.subtract(point1, previousPoint1),\n Point.subtract(point2, previousPoint2)\n );\n }\n\n private computeZoom(\n previousPoint1: Point.Point,\n previousPoint2: Point.Point,\n point1: Point.Point,\n point2: Point.Point\n ): number {\n const distance =\n Point.distance(point1, point2) -\n Point.distance(previousPoint1, previousPoint2);\n return distance * 0.5;\n }\n\n private computeAngle(\n previousPoint1: Point.Point,\n previousPoint2: Point.Point,\n point1: Point.Point,\n point2: Point.Point\n ): number {\n const previousToCurrent = Matrix2.create(\n Point.subtract(previousPoint1, previousPoint2),\n Point.subtract(point1, point2)\n );\n return Angle.toDegrees(\n Math.atan2(\n Matrix2.determinant(previousToCurrent),\n Matrix2.dot(previousToCurrent)\n )\n );\n }\n}\n","import { Point } from '@vertexvis/geometry';\n\nimport { InteractionApi } from './interactionApi';\nimport { MultiTouchInteractionHandler } from './multiTouchInteractionHandler';\n\nexport class MultiPointerInteractionHandler extends MultiTouchInteractionHandler {\n private touchPoints: Record<string, Point.Point> = {};\n\n public constructor() {\n super();\n this.handlePointerDown = this.handlePointerDown.bind(this);\n this.handlePointerMove = this.handlePointerMove.bind(this);\n this.handlePointerUp = this.handlePointerUp.bind(this);\n }\n\n public dispose(): void {\n this.element?.removeEventListener('pointerdown', this.handlePointerDown);\n super.dispose();\n }\n\n public initialize(element: HTMLElement, api: InteractionApi): void {\n super.initialize(element, api);\n\n element.addEventListener('pointerdown', this.handlePointerDown);\n }\n\n private handlePointerDown(event: PointerEvent): void {\n const point = Point.create(event.screenX, event.screenY);\n this.touchPoints = {\n ...this.touchPoints,\n [event.pointerId]: point,\n };\n const keys = Object.keys(this.touchPoints);\n if (keys.length === 1) {\n window.addEventListener('pointermove', this.handlePointerMove);\n window.addEventListener('pointerup', this.handlePointerUp);\n } else if (keys.length === 2) {\n this.beginTwoPointTouch(this.touchPoints[0], this.touchPoints[1]);\n }\n }\n\n private handlePointerMove(event: PointerEvent): void {\n if (this.touchPoints[event.pointerId] != null) {\n this.touchPoints[event.pointerId] = Point.create(\n event.screenX,\n event.screenY\n );\n }\n\n const keys = Object.keys(this.touchPoints);\n if (keys.length === 2) {\n const point1 = this.touchPoints[keys[0]];\n const point2 = this.touchPoints[keys[1]];\n this.handleTwoPointTouchMove(point1, point2);\n }\n }\n\n private handlePointerUp(event: PointerEvent): void {\n delete this.touchPoints[event.pointerId];\n\n const keys = Object.keys(this.touchPoints);\n if (keys.length === 1) {\n this.interactionApi?.endInteraction();\n }\n if (keys.length === 0) {\n window.removeEventListener('pointermove', this.handlePointerMove);\n window.removeEventListener('pointerup', this.handlePointerUp);\n }\n this.endTwoPointTouch();\n }\n}\n","import { Point } from '@vertexvis/geometry';\nimport { Disposable } from '@vertexvis/utils';\n\nimport { ConfigProvider } from '../config';\nimport { InteractionApi } from './interactionApi';\nimport {\n PanInteraction,\n PivotInteraction,\n RotateInteraction,\n RotatePointInteraction,\n TwistInteraction,\n ZoomInteraction,\n} from './mouseInteractions';\nimport { MultiElementInteractionHandler } from './multiElementInteractionHandler';\n\nexport class PointerInteractionHandler extends MultiElementInteractionHandler {\n private touchPoints: Set<number>;\n\n public constructor(\n getConfig: ConfigProvider,\n rotateInteraction = new RotateInteraction(),\n rotatePointInteraction = new RotatePointInteraction(),\n zoomInteraction = new ZoomInteraction(() => getConfig().interactions),\n panInteraction = new PanInteraction(),\n twistInteraction = new TwistInteraction(),\n pivotInteraction = new PivotInteraction()\n ) {\n super(\n 'pointerdown',\n 'pointerup',\n 'pointermove',\n rotateInteraction,\n rotatePointInteraction,\n zoomInteraction,\n panInteraction,\n twistInteraction,\n pivotInteraction,\n getConfig\n );\n this.touchPoints = new Set();\n this.handlePointerDown = this.handlePointerDown.bind(this);\n this.handlePointerUp = this.handlePointerUp.bind(this);\n }\n\n public initialize(element: HTMLElement, api: InteractionApi): void {\n super.initialize(element, api);\n\n element.addEventListener('pointerdown', this.handlePointerDown);\n }\n\n public addEventListenersToElement(element: HTMLElement): Disposable {\n element.addEventListener(this.downEvent, this.handleDownEvent);\n element.addEventListener('wheel', this.handleMouseWheel, {\n passive: false,\n });\n\n return {\n dispose: () => {\n element.removeEventListener(this.downEvent, this.handleDownEvent);\n element.removeEventListener('wheel', this.handleMouseWheel);\n },\n };\n }\n\n private handlePointerDown(event: PointerEvent): void {\n this.downPosition = Point.create(event.screenX, event.screenY);\n this.touchPoints.add(event.pointerId);\n\n if (this.touchPoints.size === 1) {\n window.addEventListener('pointerup', this.handlePointerUp);\n }\n\n if (this.touchPoints.size === 2) {\n this.disableIndividualInteractions = true;\n }\n }\n\n private handlePointerUp(event: PointerEvent): void {\n this.touchPoints.delete(event.pointerId);\n\n if (this.touchPoints.size < 2) {\n this.disableIndividualInteractions = false;\n }\n\n if (this.touchPoints.size === 0) {\n window.removeEventListener('pointerup', this.handlePointerUp);\n }\n }\n}\n","import { Point } from '@vertexvis/geometry';\n\nimport { ConfigProvider } from '../config';\nimport { InteractionApi } from './interactionApi';\nimport { BaseEvent } from './interactionEvent';\nimport { InteractionHandler } from './interactionHandler';\nimport { TapEventKeys } from './tapEventDetails';\n\ntype TapEmitter = (\n position: Point.Point,\n keyDetails?: Partial<TapEventKeys>,\n buttons?: number,\n downPosition?: Point.Point\n) => Promise<void> | void;\n\nexport class TapInteractionHandler implements InteractionHandler {\n private element?: HTMLElement;\n private interactionApi?: InteractionApi;\n\n private pointerDownPosition?: Point.Point;\n\n // Double tap positions\n private firstPointerDownPosition?: Point.Point;\n private secondPointerDownPosition?: Point.Point;\n\n private doubleTapTimer?: number;\n private longPressTimer?: number;\n private interactionTimer?: number;\n\n private buttons?: number;\n\n public constructor(\n protected downEvent: 'mousedown' | 'pointerdown',\n protected upEvent: 'mouseup' | 'pointerup',\n protected moveEvent: 'mousemove' | 'pointermove',\n private getConfig: ConfigProvider\n ) {\n this.handleDown = this.handleDown.bind(this);\n this.handleUp = this.handleUp.bind(this);\n this.handleMove = this.handleMove.bind(this);\n this.handleTouchStart = this.handleTouchStart.bind(this);\n this.handleTouchMove = this.handleTouchMove.bind(this);\n this.handleTouchEnd = this.handleTouchEnd.bind(this);\n this.handlePointerMove = this.handlePointerMove.bind(this);\n this.handlePointerEnd = this.handlePointerEnd.bind(this);\n this.clearPositions = this.clearPositions.bind(this);\n this.restartDoubleTapTimer = this.restartDoubleTapTimer.bind(this);\n this.clearDoubleTapTimer = this.clearDoubleTapTimer.bind(this);\n this.restartLongPressTimer = this.restartLongPressTimer.bind(this);\n this.clearLongPressTimer = this.clearLongPressTimer.bind(this);\n this.setPointerPositions = this.setPointerPositions.bind(this);\n this.emit = this.emit.bind(this);\n }\n\n public dispose(): void {\n this.element?.removeEventListener(this.downEvent, this.handleDown);\n this.element?.removeEventListener('touchstart', this.handleTouchStart);\n this.element = undefined;\n\n this.clearDoubleTapTimer();\n this.clearLongPressTimer();\n }\n\n public initialize(element: HTMLElement, api: InteractionApi): void {\n this.element = element;\n this.interactionApi = api;\n element.addEventListener(this.downEvent, this.handleDown);\n element.addEventListener('touchstart', this.handleTouchStart, {\n passive: true,\n });\n }\n\n private handleTouchStart(event: TouchEvent): void {\n if (event.touches.length === 1) {\n this.setPointerPositions(\n Point.create(event.touches[0].clientX, event.touches[0].clientY)\n );\n\n this.restartLongPressTimer();\n\n window.addEventListener('touchend', this.handleTouchEnd);\n window.addEventListener('touchmove', this.handleTouchMove);\n }\n }\n\n private handleTouchMove(event: TouchEvent): void {\n if (event.touches.length > 0) {\n this.handlePointerMove(\n Point.create(event.touches[0].clientX, event.touches[0].clientY),\n true\n );\n }\n }\n\n private handleTouchEnd(event: TouchEvent): void {\n if (this.pointerDownPosition != null) {\n window.removeEventListener('touchend', this.handleTouchEnd);\n window.removeEventListener('touchmove', this.handleTouchMove);\n }\n\n this.handlePointerEnd(this.pointerDownPosition);\n }\n\n private handleDown(event: BaseEvent): void {\n this.setPointerPositions(Point.create(event.clientX, event.clientY));\n this.buttons = event.buttons;\n\n const eventKeys = {\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n };\n this.restartLongPressTimer(eventKeys);\n\n window.addEventListener(this.upEvent, this.handleUp);\n window.addEventListener(this.moveEvent, this.handleMove);\n }\n\n private handleMove(event: BaseEvent): void {\n this.handlePointerMove(\n Point.create(event.clientX, event.clientY),\n this.isTouch(event)\n );\n }\n\n private handleUp(event: BaseEvent): void {\n if (this.pointerDownPosition != null) {\n window.removeEventListener(this.upEvent, this.handleUp);\n window.removeEventListener(this.moveEvent, this.handleMove);\n }\n\n this.handlePointerEnd(\n Point.create(event.clientX, event.clientY),\n {\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n },\n this.buttons,\n this.isTouch(event)\n );\n this.buttons = undefined;\n }\n\n private handlePointerMove(position: Point.Point, isTouch?: boolean): void {\n // Ignore pointer end events for this associated touch start\n // since the distance from the start is large enough\n const threshold = this.interactionApi?.pixelThreshold(isTouch) || 2;\n if (\n this.pointerDownPosition != null &&\n Point.distance(position, this.pointerDownPosition) >= threshold &&\n this.interactionTimer == null\n ) {\n this.clearPositions();\n }\n }\n\n private handlePointerEnd(\n position?: Point.Point,\n keyDetails: Partial<TapEventKeys> = {},\n buttons = 0,\n isTouch = false\n ): void {\n if (position != null) {\n if (this.longPressTimer != null) {\n this.emit(this.interactionApi?.tap)(position, keyDetails, buttons);\n }\n\n if (\n this.doubleTapTimer != null &&\n this.secondPointerDownPosition != null\n ) {\n this.emit(this.interactionApi?.doubleTap)(\n position,\n keyDetails,\n buttons,\n this.secondPointerDownPosition\n );\n this.clearDoubleTapTimer();\n }\n }\n\n this.pointerDownPosition = undefined;\n\n this.clearLongPressTimer();\n }\n\n private emit(emitter?: TapEmitter): TapEmitter {\n return (\n pointerUpPosition: Point.Point,\n keyDetails: Partial<TapEventKeys> = {},\n buttons = 0,\n pointerDownPosition?: Point.Point,\n isTouch = false\n ): void => {\n const downPosition = pointerDownPosition || this.pointerDownPosition;\n const threshold = this.interactionApi?.pixelThreshold(isTouch) || 1;\n\n let emittedPosition: Point.Point | undefined;\n if (this.interactionTimer != null) {\n emittedPosition = this.getCanvasPosition(\n downPosition || pointerUpPosition\n );\n } else if (\n downPosition != null &&\n Point.distance(downPosition, pointerUpPosition) <= threshold\n ) {\n emittedPosition = this.getCanvasPosition(pointerUpPosition);\n }\n if (emittedPosition != null && emitter != null) {\n emitter(emittedPosition, keyDetails, buttons);\n }\n };\n }\n\n private getCanvasPosition(point: Point.Point): Point.Point | undefined {\n const canvasBounds = this.element?.getBoundingClientRect();\n const canvasOffset =\n canvasBounds != null\n ? Point.create(canvasBounds.left, canvasBounds.top)\n : undefined;\n\n return canvasOffset != null\n ? Point.subtract(Point.create(point.x, point.y), canvasOffset)\n : undefined;\n }\n\n private clearPositions(): void {\n this.pointerDownPosition = undefined;\n this.firstPointerDownPosition = undefined;\n this.secondPointerDownPosition = undefined;\n\n this.clearDoubleTapTimer();\n this.clearLongPressTimer();\n this.clearInteractionTimer();\n }\n\n private clearDoubleTapTimer(): void {\n if (this.doubleTapTimer != null) {\n window.clearTimeout(this.doubleTapTimer);\n }\n this.doubleTapTimer = undefined;\n this.firstPointerDownPosition = undefined;\n this.secondPointerDownPosition = undefined;\n }\n\n private restartDoubleTapTimer(): void {\n this.clearDoubleTapTimer();\n this.doubleTapTimer = window.setTimeout(\n () => this.clearDoubleTapTimer(),\n this.getConfig().events.doubleTapThreshold\n );\n }\n\n private clearLongPressTimer(): void {\n if (this.longPressTimer != null) {\n window.clearTimeout(this.longPressTimer);\n }\n this.longPressTimer = undefined;\n }\n\n private restartLongPressTimer(eventKeys: Partial<TapEventKeys> = {}): void {\n this.clearLongPressTimer();\n this.longPressTimer = window.setTimeout(() => {\n if (this.pointerDownPosition) {\n this.emit(this.interactionApi?.longPress)(\n this.pointerDownPosition,\n eventKeys,\n this.buttons\n );\n }\n this.clearLongPressTimer();\n }, this.getConfig().events.longPressThreshold);\n }\n\n private restartInteractionTimer(): void {\n this.clearInteractionTimer();\n this.interactionTimer = window.setTimeout(() => {\n this.interactionTimer = undefined;\n }, this.getConfig().interactions.interactionDelay);\n }\n\n private clearInteractionTimer(): void {\n if (this.interactionTimer != null) {\n window.clearTimeout(this.interactionTimer);\n this.interactionTimer = undefined;\n }\n }\n\n private setPointerPositions(point: Point.Point): void {\n this.pointerDownPosition = point;\n this.restartInteractionTimer();\n if (this.firstPointerDownPosition == null) {\n this.restartDoubleTapTimer();\n this.firstPointerDownPosition = point;\n } else {\n this.secondPointerDownPosition = point;\n }\n }\n\n private isTouch(event: BaseEvent): boolean {\n return window.PointerEvent != null && event instanceof PointerEvent\n ? event.pointerType === 'touch'\n : false;\n }\n}\n","import { Point } from '@vertexvis/geometry';\n\nimport { InteractionApi } from './interactionApi';\nimport { MultiTouchInteractionHandler } from './multiTouchInteractionHandler';\n\nexport class TouchInteractionHandler extends MultiTouchInteractionHandler {\n private currentPosition1?: Point.Point;\n private isInteracting?: boolean;\n\n public constructor() {\n super();\n this.handleTouchStart = this.handleTouchStart.bind(this);\n this.handleTouchMove = this.handleTouchMove.bind(this);\n this.handleTouchEnd = this.handleTouchEnd.bind(this);\n }\n\n public dispose(): void {\n this.element?.removeEventListener('touchstart', this.handleTouchStart);\n super.dispose();\n }\n\n public initialize(element: HTMLElement, api: InteractionApi): void {\n super.initialize(element, api);\n\n element.addEventListener('touchstart', this.handleTouchStart);\n }\n\n private handleTouchStart(event: TouchEvent): void {\n if (event.touches.length >= 1) {\n event.preventDefault();\n\n const touch1 = event.touches[0];\n\n this.currentPosition1 = Point.create(touch1.screenX, touch1.screenY);\n\n if (event.touches[1] != null) {\n this.beginTwoPointTouch(\n this.currentPosition1,\n Point.create(event.touches[1].screenX, event.touches[1].screenY)\n );\n }\n\n window.addEventListener('touchmove', this.handleTouchMove, {\n passive: false,\n });\n window.addEventListener('touchend', this.handleTouchEnd);\n }\n }\n\n private handleTouchMove(event: TouchEvent): void {\n event.preventDefault();\n\n if (event.touches.length === 1) {\n this.handleOnePointTouchMove(event.touches[0]);\n } else if (event.touches.length === 2) {\n const point1 = Point.create(\n event.touches[0].clientX,\n event.touches[0].clientY\n );\n const point2 = Point.create(\n event.touches[1].clientX,\n event.touches[1].clientY\n );\n\n this.handleTwoPointTouchMove(point1, point2);\n }\n }\n\n private handleTouchEnd(event: TouchEvent): void {\n event.preventDefault();\n\n this.interactionApi?.endInteraction();\n\n this.isInteracting = false;\n\n window.removeEventListener('touchmove', this.handleTouchMove);\n window.removeEventListener('touchend', this.handleTouchEnd);\n\n this.endTwoPointTouch();\n }\n\n private handleOnePointTouchMove(touch: Touch): void {\n const position = Point.create(touch.screenX, touch.screenY);\n\n if (this.currentPosition1 != null) {\n const delta = Point.subtract(position, this.currentPosition1);\n const threshold = this.interactionApi?.pixelThreshold(true) || 2;\n if (\n Point.distance(position, this.currentPosition1) >= threshold ||\n this.isInteracting\n ) {\n this.interactionApi?.beginInteraction();\n this.interactionApi?.rotateCamera(delta);\n this.isInteracting = true;\n }\n }\n\n this.currentPosition1 = position;\n }\n}\n","import { isPromise } from './types';\n\nexport interface Timing {\n startTime: number;\n duration: number;\n}\n\n/**\n * A meter for measuring timings. Measurements are stored using the browser's\n * performance APIs, which provide high-resolution timestamps, as well as\n * provides visibility in the browser's developer tooling.\n */\nexport class TimingMeter {\n private measures = new Set<string>();\n private nextId = 0;\n\n public constructor(\n public readonly name: string,\n private readonly perf: Performance = window.performance\n ) {}\n\n /**\n * Clears any measurements from the buffer.\n */\n public clearMeasurements(): void {\n this.perf.clearMeasures(this.name);\n }\n\n /**\n * Measures the execution time of a function.\n *\n * @param target A function to execute and measure.\n */\n public measure<T>(target: () => T): T;\n\n /**\n * Measures the time for a promise to resolve, either successfully or not.\n *\n * @param target The promise to measure.\n */\n public measure<T>(target: Promise<T>): Promise<T>;\n public measure<T>(target: (() => T) | Promise<T>): T | Promise<T> {\n if (isPromise(target)) {\n const mark = this.begin();\n return target.finally(() => this.end(mark));\n } else if (typeof target === 'function') {\n const mark = this.begin();\n const result = target();\n this.end(mark);\n return result;\n } else {\n throw new Error('Input must be a function or Promise');\n }\n }\n\n /**\n * Returns a list of measurements that have been recorded, and clears the\n * internal measurement buffer.\n */\n public takeMeasurements(): Timing[] {\n const timings = this.perf.getEntriesByName(this.name);\n this.clearMeasurements();\n return timings;\n }\n\n /**\n * Returns the last measurement to have been recorded, and clears the internal\n * measurement buffer.\n */\n public takeLastMeasurement(): Timing | undefined {\n const measurements = this.takeMeasurements();\n return measurements[measurements.length - 1];\n }\n\n private begin(): string {\n const mark = `${this.name}-${this.nextId++}`;\n this.measures.add(mark);\n this.perf.mark(mark);\n return mark;\n }\n\n private end(mark: string): void {\n this.perf.measure(this.name, mark);\n this.perf.clearMarks(mark);\n this.measures.delete(mark);\n }\n}\n\nexport const paintTime = new TimingMeter('paint_time');\n","import { Disposable } from '@vertexvis/utils';\n\nimport { ImageLoadError } from '../errors';\n\nexport interface HtmlImage extends Disposable {\n image: HTMLImageElement | ImageBitmap;\n}\n\nfunction loadImageBytesAsImageElement(\n imageData: Uint8Array\n): Promise<HtmlImage> {\n return new Promise((resolve, reject) => {\n const blob = new Blob([imageData]);\n const blobUrl = URL.createObjectURL(blob);\n\n const image = new Image();\n image.addEventListener('load', () => {\n resolve({ image, dispose: () => undefined });\n URL.revokeObjectURL(blobUrl);\n });\n image.addEventListener('error', () => {\n reject(new ImageLoadError('Failed to load image data'));\n URL.revokeObjectURL(blobUrl);\n });\n\n image.src = blobUrl;\n });\n}\n\nasync function loadImageBytesAsImageBitmap(\n imageData: Uint8Array\n): Promise<HtmlImage> {\n const blob = new Blob([imageData]);\n const bitmap = await window.createImageBitmap(blob);\n return { image: bitmap, dispose: () => bitmap.close() };\n}\n\nexport function loadImageBytes(imageBytes: Uint8Array): Promise<HtmlImage> {\n if (window.createImageBitmap != null) {\n return loadImageBytesAsImageBitmap(imageBytes);\n } else {\n return loadImageBytesAsImageElement(imageBytes);\n }\n}\n","import { Dimensions } from '@vertexvis/geometry';\n\nimport { Timing, TimingMeter } from '../meters';\nimport { StencilBufferManager, Viewport } from '../types';\nimport { Frame } from '../types/frame';\nimport { HtmlImage, loadImageBytes } from './imageLoaders';\nimport { FrameRenderer } from './renderer';\n\nconst REPORTING_INTERVAL_MS = 1000;\n\nexport interface DrawFrame {\n canvas: CanvasRenderingContext2D;\n canvasDimensions: Dimensions.Dimensions;\n frame: Frame;\n viewport: Viewport;\n predicate?: () => boolean;\n beforeDraw?: VoidFunction;\n}\n\nexport type CanvasRenderer = FrameRenderer<DrawFrame, Frame | undefined>;\n\nexport type ReportTimingsCallback = (timing: Timing[]) => void;\n\nfunction drawImage(image: HtmlImage, data: DrawFrame): void {\n const rect = data.viewport.calculateDrawRect(data.frame.image);\n\n data.canvas.clearRect(\n 0,\n 0,\n data.canvasDimensions.width,\n data.canvasDimensions.height\n );\n data.canvas.drawImage(image.image, rect.x, rect.y, rect.width, rect.height);\n}\n\nfunction reportTimings(\n meter: TimingMeter,\n callback: ReportTimingsCallback\n): void {\n const timings = meter.takeMeasurements();\n\n if (timings.length > 0) {\n callback(timings);\n }\n}\n\nexport function measureCanvasRenderer(\n meter: TimingMeter,\n renderer: CanvasRenderer,\n logFrameRate: boolean,\n callback: ReportTimingsCallback,\n intervalMs: number = REPORTING_INTERVAL_MS\n): CanvasRenderer {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let timer: any;\n let renderCount = 0;\n let fpsFrameCount: number | undefined;\n let fpsHistory: number[] = [];\n\n function start(): void {\n renderCount++;\n if (timer == null) {\n timer = setInterval(() => {\n reportTimings(meter, callback);\n if (renderCount === 0) {\n clearTimer();\n }\n }, intervalMs);\n }\n }\n\n function end(): void {\n renderCount--;\n }\n\n function clearTimer(): void {\n if (timer != null) {\n clearInterval(timer);\n timer = undefined;\n }\n }\n\n /* istanbul ignore next */\n if (logFrameRate) {\n setInterval(() => {\n if (fpsFrameCount != null) {\n if (fpsHistory.length === 5) {\n fpsHistory = [...fpsHistory.slice(1), fpsFrameCount];\n } else {\n fpsHistory.push(fpsFrameCount);\n }\n\n const avgFps =\n fpsHistory.reduce((res, num) => res + num) / fpsHistory.length;\n console.debug(`Paint rate: ${fpsFrameCount}fps`);\n console.debug(`Paint rate (avg): ${avgFps}`);\n fpsFrameCount = undefined;\n }\n }, 1000);\n }\n\n return (data) => {\n start();\n return meter\n .measure(async () => {\n const frame = await renderer(data);\n fpsFrameCount = fpsFrameCount == null ? 1 : fpsFrameCount + 1;\n return frame;\n })\n .finally(() => end());\n };\n}\n\nexport function createCanvasRenderer(): CanvasRenderer {\n let accumulatedCorrelationIds: string[] = [];\n\n function addCorrelationIds(frame: Frame | undefined): Frame | undefined {\n if (frame != null) {\n const frameWithCorrelationIds = frame.copy({\n correlationIds: [\n ...frame.correlationIds,\n ...accumulatedCorrelationIds.filter(\n (id) => !frame.correlationIds.includes(id)\n ),\n ],\n });\n accumulatedCorrelationIds = [];\n\n return frameWithCorrelationIds;\n }\n return frame;\n }\n\n function loadFrame(): (data: DrawFrame) => Promise<HtmlImage | undefined> {\n let lastLoadedFrameNumber = -1;\n\n return async (data: DrawFrame): Promise<HtmlImage | undefined> => {\n if (data.frame.sequenceNumber > lastLoadedFrameNumber) {\n const image = await loadImageBytes(data.frame.image.imageBytes);\n\n lastLoadedFrameNumber = data.frame.sequenceNumber;\n\n return image;\n }\n };\n }\n\n function drawFrame(): (\n data: DrawFrame,\n image?: HtmlImage\n ) => Promise<Frame | undefined> {\n let lastDrawnFrameNumber = -1;\n\n return async (\n data: DrawFrame,\n image?: HtmlImage\n ): Promise<Frame | undefined> => {\n if (image != null && data.frame.sequenceNumber > lastDrawnFrameNumber) {\n lastDrawnFrameNumber = data.frame.sequenceNumber;\n\n data.beforeDraw?.();\n drawImage(image, data);\n\n image.dispose();\n return data.frame;\n }\n image?.dispose();\n };\n }\n\n const load = loadFrame();\n const draw = drawFrame();\n\n return async (data) => {\n const predicatePassing = data.predicate?.() ?? true;\n\n accumulatedCorrelationIds = [\n ...accumulatedCorrelationIds,\n ...data.frame.correlationIds,\n ];\n\n if (predicatePassing) {\n return load(data).then((image) =>\n draw(data, image).then(addCorrelationIds)\n );\n }\n };\n}\n\nexport function debugStencilBuffer(\n stencilManager: StencilBufferManager,\n drawStencil: () => boolean,\n renderer: CanvasRenderer\n): CanvasRenderer {\n return async (data) => {\n const frame = await renderer(data);\n\n if (drawStencil()) {\n const stencil = await stencilManager.fetch();\n if (stencil != null) {\n const rect = data.viewport.calculateDrawRect(stencil);\n const stencilImage = await loadImageBytes(stencil.imageBytes);\n data.canvas.globalAlpha = 0.25;\n data.canvas.drawImage(\n stencilImage.image,\n rect.x,\n rect.y,\n rect.width,\n rect.height\n );\n data.canvas.globalAlpha = 1;\n stencilImage.dispose();\n }\n }\n\n return frame;\n };\n}\n","import { vertexvis } from '@vertexvis/frame-streaming-protos';\nimport { RequestMessageHandler } from '@vertexvis/stream-api';\n\nexport function ifRequestId(\n f: (id: string) => RequestMessageHandler\n): RequestMessageHandler {\n return (req) => {\n const reqId = req.request.requestId?.value;\n if (reqId != null) {\n f(reqId)(req);\n }\n };\n}\n\nexport function ifDrawFrame(\n f: (\n frame: vertexvis.protobuf.stream.IDrawFramePayload\n ) => RequestMessageHandler\n): RequestMessageHandler {\n return (req) => {\n const { drawFrame } = req.request;\n\n if (drawFrame != null) {\n f(drawFrame)(req);\n }\n };\n}\n","import { google } from '@vertexvis/frame-streaming-protos';\nimport {\n protoToDate,\n RequestMessageHandler,\n StreamApi,\n toProtoDuration,\n} from '@vertexvis/stream-api';\n\nimport { SynchronizedClock } from '../types';\nimport { ifDrawFrame, ifRequestId } from './utils';\n\nconst MUTE_WARNING_SECONDS = 1 * 60; // 1 minute\n\nfunction calculateSendToReceiveDuration(\n clockProvider: () => SynchronizedClock | undefined\n): (sentAt: Date) => google.protobuf.IDuration | undefined {\n let muteWarning = false;\n\n return (sentAt) => {\n const clock = clockProvider();\n if (clock != null) {\n const receivedAt = clock.remoteTime(new Date(Date.now()));\n const duration = toProtoDuration(sentAt, receivedAt);\n\n const durationInMs = protoToDate(duration).getTime();\n if (durationInMs >= 0) {\n return duration;\n } else {\n if (!muteWarning) {\n console.warn(\n `Possible erroneous send to receive timing. Muting for ${MUTE_WARNING_SECONDS}s. [sent-at=${sentAt.toISOString()}, received-at=${receivedAt.toISOString()}, remote-time=${clock.knownRemoteTime.toISOString()}]`\n );\n\n muteWarning = true;\n setTimeout(() => (muteWarning = false), MUTE_WARNING_SECONDS * 1000);\n }\n return undefined;\n }\n }\n };\n}\n\n/**\n * Returns a request handler that will acknowledge any frame requests that it\n * receives.\n *\n * @param api The client to acknowledge frames from.\n * @param clock A function that returns a synchronized clock.\n */\nexport function acknowledgeFrameRequests(\n api: StreamApi,\n clockProvider: () => SynchronizedClock | undefined\n): RequestMessageHandler {\n const sendToReceiveDuration = calculateSendToReceiveDuration(clockProvider);\n return ifRequestId((reqId) =>\n ifDrawFrame((_) => (req) => {\n const sentAt = protoToDate(req.sentAtTime);\n if (sentAt != null) {\n api.replyResult(reqId, {\n drawFrame: {\n sendToReceiveDuration: sendToReceiveDuration(sentAt),\n },\n });\n }\n })\n );\n}\n","export enum StorageKeys {\n DEVICE_ID = 'vertexvis:device-id',\n}\n\nexport function upsertStorageEntry<T>(\n key: string,\n values: Record<string, T>,\n storage: Storage = window.localStorage\n): void {\n const existing = storage.getItem(key);\n\n if (existing != null) {\n const updated = { ...JSON.parse(existing), ...values };\n storage.setItem(key, JSON.stringify(updated));\n } else {\n storage.setItem(key, JSON.stringify(values));\n }\n}\n\nexport function getStorageEntry<T>(\n key: string,\n f: (value: Record<string, T>) => T | undefined,\n storage: Storage = window.localStorage\n): T | undefined {\n const item = storage.getItem(key);\n\n if (item != null) {\n return f(JSON.parse(item));\n }\n}\n","'use strict';\n\n// do not edit .js files directly - edit src/index.jst\n\n\n\nmodule.exports = function equal(a, b) {\n if (a === b) return true;\n\n if (a && b && typeof a == 'object' && typeof b == 'object') {\n if (a.constructor !== b.constructor) return false;\n\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n\n\n\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n\n for (i = length; i-- !== 0;)\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n for (i = length; i-- !== 0;) {\n var key = keys[i];\n\n if (!equal(a[key], b[key])) return false;\n }\n\n return true;\n }\n\n // true if both NaN, false otherwise\n return a!==a && b!==b;\n};\n","import { Dimensions } from '@vertexvis/geometry';\nimport {\n ConnectionDescriptor,\n currentDateAsProtoTimestamp,\n Settings,\n StreamApi,\n StreamRequestError,\n WebSocketClient,\n} from '@vertexvis/stream-api';\nimport {\n Async,\n Color,\n Disposable,\n EventDispatcher,\n Listener,\n Mapper,\n Objects,\n Uri,\n} from '@vertexvis/utils';\nimport deepEqual from 'fast-deep-equal';\n\nimport { Color3, StreamAttributes } from '../../interfaces';\nimport { Config, parseConfig } from '../config';\nimport {\n CustomError,\n SceneRenderError,\n WebsocketConnectionError,\n} from '../errors';\nimport {\n fromPbFrameOrThrow,\n fromPbReconnectResponseOrThrow,\n fromPbRefreshTokenResponseOrThrow,\n fromPbStartStreamResponseOrThrow,\n fromPbSyncTimeResponseOrThrow,\n toPbRGBi,\n toPbStreamAttributes,\n} from '../mappers';\nimport { acknowledgeFrameRequests } from '../rendering';\nimport { Token } from '../token';\nimport {\n Frame,\n LoadableResource,\n Orientation,\n SynchronizedClock,\n} from '../types';\nimport { Resource, SuppliedIdQueryValue } from '../types/loadableResource';\nimport {\n Connected,\n Connecting,\n Reconnecting,\n ViewerStreamState,\n} from './state';\n\ntype StreamResult = Omit<\n Connected,\n 'type' | 'frame' | 'connection' | 'clock'\n> & { frame: Frame | undefined };\n\ninterface FrameStreamOptions {\n /**\n * The number of seconds before the token expires, when the token will be\n * refreshed. Defaults to 30 seconds.\n */\n tokenRefreshOffsetInSeconds?: number;\n\n /**\n * Indicates if debug logs will be emitted for websocket messages.\n */\n loggingEnabled?: boolean;\n\n /**\n * The number of seconds after the host goes offline before a reconnect is\n * attempted.\n */\n offlineThresholdInSeconds?: number;\n\n /**\n * The number of seconds before we consider loading a scene failed.\n */\n loadTimeoutInSeconds?: number;\n\n /**\n * Enable temporal refinement of still images.\n */\n enableTemporalRefinement?: boolean;\n}\n\ninterface UpdateFields {\n dimensions?: ViewerStream['dimensions'];\n streamAttributes?: ViewerStream['streamAttributes'];\n enableTemporalRefinement?: ViewerStream['enableTemporalRefinement'];\n frameBgColor?: ViewerStream['frameBgColor'];\n config?: ViewerStream['config'];\n clientId?: ViewerStream['clientId'];\n deviceId?: ViewerStream['deviceId'];\n}\n\nexport class ViewerStream extends StreamApi {\n private static WS_RECONNECT_DELAYS = [0, 1000, 1000, 5000];\n\n private dimensions: Dimensions.Dimensions;\n private streamAttributes: StreamAttributes;\n private enableTemporalRefinement: boolean;\n private frameBgColor: Color3;\n private config: Config;\n private clientId: string | undefined;\n private deviceId: string | undefined;\n\n private state: ViewerStreamState = { type: 'disconnected' };\n public readonly stateChanged = new EventDispatcher<ViewerStreamState>();\n\n private options: Required<Omit<FrameStreamOptions, 'loggingEnabled'>>;\n\n public constructor(ws: WebSocketClient, opts: FrameStreamOptions = {}) {\n super(ws, { loggingEnabled: opts.loggingEnabled });\n\n this.dimensions = Dimensions.create(0, 0);\n this.streamAttributes = {};\n this.enableTemporalRefinement = opts.enableTemporalRefinement ?? true;\n this.frameBgColor = Color.create(255, 255, 255);\n this.config = parseConfig('platprod');\n\n this.options = {\n tokenRefreshOffsetInSeconds: opts.tokenRefreshOffsetInSeconds ?? 30,\n offlineThresholdInSeconds: opts.offlineThresholdInSeconds ?? 30,\n loadTimeoutInSeconds: opts.loadTimeoutInSeconds ?? 15,\n enableTemporalRefinement: opts.enableTemporalRefinement ?? true,\n };\n }\n\n public getState(): ViewerStreamState {\n return this.state;\n }\n\n public disconnect(): void {\n if (\n this.state.type !== 'disconnected' &&\n this.state.type !== 'connection-failed'\n ) {\n console.debug('Disconnecting websocket');\n this.state.connection.dispose();\n this.updateState({ type: 'disconnected' });\n }\n }\n\n public async load(\n urn: string,\n clientId: string | undefined,\n deviceId: string | undefined,\n config: Config = parseConfig('platprod')\n ): Promise<void> {\n this.clientId = clientId;\n this.deviceId = deviceId;\n this.config = config;\n\n if (this.state.type === 'disconnected') {\n return this.loadIfDisconnected(urn);\n } else if (this.state.type === 'connection-failed') {\n return this.loadIfDisconnected(urn);\n } else if (this.state.type === 'reconnecting') {\n return this.loadIfConnectingOrConnected(urn, this.state);\n } else if (this.state.type === 'connecting') {\n return this.loadIfConnectingOrConnected(urn, this.state);\n } else {\n return this.loadIfConnectingOrConnected(urn, this.state);\n }\n }\n\n public update(fields: UpdateFields): void {\n this.frameBgColor = fields.frameBgColor\n ? fields.frameBgColor\n : this.frameBgColor;\n\n if (\n fields.dimensions != null &&\n !deepEqual(fields.dimensions, this.dimensions)\n ) {\n this.dimensions = fields.dimensions;\n this.ifState('connected', () =>\n this.updateDimensions({ dimensions: this.getDimensions() })\n );\n }\n\n if (\n fields.streamAttributes != null &&\n !deepEqual(this.streamAttributes, fields.streamAttributes)\n ) {\n this.streamAttributes = fields.streamAttributes;\n this.ifState('connected', () =>\n this.updateStream({\n streamAttributes: toPbStreamAttributesOrThrow(this.streamAttributes),\n })\n );\n }\n\n if (\n fields.enableTemporalRefinement != null &&\n fields.enableTemporalRefinement !== this.enableTemporalRefinement\n ) {\n this.enableTemporalRefinement = fields.enableTemporalRefinement;\n\n if (this.state.type === 'connected') {\n this.closeAndReconnect(this.state);\n }\n }\n }\n\n private async loadIfConnectingOrConnected(\n urn: string,\n state: Connected | Connecting | Reconnecting\n ): Promise<void> {\n const { resource: pResource, subResource: pSubResource } = state.resource;\n const resource = LoadableResource.fromUrn(urn);\n\n const hasResourceChanged = !Objects.isEqual(pResource, resource.resource);\n const hasSubResourceChanged = !Objects.isEqual(\n pSubResource,\n resource.subResource\n );\n const isConnecting =\n state.type === 'connecting' || state.type === 'reconnecting';\n const isConnected = state.type === 'connected';\n const suppliedIdQuery = resource.queries.find(\n (q) => q.type === 'supplied-id'\n ) as SuppliedIdQueryValue | undefined;\n\n if (hasResourceChanged || (isConnecting && hasSubResourceChanged)) {\n this.disconnect();\n return this.loadIfDisconnected(urn);\n } else if (\n isConnected &&\n hasSubResourceChanged &&\n resource.subResource?.type === 'scene-view-state'\n ) {\n const payload = {\n ...(resource.subResource.id != null\n ? { sceneViewStateId: { hex: resource.subResource.id } }\n : {}),\n ...(suppliedIdQuery != null\n ? { sceneViewStateSuppliedId: { value: suppliedIdQuery.id } }\n : {}),\n };\n\n await this.loadSceneViewState(payload);\n this.updateState({ ...state, resource });\n }\n }\n\n private async loadIfDisconnected(urn: string): Promise<void> {\n try {\n await this.connectWithNewStream(LoadableResource.fromUrn(urn));\n } catch (e) {\n if (e instanceof CustomError) {\n this.updateState({\n type: 'connection-failed',\n message: `Cannot load scene. ${e.message}`,\n error: e,\n });\n } else if (e instanceof StreamRequestError) {\n this.updateState({\n type: 'connection-failed',\n message: `Cannot load scene. Stream request failed to start stream.`,\n error: e,\n });\n } else {\n this.updateState({\n type: 'connection-failed',\n message: `Cannot load scene for unknown reason. See console logs.`,\n error: e,\n });\n }\n\n throw e;\n }\n }\n\n private connectWithNewStream(resource: Resource): Promise<void> {\n return this.openWebsocketStream(resource, 'connecting', () =>\n this.requestNewStream(resource)\n );\n }\n\n private connectToExistingStream(state: Connected): Promise<void> {\n return this.openWebsocketStream(\n state.resource,\n 'reconnecting',\n () => this.requestReconnectStream(state),\n { maxRetries: Number.POSITIVE_INFINITY }\n );\n }\n\n private async openWebsocketStream(\n resource: Resource,\n type: Connecting['type'] | Reconnecting['type'],\n requestStream: () => Promise<StreamResult>,\n { maxRetries = 3 }: { maxRetries?: number } = {}\n ): Promise<void> {\n const descriptor = getWebsocketDescriptor(\n getWebsocketUri(\n this.config,\n resource.resource,\n this.clientId,\n this.deviceId\n )\n );\n console.debug(`Initiating WS connection [uri=${descriptor.url}]`);\n\n const controller = new AbortController();\n const settings = getStreamSettings(this.config);\n this.updateState({\n type,\n resource,\n connection: {\n dispose: () => {\n this.dispose();\n controller.abort();\n },\n },\n });\n\n const connection = await Async.abort(\n controller.signal,\n Async.retry(() => this.connect(descriptor, settings), {\n maxRetries,\n delaysInMs: ViewerStream.WS_RECONNECT_DELAYS,\n })\n ).catch((e) => {\n throw new WebsocketConnectionError(\n 'Websocket connection failed.',\n e instanceof Error ? e : undefined\n );\n });\n\n if (!connection.aborted) {\n return this.requestNewOrExistingStream(\n resource,\n connection.result,\n requestStream\n );\n } else {\n this.updateState({ type: 'disconnected' });\n }\n }\n\n private async requestNewOrExistingStream(\n resource: Resource,\n connection: Disposable,\n requestStream: () => Promise<StreamResult>\n ): Promise<void> {\n const pendingClock = this.requestClock();\n\n const stream = await requestStream();\n console.debug(\n `Stream connected [stream-id=${stream.streamId}, scene-id=${stream.sceneId}, scene-view-id=${stream.sceneViewId}]`\n );\n\n const onRequest = this.onRequest((msg) => {\n const req = msg.request.drawFrame;\n if (req != null) {\n const frame = fromPbFrameOrThrow(stream.worldOrientation)(req);\n\n if (this.state.type === 'connected') {\n if (\n frame.depthBufferBytes != null ||\n this.state.frame.temporalRefinementCorrelationId !==\n frame.temporalRefinementCorrelationId\n ) {\n this.updateState({\n ...this.state,\n frame: frame,\n fallbackDepthBufferBytes: frame.depthBufferBytes,\n });\n } else {\n this.updateState({\n ...this.state,\n frame: frame.copy({\n depthBufferBytes: this.state.fallbackDepthBufferBytes,\n }),\n });\n }\n }\n }\n });\n\n const reconnect = this.reconnectWhenNeeded();\n const refreshToken = this.refreshTokenWhenExpired(stream.token);\n const acknowledgeFrameRequests = this.acknowledgeFrameRequests();\n const frame =\n stream.frame == null\n ? await this.waitForFrame(\n stream.worldOrientation,\n this.options.loadTimeoutInSeconds\n )\n : stream.frame;\n const clock = await pendingClock;\n console.debug(\n `Synchronized clocks [local-time=${clock.knownLocalTime.toISOString()}, remote-time=${clock.knownRemoteTime.toISOString()}]`\n );\n\n this.updateState({\n type: 'connected',\n connection: {\n dispose: () => {\n reconnect.dispose();\n onRequest.dispose();\n refreshToken.dispose();\n acknowledgeFrameRequests.dispose();\n connection.dispose();\n },\n },\n resource,\n streamId: stream.streamId,\n deviceId: stream.deviceId,\n sceneId: stream.sceneId,\n sceneViewId: stream.sceneViewId,\n worldOrientation: stream.worldOrientation,\n token: stream.token,\n frame,\n clock,\n fallbackDepthBufferBytes: undefined,\n });\n }\n\n private async requestNewStream(resource: Resource): Promise<StreamResult> {\n const suppliedIdQuery = resource.queries.find(\n (q) => q.type === 'supplied-id'\n ) as SuppliedIdQueryValue | undefined;\n\n const res = fromPbStartStreamResponseOrThrow(\n await this.startStream({\n streamKey: { value: resource.resource.id },\n dimensions: this.getDimensions(),\n frameBackgroundColor: toPbColorOrThrow(this.frameBgColor),\n clientSupportsTemporalRefinement: this.enableTemporalRefinement,\n streamAttributes: toPbStreamAttributesOrThrow(this.streamAttributes),\n sceneViewStateId:\n resource.subResource?.type === 'scene-view-state' &&\n resource.subResource.id != null\n ? { hex: resource.subResource.id }\n : undefined,\n sceneViewStateSuppliedId:\n resource.subResource?.type === 'scene-view-state' &&\n suppliedIdQuery != null\n ? { value: suppliedIdQuery.id }\n : undefined,\n })\n );\n\n return {\n resource: resource,\n streamId: res.streamId,\n sceneId: res.sceneId,\n sceneViewId: res.sceneViewId,\n deviceId: res.sessionId,\n token: res.token,\n worldOrientation: res.worldOrientation,\n frame: undefined,\n fallbackDepthBufferBytes: undefined,\n };\n }\n\n private async requestReconnectStream(\n state: Connected\n ): Promise<StreamResult> {\n const res = fromPbReconnectResponseOrThrow(\n await this.reconnect({\n streamId: { hex: state.streamId },\n dimensions: this.getDimensions(),\n frameBackgroundColor: toPbColorOrThrow(this.frameBgColor),\n streamAttributes: toPbStreamAttributesOrThrow(this.streamAttributes),\n clientSupportsTemporalRefinement: this.enableTemporalRefinement,\n })\n );\n return { ...state, token: res.token };\n }\n\n private async requestClock(): Promise<SynchronizedClock> {\n const remoteTime = fromPbSyncTimeResponseOrThrow(\n await this.syncTime({\n requestTime: currentDateAsProtoTimestamp(),\n })\n );\n\n return new SynchronizedClock(remoteTime);\n }\n\n private reconnectWhenNeeded(): Disposable {\n const whenDisconnected = this.onClose(() => {\n if (this.state.type === 'connected') {\n this.closeAndReconnect(this.state);\n }\n });\n\n const whenRequested = this.onRequest((msg) => {\n const isReconnectMsg = msg.request.gracefulReconnection != null;\n if (isReconnectMsg && this.state.type === 'connected') {\n console.debug(\n 'Received request for graceful reconnect. Closing connection and attempting reconnect.'\n );\n this.closeAndReconnect(this.state);\n }\n });\n\n const whenOffline = this.reconnectWhenOffline();\n\n return {\n dispose: () => {\n whenDisconnected.dispose();\n whenRequested.dispose();\n whenOffline.dispose();\n },\n };\n }\n\n private refreshTokenWhenExpired(token: Token): Disposable {\n let timer: number;\n\n const startTimer = (token: Token): void => {\n const { tokenRefreshOffsetInSeconds } = this.options;\n const ms = token.remainingTimeInMs(tokenRefreshOffsetInSeconds);\n\n timer = window.setTimeout(async () => {\n const res = await this.refreshToken();\n const newToken = fromPbRefreshTokenResponseOrThrow(res);\n startTimer(newToken);\n if (this.state.type === 'connected') {\n this.updateState({ ...this.state, token: newToken });\n }\n }, ms);\n };\n\n startTimer(token);\n\n return { dispose: () => clearTimeout(timer) };\n }\n\n private reconnectWhenOffline(): Disposable {\n let timer: number;\n\n const clearTimer = (): void => window.clearTimeout(timer);\n\n const restartTimer = (): void => {\n clearTimer();\n\n const delayInSec = this.options.offlineThresholdInSeconds;\n console.debug(\n `Detected that host is offline. Will attempt reconnect in ${delayInSec}s.`\n );\n\n timer = window.setTimeout(() => {\n if (this.state.type === 'connected') {\n this.closeAndReconnect(this.state);\n }\n }, delayInSec * 1000);\n };\n\n const handleOnline = (): void => {\n console.debug('Detected that host is online.');\n clearTimer();\n };\n\n const handleOffline = (): void => restartTimer();\n\n window.addEventListener('offline', handleOffline);\n window.addEventListener('online', handleOnline);\n\n return {\n dispose: () => {\n clearTimer();\n window.removeEventListener('offline', restartTimer);\n window.removeEventListener('online', clearTimer);\n },\n };\n }\n\n private closeAndReconnect(state: Connected): Promise<void> {\n state.connection.dispose();\n return this.connectToExistingStream(state);\n }\n\n private async waitForFrame(\n worldOrientation: Orientation,\n timeoutInSeconds: number\n ): Promise<Frame> {\n let disposable: Disposable | undefined;\n\n try {\n return await Async.timeout(\n timeoutInSeconds * 1000,\n new Promise<Frame>((resolve) => {\n disposable = this.onRequest((msg) => {\n try {\n const req = msg.request.drawFrame;\n if (req != null) {\n const frame = fromPbFrameOrThrow(worldOrientation)(req);\n resolve(frame);\n }\n } finally {\n disposable?.dispose();\n }\n });\n })\n );\n } catch (e) {\n throw new SceneRenderError(\n `Frame timed out after ${timeoutInSeconds / 1000}s`,\n e instanceof Error ? e : undefined\n );\n } finally {\n disposable?.dispose();\n }\n }\n\n private acknowledgeFrameRequests(): Disposable {\n return this.onRequest(\n acknowledgeFrameRequests(this, () =>\n this.state.type === 'connected' ? this.state.clock : undefined\n )\n );\n }\n\n private updateState(state: ViewerStreamState): void {\n if (this.state !== state) {\n this.state = state;\n this.stateChanged.emit(this.state);\n }\n }\n\n private getDimensions(): Dimensions.Dimensions {\n if (Dimensions.area(this.dimensions) === 0) {\n // Ensure we always request at least a 1-pixel frame, even if the dimensions\n // haven't been set higher than zero.\n return Dimensions.create(1, 1);\n }\n return this.dimensions;\n }\n\n private ifState<T>(\n state: ViewerStreamState['type'],\n f: () => T\n ): T | undefined {\n if (this.state.type === state) {\n return f();\n }\n }\n\n public onStateChanged(listener: Listener<ViewerStreamState>): Disposable {\n return this.stateChanged.on(listener);\n }\n}\n\nconst toPbStreamAttributesOrThrow = Mapper.ifInvalidThrow(toPbStreamAttributes);\nconst toPbColorOrThrow = Mapper.ifInvalidThrow(toPbRGBi);\n\nfunction getStreamSettings(config: Config): Settings {\n return {\n EXPERIMENTAL_frameDelivery: {\n ...config.EXPERIMENTAL_frameDelivery,\n rateLimitingEnabled: config.flags.throttleFrameDelivery,\n },\n EXPERIMENTAL_adaptiveRendering: {\n ...config.EXPERIMENTAL_adaptiveRendering,\n enabled: config.flags.adaptiveRendering,\n },\n EXPERIMENTAL_qualityOfService: {\n ...config.EXPERIMENTAL_qualityOfService,\n },\n };\n}\n\nfunction getWebsocketDescriptor(uri: Uri.Uri): ConnectionDescriptor {\n return {\n url: Uri.toString(uri),\n protocols: ['ws.vertexvis.com'],\n };\n}\n\nfunction getWebsocketUri(\n config: Config,\n resource: LoadableResource.LoadableResource,\n clientId?: string,\n deviceId?: string\n): Uri.Uri {\n if (clientId != null) {\n return Uri.appendPath(\n Uri.toString(\n Uri.parseAndAddParams('/ws', {\n clientId,\n deviceId,\n })\n ),\n Uri.parse(config.network.renderingHost)\n );\n } else {\n return Uri.appendPath(\n `/stream-keys/${resource.id}/session`,\n Uri.parse(config.network.renderingHost)\n );\n }\n}\n","import { Color } from '@vertexvis/utils';\n\nexport const DEFAULT_VIEWER_SCENE_WAIT_MS = 15000;\n\nexport function getElementBackgroundColor(\n element: HTMLElement\n): Color.Color | undefined {\n const styles = window.getComputedStyle(element);\n return Color.fromCss(styles.backgroundColor);\n}\n\nexport function getElementBoundingClientRect(element: HTMLElement): ClientRect {\n return element.getBoundingClientRect();\n}\n\nexport function getElementPropertyValue(\n element: HTMLElement,\n property: string\n): string | undefined {\n const styles = window.getComputedStyle(element);\n const value = styles.getPropertyValue(property);\n return value !== '' ? value : undefined;\n}\n",":host {\n /**\n * @prop --image-background: The background color of the rendered image.\n * Defaults to `--viewer-background`.\n */\n --image-background: var(--image-background);\n\n /**\n * @prop --viewer-background: The background color of the viewer component.\n * This will be visible if the size of the viewer becomes greater than the\n * maximum image size of 1280x1280. Defaults to #FFFFFF.\n */\n --viewer-background: var(--viewer-background);\n\n display: block;\n position: relative;\n width: 300px;\n height: 300px;\n min-width: 1px;\n min-height: 1px;\n\n user-select: none;\n -webkit-user-select: none;\n}\n\n.canvas-container {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n position: relative;\n}\n.enable-pointer-events {\n touch-action: none;\n}\n\n.viewer-container {\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.error-message {\n position: absolute;\n top: 50%;\n width: 100%;\n transform: translateY(-50%);\n text-align: center;\n}\n","import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Listen,\n Method,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport { Dimensions, Point } from '@vertexvis/geometry';\nimport { SceneViewAPIClient } from '@vertexvis/scene-view-protos/sceneview/protos/scene_view_api_pb_service';\nimport { toProtoDuration, WebSocketClientImpl } from '@vertexvis/stream-api';\nimport { Color, Disposable, EventDispatcher, UUID } from '@vertexvis/utils';\nimport classnames from 'classnames';\n\nimport {\n FeatureHighlightOptions,\n FeatureLineOptions,\n FrameType,\n PhantomOptions,\n SceneComparisonOptions,\n SelectionHighlightingOptions,\n StreamAttributes,\n} from '../../interfaces';\nimport {\n AnnotationController,\n AnnotationState,\n} from '../../lib/annotations/controller';\nimport { Config, parseConfig, PartialConfig } from '../../lib/config';\nimport { Cursor, CursorManager } from '../../lib/cursors';\nimport { cssCursor } from '../../lib/dom';\nimport { Environment } from '../../lib/environment';\nimport {\n ComponentInitializationError,\n InteractionHandlerError,\n ViewerInitializationError,\n} from '../../lib/errors';\nimport {\n InteractionApiOrthographic,\n InteractionApiPerspective,\n} from '../../lib/interactions';\nimport { BaseInteractionHandler } from '../../lib/interactions/baseInteractionHandler';\nimport { FlyToPartKeyInteraction } from '../../lib/interactions/flyToPartKeyInteraction';\nimport { FlyToPositionKeyInteraction } from '../../lib/interactions/flyToPositionKeyInteraction';\nimport { InteractionApi } from '../../lib/interactions/interactionApi';\nimport { InteractionHandler } from '../../lib/interactions/interactionHandler';\nimport { KeyInteraction } from '../../lib/interactions/keyInteraction';\nimport { MouseInteractionHandler } from '../../lib/interactions/mouseInteractionHandler';\nimport { MultiPointerInteractionHandler } from '../../lib/interactions/multiPointerInteractionHandler';\nimport { PointerInteractionHandler } from '../../lib/interactions/pointerInteractionHandler';\nimport { TapEventDetails } from '../../lib/interactions/tapEventDetails';\nimport { TapInteractionHandler } from '../../lib/interactions/tapInteractionHandler';\nimport { TouchInteractionHandler } from '../../lib/interactions/touchInteractionHandler';\nimport { fromPbFrameOrThrow } from '../../lib/mappers';\nimport { paintTime, Timing } from '../../lib/meters';\nimport { ModelViewController } from '../../lib/model-views/controller';\nimport {\n CanvasRenderer,\n createCanvasRenderer,\n measureCanvasRenderer,\n} from '../../lib/rendering';\nimport { Scene } from '../../lib/scenes/scene';\nimport { writeDOM } from '../../lib/stencil';\nimport {\n getStorageEntry,\n StorageKeys,\n upsertStorageEntry,\n} from '../../lib/storage';\nimport {\n Connected,\n Connecting,\n ConnectionFailed,\n Disconnected,\n ViewerStreamState,\n} from '../../lib/stream/state';\nimport { ViewerStream } from '../../lib/stream/stream';\nimport {\n FrameCamera,\n Orientation,\n SceneViewSummary,\n StencilBufferManager,\n Viewport,\n} from '../../lib/types';\nimport { Frame, FrameCameraBase } from '../../lib/types/frame';\nimport { FrameCameraType } from '../../lib/types/frameCamera';\nimport {\n DEFAULT_VIEWER_SCENE_WAIT_MS,\n getElementBoundingClientRect,\n getElementPropertyValue,\n} from './utils';\n\ninterface ConnectedStatus {\n jwt: string;\n status: 'connected';\n}\n\ninterface ConnectingStatus {\n status: 'connecting';\n}\n\ninterface DisconnectedStatus {\n status: 'disconnected';\n}\n\ninterface ConnectionFailedStatus {\n status: 'connection-failed';\n errorMessage: string;\n}\n\n/**\n * Internal state values for the component. Used to preserve values across live\n * reload refreshes.\n */\ninterface StateMap {\n streamWorldOrientation?: Orientation;\n cursorManager: CursorManager;\n interactionTarget?: HTMLElement;\n streamState: ViewerStreamState;\n streamListeners?: Disposable;\n}\n\n/** @internal */\nexport type ConnectionStatus =\n | ConnectingStatus\n | ConnectedStatus\n | DisconnectedStatus\n | ConnectionFailedStatus;\n\n@Component({\n tag: 'vertex-viewer',\n styleUrl: 'viewer.css',\n shadow: true,\n})\nexport class Viewer {\n @Element() private hostElement!: HTMLVertexViewerElement;\n\n /**\n * A URN of the scene resource to load when the component is mounted in the\n * DOM tree. The specified resource is a URN in the following format:\n *\n * * `urn:vertex:scene:<sceneid>`\n */\n @Prop() public src?: string;\n\n /**\n * The Client ID associated with your Vertex Application.\n */\n @Prop() public clientId?: string;\n\n /**\n * Property used for internals or testing.\n *\n * @private\n * @internal\n */\n @Prop({ mutable: true }) public deviceId?: string;\n\n /**\n * An object or JSON encoded string that defines configuration settings for\n * the viewer.\n */\n @Prop() public config?: PartialConfig | string;\n\n /**\n * Sets the default environment for the viewer. This setting is used for\n * auto-configuring network hosts.\n *\n * Use the `config` property for manually setting hosts.\n *\n * @see Viewer.config\n */\n @Prop() public configEnv: Environment = 'platprod';\n\n /**\n * @internal\n */\n @Prop({ mutable: true }) public resolvedConfig?: Config;\n\n /**\n * Enables or disables the default mouse and touch interactions provided by\n * the viewer. Enabled by default.\n */\n @Prop() public cameraControls = true;\n\n /**\n * The type of camera model to represent the scene with. Can be either\n * `perspective` or `orthographic`, and defaults to `perspective`.\n */\n @Prop({ mutable: true, reflect: true }) public cameraType: FrameCameraType =\n 'perspective';\n\n /**\n * Enables or disables the default keyboard shortcut interactions provided by\n * the viewer. Enabled by default, requires `cameraControls` being enabled.\n *\n */\n @Prop() public keyboardControls = true;\n\n /**\n * Enables or disables the default rotation interaction being changed to\n * rotate around the pointer down location.\n */\n @Prop() public rotateAroundTapPoint = true;\n\n /**\n * A token that can be used to make API calls to other Vertex services.\n *\n * @internal\n */\n @Prop({ mutable: true }) public token?: string;\n\n /**\n * Specifies when a depth buffer is requested from rendering. Possible values\n * are:\n *\n * * `undefined`: A depth buffer is never requested.\n * * `final`: A depth buffer is only requested on the final frame.\n * * `all`: A depth buffer is requested for every frame.\n *\n * Depth buffers can increase the amount of data that's sent to a client and\n * can impact rendering performance. Values of `undefined` or `final` should\n * be used when needing the highest rendering performance.\n */\n @Prop() public depthBuffers?: FrameType;\n\n /**\n * Specifies how phantom parts should appear.\n * The opacity must be between 0 and 1, where 0 is completely hidden and 1 is completely visible.\n */\n @Prop({ attribute: null })\n public phantom?: PhantomOptions = { opacity: 0.1 };\n\n /**\n * Specifies whether to use the default lights for the scene. When false, default\n * lights are used. When true, no default lights are used, and the lights must\n * be specified separately.\n */\n @Prop() public noDefaultLights = false;\n\n /**\n * Specifies whether to enable temporal refinement of still images.\n */\n @Prop() public enableTemporalRefinement = true;\n\n /**\n * @private\n * @internal\n * Specifies experimental rendering options. For Vertex use only.\n */\n @Prop() public experimentalRenderingOptions = '';\n\n /**\n * Specifies if and how to render feature lines.\n */\n @Prop({ attribute: null }) public featureLines?: FeatureLineOptions;\n\n /**\n * Specifies the halo selection properties.\n * Parameter notes:\n * * lineWidth values supported currently are 0-5. This width is currently the value x2. For example, 1 will have a pixel width of 2.\n * * color is optional. This will be the color of the selected items in the viewer.\n * * opacity is also optional. The opacity will be applied to everything selected besides the highlighted outer line.\n */\n @Prop({ attribute: null })\n public selectionHighlighting?: SelectionHighlightingOptions;\n\n /**\n * Specifies how selected features should be highlighted.\n */\n @Prop({ attribute: null })\n public featureHighlighting?: FeatureHighlightOptions;\n\n /**\n * Specifies if and how to compare to another scene\n */\n @Prop({ attribute: null })\n public sceneComparison?: SceneComparisonOptions;\n\n /**\n * Specifies when a feature map is returned from rendering. Feature maps\n * include information about the surfaces, edges and cross sections that are\n * in a frame.\n *\n * Possible values are:\n *\n * * `undefined`: A feature map is never requested.\n * * `final`: A feature map is only requested on the final frame.\n * * `all`: A feature map is requested for every frame.\n *\n * Feature maps can increase the amount of data that's sent to a client and\n * can impact rendering performance. Values of `undefined` or `final` should\n * be used when needing the highest rendering performance.\n */\n @Prop() public featureMaps?: FrameType;\n\n /**\n * An optional value that will debounce frame updates when resizing\n * this viewer element.\n */\n @Prop() public resizeDebounce = 100;\n\n /**\n * The last frame that was received, which can be used to inspect the scene\n * and camera information.\n *\n * @readonly\n */\n @Prop({ mutable: true }) public frame: Frame | undefined;\n\n /**\n * @internal\n */\n @Prop({ mutable: true }) public stream?: ViewerStream;\n\n /**\n * @internal\n */\n @Prop({ mutable: true })\n public stencilBuffer: StencilBufferManager = new StencilBufferManager(\n this.hostElement\n );\n\n /**\n * Represents the current viewport of the viewer. The viewport represents the\n * dimensions of the canvas where a frame is rendered. It contains methods for\n * translating between viewport coordinates, frame coordinates and world\n * coordinates.\n */\n @Prop({ mutable: true })\n public viewport: Viewport = Viewport.fromDimensions(Dimensions.create(0, 0));\n\n /**\n * The annotation controller for accessing annotations associated with the\n * scene view.\n *\n * @readonly\n */\n @Prop({ mutable: true }) public annotations: AnnotationController | undefined;\n\n /**\n * The controller for accessing model views associated with the scene view.\n *\n * @readonly\n */\n @Prop({ mutable: true }) public modelViews: ModelViewController | undefined;\n\n /**\n * Emits an event whenever the user taps or clicks a location in the viewer.\n * The event includes the location of the tap or click.\n *\n * This event can be used in combination with the {@link VertexViewer.scene scene} method\n * to query for items at the point of the tap.\n *\n * @see {@link Scene.raycaster Scene.raycaster} for more information.\n */\n @Event() public tap!: EventEmitter<TapEventDetails>;\n\n /**\n * Emits an event whenever the user double taps or clicks a location in the viewer.\n * The event includes the location of the first tap or click.\n */\n @Event() public doubletap!: EventEmitter<TapEventDetails>;\n\n /**\n * Emits an event whenever the user taps or clicks a location in the viewer and the\n * configured amount of time passes without receiving a mouseup or touchend.\n * The event includes the location of the tap or click.\n */\n @Event() public longpress!: EventEmitter<TapEventDetails>;\n\n /**\n * Emits an event when a frame has been received by the viewer. The event\n * will include details about the drawn frame, such as the `Scene` information\n * related to the scene.\n */\n @Event() public frameReceived!: EventEmitter<Frame>;\n\n /**\n * Emits an event when a frame has been drawn to the viewer's canvas. The event\n * will include details about the drawn frame, such as the `Scene` information\n * related to the scene.\n */\n @Event() public frameDrawn!: EventEmitter<Frame>;\n\n /**\n * Emits an event when a provided oauth2 token is about to expire, or is about to expire,\n * causing issues with establishing a websocket connection, or performing API calls.\n */\n @Event() public tokenExpired!: EventEmitter<void>;\n\n /**\n * Emits an event when the connection status changes for the viewer\n */\n @Event() public connectionChange!: EventEmitter<ConnectionStatus>;\n\n /**\n * Emits an event when the scene is ready to be interacted with.\n */\n @Event() public sceneReady!: EventEmitter<void>;\n\n /**\n * Emits an event when a frame is received with a different scene attribute.\n */\n @Event() public sceneChanged!: EventEmitter<void>;\n\n /**\n * Emits an event when the user has started an interaction.\n */\n @Event() public interactionStarted!: EventEmitter<void>;\n\n /**\n * Emits an event when the user hs finished an interaction.\n */\n @Event() public interactionFinished!: EventEmitter<void>;\n\n /**\n * Emits an event when the camera has changed.\n */\n @Event() public cameraChanged!: EventEmitter<FrameCameraBase | undefined>;\n\n /**\n * Emits an event when the camera type changes.\n */\n @Event() public cameraTypeChanged!: EventEmitter<FrameCameraType>;\n\n /**\n * Emits an event when the state for annotation changes.\n */\n @Event() public annotationStateChanged!: EventEmitter<AnnotationState>;\n\n /**\n * Used for internals or testing.\n *\n * @private\n */\n @Event() public deviceIdChange!: EventEmitter<string>;\n\n @Event() public dimensionschange!: EventEmitter<Dimensions.Dimensions>;\n\n @State() private dimensions?: Dimensions.Dimensions;\n @State() private hostDimensions?: Dimensions.Dimensions;\n @State() private errorMessage?: string;\n\n @State() private cursor?: Cursor;\n\n /**\n * This stores internal state that you want to preserve across live-reloads,\n * but shouldn't trigger a refresh if the data changes. Marking this with\n * @State to allow to preserve state across live-reloads.\n */\n @State() private stateMap: StateMap = {\n cursorManager: new CursorManager(),\n streamState: { type: 'disconnected' },\n };\n\n private viewerContainerElement?: HTMLElement;\n private canvasContainerElement?: HTMLElement;\n private canvasElement?: HTMLCanvasElement;\n\n private canvasRenderer!: CanvasRenderer;\n\n private mutationObserver?: MutationObserver;\n private styleObserver?: MutationObserver;\n private resizeObserver?: ResizeObserver;\n private isResizing?: boolean;\n private isResizeUpdate?: boolean;\n\n private resizeTimer?: NodeJS.Timeout;\n\n private interactionHandlers: InteractionHandler[] = [];\n private defaultInteractionHandlerDisposables: Array<Disposable> = [];\n private tapHandlerDisposable?: Disposable;\n private interactionApi!: InteractionApi;\n private tapKeyInteractions: KeyInteraction<TapEventDetails>[] = [];\n private defaultTapKeyInteractions: KeyInteraction<TapEventDetails>[] = [];\n private baseInteractionHandler?: BaseInteractionHandler;\n\n private internalFrameDrawnDispatcher = new EventDispatcher<Frame>();\n\n public constructor() {\n this.handleElementResize = this.handleElementResize.bind(this);\n }\n\n /**\n * @ignore\n */\n protected componentWillLoad(): void {\n this.updateResolvedConfig();\n this.calculateComponentDimensions();\n\n this.resizeObserver = new ResizeObserver(this.handleElementResize);\n this.registerSlotChangeListeners();\n\n const config = this.getResolvedConfig();\n const client = new SceneViewAPIClient(config.network.sceneViewHost);\n\n this.annotations = new AnnotationController(\n client,\n () => this.token,\n () => this.deviceId\n );\n this.annotations.onStateChange.on((state) =>\n this.annotationStateChanged.emit(state)\n );\n\n this.stream =\n this.stream ??\n new ViewerStream(new WebSocketClientImpl(), {\n loggingEnabled: config.flags.logWsMessages,\n enableTemporalRefinement: this.enableTemporalRefinement,\n });\n this.addStreamListeners();\n\n this.modelViews = new ModelViewController(\n client,\n this.stream,\n () => this.token,\n () => this.deviceId\n );\n\n this.updateStreamAttributes();\n this.stateMap.cursorManager.onChanged.on(() => this.handleCursorChanged());\n }\n\n /**\n * @ignore\n */\n protected async componentDidLoad(): Promise<void> {\n this.interactionApi = this.createInteractionApi();\n\n if (this.canvasContainerElement != null) {\n this.resizeObserver?.observe(this.canvasContainerElement);\n }\n\n if (this.src != null) {\n this.load(this.src).catch((e) => {\n console.error('Error loading scene', e);\n });\n }\n\n await this.initializeDefaultInteractionHandlers();\n this.injectViewerApi();\n }\n\n /**\n * @ignore\n */\n protected render(): h.JSX.IntrinsicElements {\n return (\n <Host>\n <div\n ref={(ref) => (this.viewerContainerElement = ref)}\n class=\"viewer-container\"\n style={{ cursor: cssCursor(this.cursor ?? '') }}\n onContextMenu={(event) => event.preventDefault()}\n >\n <div\n ref={(ref) => (this.canvasContainerElement = ref)}\n class={classnames('canvas-container', {\n 'enable-pointer-events ': window.PointerEvent != null,\n })}\n >\n <canvas\n ref={(ref) => {\n this.canvasElement = ref;\n this.stateMap.interactionTarget = ref;\n }}\n class=\"canvas\"\n ></canvas>\n {this.errorMessage != null ? (\n <div class=\"error-message\">{this.errorMessage}</div>\n ) : null}\n </div>\n <slot></slot>\n </div>\n </Host>\n );\n }\n\n /**\n * @internal\n */\n @Method()\n public async dispatchFrameDrawn(frame: Frame): Promise<void> {\n this.frame = frame;\n this.internalFrameDrawnDispatcher.emit(frame);\n this.frameDrawn.emit(frame);\n }\n\n /**\n * Registers and initializes an interaction handler with the viewer. Returns a\n * `Disposable` that should be used to deregister the interaction handler.\n *\n * `InteractionHandler`s are used to build custom mouse and touch interactions\n * for the viewer. Use `<vertex-viewer camera-controls=\"false\" />` to disable\n * the default camera controls provided by the viewer.\n *\n * @example\n * ```\n * class CustomInteractionHandler extends InteractionHandler {\n * private element: HTMLElement;\n * private api: InteractionApi;\n *\n * public dispose(): void {\n * this.element.removeEventListener('click', this.handleElementClick);\n * }\n *\n * public initialize(element: HTMLElement, api: InteractionApi): void {\n * this.api = api;\n * this.element = element;\n * this.element.addEventListener('click', this.handleElementClick);\n * }\n *\n * private handleElementClick = (event: MouseEvent) => {\n * api.tap({ x: event.clientX, y: event.clientY });\n * }\n * }\n *\n * const viewer = document.querySelector(\"vertex-viewer\");\n * viewer.registerInteractionHandler(new CustomInteractionHandler);\n * ```\n *\n * @param interactionHandler The interaction handler to register.\n * @returns {Promise<void>} A promise containing the disposable to use to\n * deregister the handler.\n */\n @Method()\n public async registerInteractionHandler(\n interactionHandler: InteractionHandler\n ): Promise<Disposable> {\n this.interactionHandlers.push(interactionHandler);\n this.initializeInteractionHandler(interactionHandler);\n return {\n dispose: () => {\n const index = this.interactionHandlers.indexOf(interactionHandler);\n if (index !== -1) {\n this.interactionHandlers[index].dispose();\n this.interactionHandlers.splice(index, 1);\n }\n },\n };\n }\n\n /**\n * Registers a key interaction to be invoked when a specific set of\n * keys are pressed during a `tap` event.\n *\n * `KeyInteraction`s are used to build custom keyboard shortcuts for the\n * viewer using the current state of they keyboard to determine whether\n * the `fn` should be invoked. Use `<vertex-viewer keyboard-controls=\"false\" />`\n * to disable the default keyboard shortcuts provided by the viewer.\n *\n * @example\n * ```\n * class CustomKeyboardInteraction extends KeyInteraction<TapEventDetails> {\n * constructor(private viewer: HTMLVertexViewerElement) {}\n *\n * public predicate(keyState: KeyState): boolean {\n * return keyState['Alt'];\n * }\n *\n * public async fn(event: TapEventDetails) {\n * const scene = await this.viewer.scene();\n * const result = await scene.raycaster().hitItems(event.position);\n *\n * if (result.hits.length > 0) {\n * await scene\n * .camera()\n * .fitTo(q => q.withItemId(result.hits[0].itemId))\n * .render();\n * }\n * }\n * }\n * ```\n *\n * @param keyInteraction - The `KeyInteraction` to register.\n */\n @Method()\n public async registerTapKeyInteraction(\n keyInteraction: KeyInteraction<TapEventDetails>\n ): Promise<void> {\n this.tapKeyInteractions = [...this.tapKeyInteractions, keyInteraction];\n }\n\n /**\n * The HTML element that will handle interaction events from the user. Used by\n * components to listen for interaction events from the same element as the\n * viewer. Note, this property maybe removed in the future when refactoring\n * our interaction handling.\n *\n * @internal\n * @deprecated Use `InteractionHandler`.\n */\n @Method()\n public async getInteractionTarget_DEPRECATED(): Promise<HTMLElement> {\n if (this.stateMap.interactionTarget != null) {\n return this.stateMap.interactionTarget;\n } else throw new Error('Interaction target is undefined.');\n }\n\n /**\n * Adds a cursor to the viewer, and displays it if the cursor has the highest\n * priority.\n *\n * Cursors are managed as a prioritized list. A cursor is displayed if it has\n * the highest priority or if the cursor is the most recently added cursor in\n * the set of cursors with the same priority.\n *\n * To remove a cursor, call `dispose()` on the returned disposable.\n *\n * @param cursor The cursor to add.\n * @param priority The priority of the cursor.\n * @returns A disposable that can be used to remove the cursor.\n * @see See {@link CursorManager} for constants to pass to `priority`.\n */\n @Method()\n public async addCursor(\n cursor: Cursor,\n priority?: number\n ): Promise<Disposable> {\n return this.stateMap.cursorManager.add(cursor, priority);\n }\n\n @Method()\n public async getInteractionHandlers(): Promise<InteractionHandler[]> {\n return this.interactionHandlers;\n }\n\n /**\n * @internal\n * @ignore\n */\n @Method()\n public async getKeyInteractions(): Promise<\n KeyInteraction<TapEventDetails>[]\n > {\n return this.tapKeyInteractions;\n }\n\n @Method()\n public async getBaseInteractionHandler(): Promise<\n BaseInteractionHandler | undefined\n > {\n return this.baseInteractionHandler;\n }\n\n /**\n * @deprecated Use `token`.\n */\n @Method()\n public async getJwt(): Promise<string | undefined> {\n return this.token;\n }\n\n @Watch('src')\n public handleSrcChanged(src: string | undefined): void {\n if (src != null) {\n this.load(src);\n } else {\n this.unload();\n }\n }\n\n /**\n * @ignore\n */\n @Watch('cameraControls')\n protected handleCameraControlsChanged(): void {\n this.initializeDefaultCameraInteractionHandlers();\n }\n\n /**\n * @ignore\n */\n @Watch('keyboardControls')\n protected handleKeyboardControlsChanged(): void {\n this.initializeDefaultKeyboardInteractionHandlers();\n }\n\n /**\n * @ignore\n */\n @Watch('rotateAroundTapPoint')\n protected handleRotateAboutTapPointChanged(): void {\n this.updateStreamAttributes();\n if (this.rotateAroundTapPoint) {\n this.baseInteractionHandler?.setPrimaryInteractionType('rotate-point');\n } else {\n this.baseInteractionHandler?.setPrimaryInteractionType('rotate');\n }\n }\n\n @Watch('cameraType')\n protected handleCameraTypeChanged(\n updatedCameraType: string,\n previousCameraType: string\n ): void {\n if (updatedCameraType !== previousCameraType) {\n this.updateCameraType();\n }\n }\n\n /**\n * @ignore\n */\n @Watch('experimentalRenderingOptions')\n @Watch('depthBuffers')\n @Watch('featureHighlighting')\n @Watch('featureLines')\n @Watch('featureMaps')\n @Watch('noDefaultLights')\n @Watch('phantom')\n @Watch('sceneComparison')\n @Watch('selectionHighlighting')\n protected handleStreamAttributesChanged(): void {\n this.updateStreamAttributes();\n }\n\n /**\n * @ignore\n */\n @Watch('enableTemporalRefinement')\n protected handleEnableTemporalRefinementChanged(): void {\n this.updateEnableTemporalRefinement();\n }\n\n /**\n * @ignore\n */\n @Watch('config')\n protected handleConfigChanged(): void {\n this.updateResolvedConfig();\n }\n\n /**\n * @ignore\n */\n @Watch('configEnv')\n protected handleConfigEnvChanged(): void {\n this.updateResolvedConfig();\n }\n\n /**\n * Loads the given scene into the viewer and return a `Promise` that\n * resolves when the scene has been loaded. The specified scene is\n * provided as a URN in the following format:\n *\n * * `urn:vertex:scene:<sceneid>`\n *\n * @param urn The URN of the resource to load.\n */\n @Method()\n public async load(urn: string): Promise<void> {\n if (this.stream != null && this.dimensions != null) {\n const { EXPERIMENTAL_annotationPollingIntervalInMs } =\n this.getResolvedConfig();\n\n this.calculateComponentDimensions();\n\n this.stream.update({\n streamAttributes: this.getStreamAttributes(),\n config: parseConfig(this.configEnv, this.config),\n dimensions: this.dimensions,\n frameBgColor: this.getBackgroundColor(),\n });\n await this.stream?.load(\n urn,\n this.clientId,\n this.getDeviceId(),\n this.getResolvedConfig()\n );\n this.sceneReady.emit();\n\n if (EXPERIMENTAL_annotationPollingIntervalInMs !== undefined) {\n this.annotations?.connect(EXPERIMENTAL_annotationPollingIntervalInMs);\n }\n } else {\n throw new ViewerInitializationError(\n 'Cannot load scene. Viewer has not been initialized.'\n );\n }\n }\n\n /**\n * Disconnects the websocket and removes any internal state associated with\n * the scene.\n */\n @Method()\n public async unload(): Promise<void> {\n if (this.stream != null) {\n this.annotations?.disconnect();\n this.stream.disconnect();\n\n this.frame = undefined;\n this.errorMessage = undefined;\n }\n\n if (this.canvasElement != null) {\n const context = this.canvasElement.getContext('2d');\n if (context != null) {\n context.clearRect(\n 0,\n 0,\n this.canvasElement.width,\n this.canvasElement.height\n );\n }\n }\n }\n\n /**\n * Returns an object that is used to perform operations on the `Scene` that's\n * currently being viewed. These operations include updating items,\n * positioning the camera and performing hit tests.\n */\n @Method()\n public async scene(): Promise<Scene> {\n return this.createScene();\n }\n\n /**\n * Returns `true` indicating that the scene is ready to be interacted with.\n */\n @Method()\n public async isSceneReady(): Promise<boolean> {\n return this.stateMap.streamState.type === 'connected';\n }\n\n @Listen('tap')\n private async handleTapEvent(\n event: CustomEvent<TapEventDetails>\n ): Promise<void> {\n this.tapKeyInteractions\n .filter((i) => i.predicate(event.detail))\n .forEach((i) => i.fn(event.detail));\n }\n\n private emitConnectionChange(status: ConnectionStatus): void {\n if (status.status === 'connected') {\n // NOTE: Uncomment once FSS is deployed.\n // if (status.jwt.length === 0) {\n // throw new MissingJWTError('JWT is empty');\n // }\n }\n this.connectionChange.emit(status);\n }\n\n private handleElementResize(entries: ResizeObserverEntry[]): void {\n const dimensionsHaveChanged =\n entries.length > 0 &&\n this.dimensions != null &&\n !Dimensions.isEqual(entries[0].contentRect, this.viewport);\n\n if (dimensionsHaveChanged) {\n if (this.resizeTimer != null) {\n clearTimeout(this.resizeTimer);\n this.resizeTimer = undefined;\n }\n\n if (!this.isResizing) {\n this.resizeTimer = setTimeout(() => {\n this.isResizing = true;\n this.isResizeUpdate = true;\n this.recalculateComponentDimensions();\n }, this.resizeDebounce);\n }\n }\n }\n\n private registerSlotChangeListeners(): void {\n this.mutationObserver = new MutationObserver((_) => this.injectViewerApi());\n this.mutationObserver.observe(this.hostElement, {\n childList: true,\n subtree: true,\n });\n\n this.styleObserver = new MutationObserver((_) => this.syncViewerStyles());\n this.styleObserver.observe(this.hostElement, {\n attributes: true,\n attributeFilter: ['style'],\n });\n }\n\n private injectViewerApi(): void {\n function queryChildren(el: Element): HTMLElement[] {\n return Array.from(el.querySelectorAll('*'));\n }\n\n const children = queryChildren(this.hostElement);\n\n children\n .filter((node) => node.nodeName.startsWith('VERTEX-'))\n .reduce(\n (elements, element) => [\n ...elements,\n element,\n ...queryChildren(element),\n ],\n [] as Element[]\n )\n .forEach((node) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (node as any).viewer = this.hostElement;\n });\n }\n\n private syncViewerStyles(): void {\n const backgroundColor = this.getBackgroundColor();\n\n this.stream?.update({\n frameBgColor: backgroundColor,\n streamAttributes: this.getStreamAttributes(),\n });\n }\n\n private calculateComponentDimensions(): void {\n const maxPixelCount = 2073600;\n const bounds = this.getBounds();\n if (bounds?.width != null && bounds?.height != null) {\n const measuredViewport = Dimensions.create(bounds.width, bounds.height);\n const trimmedViewport = Dimensions.scaleFit(\n maxPixelCount,\n measuredViewport\n );\n\n this.hostDimensions = measuredViewport;\n this.dimensions =\n trimmedViewport != null\n ? Dimensions.create(trimmedViewport.width, trimmedViewport.height)\n : undefined;\n this.viewport = Viewport.fromDimensions(\n this.getCanvasDimensions() ?? Dimensions.create(0, 0)\n );\n }\n }\n\n private recalculateComponentDimensions(): void {\n if (this.isResizing) {\n this.calculateComponentDimensions();\n this.isResizing = false;\n\n if (this.stream?.getState().type === 'connected') {\n this.updateDimensions(this.dimensions);\n }\n }\n }\n\n private reportPerformance(timings: Timing[]): void {\n if (this.stateMap.streamState.type === 'connected') {\n const payload = {\n timings: timings.map((t) => ({\n receiveToPaintDuration: toProtoDuration(t.duration),\n })),\n };\n this.getStream().recordPerformance(payload, false);\n }\n }\n\n private addStreamListeners(): void {\n this.stateMap.streamListeners = this.getStream().stateChanged.on((s) => {\n this.handleStreamStateChanged(this.stateMap.streamState, s);\n });\n }\n\n private handleStreamStateChanged(\n previous: ViewerStreamState,\n state: ViewerStreamState\n ): void {\n this.stateMap.streamState = state;\n\n if (state.type === 'connecting') {\n this.handleConnecting(previous, state);\n } else if (state.type === 'connected') {\n this.handleConnected(previous, state);\n } else if (state.type === 'connection-failed') {\n this.handleConnectionFailed(previous, state);\n } else if (state.type === 'disconnected') {\n this.handleDisconnected(previous, state);\n }\n }\n\n private handleConnecting(\n previous: ViewerStreamState,\n state: Connecting\n ): void {\n if (previous.type !== 'connecting') {\n this.token = undefined;\n this.errorMessage = undefined;\n this.emitConnectionChange({ status: 'connecting' });\n }\n }\n\n private handleConnected(previous: ViewerStreamState, state: Connected): void {\n this.token = state.token.token;\n\n if (previous.type !== 'connected') {\n this.errorMessage = undefined;\n this.canvasRenderer = measureCanvasRenderer(\n paintTime,\n createCanvasRenderer(),\n this.getResolvedConfig().flags.logFrameRate,\n (timings) => this.reportPerformance(timings)\n );\n this.emitConnectionChange({\n status: 'connected',\n jwt: state.token.token,\n });\n this.deviceIdChange.emit(state.deviceId);\n }\n\n if (this.frame?.getId() !== state.frame.getId()) {\n this.updateFrame(state.frame);\n }\n\n this.updateDimensions(this.dimensions);\n }\n\n private handleConnectionFailed(\n previous: ViewerStreamState,\n state: ConnectionFailed\n ): void {\n if (previous.type !== 'connection-failed') {\n this.token = undefined;\n this.errorMessage = state.message;\n this.emitConnectionChange({\n status: 'connection-failed',\n errorMessage: state.message,\n });\n }\n }\n\n private handleDisconnected(\n previous: ViewerStreamState,\n state: Disconnected\n ): void {\n if (previous.type !== 'disconnected') {\n this.token = undefined;\n this.errorMessage = undefined;\n this.emitConnectionChange({ status: 'disconnected' });\n }\n }\n\n private updateDimensions(dimensions?: Dimensions.Dimensions): void {\n this.stream?.update({ dimensions });\n this.dimensionschange.emit(dimensions);\n }\n\n private async updateFrame(frame: Frame): Promise<void> {\n const canvasDimensions = this.getCanvasDimensions();\n\n if (\n this.canvasElement != null &&\n canvasDimensions != null &&\n this.frame?.getId() !== frame.getId()\n ) {\n const canvas = this.canvasElement.getContext('2d');\n if (canvas != null) {\n const previousFrame = this.frame;\n this.frame = SceneViewSummary.copySummaryIfInvalid(\n frame,\n previousFrame\n );\n\n this.updateInteractionApi(previousFrame);\n\n const data = {\n canvas,\n canvasDimensions,\n dimensions: this.dimensions,\n frame: this.frame,\n viewport: this.viewport,\n beforeDraw: () => {\n this.updateCanvasDimensions(canvasDimensions);\n this.isResizeUpdate = false;\n },\n predicate: () => {\n if (this.isResizeUpdate) {\n return (\n this.dimensions == null ||\n Dimensions.isEqual(\n this.dimensions,\n data.frame.image.imageAttr.frameDimensions\n )\n );\n }\n return true;\n },\n };\n\n this.frameReceived.emit(this.frame);\n\n if (this.frame.scene.hasChanged) {\n this.sceneChanged.emit();\n }\n\n const drawnFrame = await this.canvasRenderer(data);\n\n if (drawnFrame != null) {\n this.updateViewerBackground();\n\n this.dispatchFrameDrawn(drawnFrame);\n }\n }\n }\n }\n\n private updateViewerBackground(): void {\n const backgroundColor = this.getBackgroundColor();\n\n writeDOM(() => {\n this.viewerContainerElement?.style.setProperty(\n 'background',\n backgroundColor != null ? Color.toHexString(backgroundColor) : '#ffffff'\n );\n this.canvasContainerElement?.style.setProperty(\n 'background',\n backgroundColor != null ? Color.toHexString(backgroundColor) : '#ffffff'\n );\n });\n }\n\n private async initializeDefaultInteractionHandlers(): Promise<void> {\n await this.initializeDefaultCameraInteractionHandlers();\n await this.initializeDefaultTapInteractionHandler();\n this.initializeDefaultKeyboardInteractionHandlers();\n\n if (this.rotateAroundTapPoint) {\n this.baseInteractionHandler?.setPrimaryInteractionType('rotate-point');\n }\n }\n\n private clearDefaultCameraInteractionHandlers(): void {\n this.defaultInteractionHandlerDisposables.forEach((disposable) =>\n disposable.dispose()\n );\n this.defaultInteractionHandlerDisposables = [];\n }\n\n private clearDefaultKeyboardInteractions(): void {\n this.defaultTapKeyInteractions.forEach((interaction) => {\n const index = this.tapKeyInteractions.indexOf(interaction);\n if (index !== -1) {\n this.tapKeyInteractions.splice(index, 1);\n }\n });\n this.tapKeyInteractions = [];\n }\n\n private async initializeDefaultCameraInteractionHandlers(): Promise<void> {\n this.clearDefaultCameraInteractionHandlers();\n\n if (this.cameraControls) {\n if (window.PointerEvent != null) {\n this.baseInteractionHandler =\n this.baseInteractionHandler ??\n new PointerInteractionHandler(() => this.getResolvedConfig());\n const baseDisposable = await this.registerInteractionHandler(\n this.baseInteractionHandler\n );\n const multiPointerDisposable = await this.registerInteractionHandler(\n new MultiPointerInteractionHandler()\n );\n\n this.defaultInteractionHandlerDisposables = [\n baseDisposable,\n multiPointerDisposable,\n ];\n } else {\n // fallback to touch events and mouse events as a default\n this.baseInteractionHandler =\n this.baseInteractionHandler ??\n new MouseInteractionHandler(() => this.getResolvedConfig());\n const baseDisposable = await this.registerInteractionHandler(\n this.baseInteractionHandler\n );\n const touchDisposable = await this.registerInteractionHandler(\n new TouchInteractionHandler()\n );\n\n this.defaultInteractionHandlerDisposables = [\n baseDisposable,\n touchDisposable,\n ];\n }\n }\n }\n\n private initializeDefaultKeyboardInteractionHandlers(): void {\n this.clearDefaultKeyboardInteractions();\n\n if (this.keyboardControls && this.stream != null) {\n this.baseInteractionHandler?.setDefaultKeyboardControls(\n this.keyboardControls\n );\n\n const flyToPart = new FlyToPartKeyInteraction(\n this.stream,\n () => this.getResolvedConfig(),\n () => this.getImageScale()\n );\n const flyToPosition = new FlyToPositionKeyInteraction(\n this.stream,\n () => this.getResolvedConfig(),\n () => this.getImageScale(),\n () => this.createScene()\n );\n\n this.registerTapKeyInteraction(flyToPart);\n this.registerTapKeyInteraction(flyToPosition);\n\n this.defaultTapKeyInteractions = [flyToPart, flyToPosition];\n }\n }\n\n private async initializeDefaultTapInteractionHandler(): Promise<void> {\n if (this.tapHandlerDisposable == null) {\n if (window.PointerEvent != null) {\n const tapInteractionHandler = new TapInteractionHandler(\n 'pointerdown',\n 'pointerup',\n 'pointermove',\n () => this.getResolvedConfig()\n );\n\n this.tapHandlerDisposable = await this.registerInteractionHandler(\n tapInteractionHandler\n );\n } else {\n const tapInteractionHandler = new TapInteractionHandler(\n 'mousedown',\n 'mouseup',\n 'mousemove',\n () => this.getResolvedConfig()\n );\n\n this.tapHandlerDisposable = await this.registerInteractionHandler(\n tapInteractionHandler\n );\n }\n }\n }\n\n private initializeInteractionHandler(handler: InteractionHandler): void {\n if (this.stateMap.interactionTarget == null) {\n throw new InteractionHandlerError(\n 'Cannot initialize interaction handler. Interaction target is undefined.'\n );\n }\n if (this.interactionApi == null) {\n throw new InteractionHandlerError(\n 'Cannot initialize interaction handler. Interaction APi is undefined.'\n );\n }\n handler.initialize(this.stateMap.interactionTarget, this.interactionApi);\n }\n\n private createInteractionApi(): InteractionApi {\n if (this.stream == null) {\n throw new ComponentInitializationError(\n 'Cannot create interaction API. Component has not been initialized.'\n );\n }\n\n return this.frame == null || this.frame.scene.camera.isPerspective()\n ? new InteractionApiPerspective(\n this.stream,\n this.stateMap.cursorManager,\n () => this.getResolvedConfig().interactions,\n () => this.createScene(),\n () => this.frame,\n () => this.viewport,\n this.tap,\n this.doubletap,\n this.longpress,\n this.interactionStarted,\n this.interactionFinished,\n this.cameraChanged\n )\n : new InteractionApiOrthographic(\n this.stream,\n this.stateMap.cursorManager,\n () => this.getResolvedConfig().interactions,\n () => this.createScene(),\n () => this.frame,\n () => this.viewport,\n this.tap,\n this.doubletap,\n this.longpress,\n this.interactionStarted,\n this.interactionFinished,\n this.cameraChanged\n );\n }\n\n private handleCursorChanged(): void {\n window.requestAnimationFrame(() => {\n this.cursor = this.stateMap.cursorManager.getActiveCursor();\n });\n }\n\n private async createScene(): Promise<Scene> {\n const state = await this.waitForConnectedState();\n\n const { frame, sceneId, sceneViewId, worldOrientation } = state;\n\n return new Scene(\n this.getStream(),\n frame,\n fromPbFrameOrThrow(worldOrientation),\n () => this.getImageScale(),\n this.viewport,\n sceneId,\n sceneViewId\n );\n }\n\n /**\n * This function is currently not in use, but will required\n * when we want to automatically configure the background color of\n * JPEG images.\n */\n private getBackgroundColor(): Color.Color | undefined {\n if (this.canvasContainerElement != null) {\n const imageBackground = getElementPropertyValue(\n this.hostElement,\n '--image-background'\n );\n const viewerBackground = getElementPropertyValue(\n this.hostElement,\n '--viewer-background'\n );\n const propertyColor = imageBackground ?? viewerBackground;\n\n return propertyColor != null\n ? Color.fromCss(propertyColor)\n : Color.create(255, 255, 255);\n }\n }\n\n private getBounds(): ClientRect | undefined {\n return getElementBoundingClientRect(this.hostElement);\n }\n\n private getCanvasDimensions(): Dimensions.Dimensions | undefined {\n return this.getResolvedConfig().flags.letterboxFrames\n ? this.dimensions\n : this.hostDimensions;\n }\n\n private getImageScale(): Point.Point | undefined {\n const canvasDimensions = this.getCanvasDimensions();\n if (this.dimensions != null && canvasDimensions != null) {\n return Point.create(\n this.dimensions.width / canvasDimensions.width,\n this.dimensions.height / canvasDimensions.height\n );\n }\n }\n\n private getStreamAttributes(): StreamAttributes {\n return {\n depthBuffers: this.getDepthBufferStreamAttributesValue(),\n experimentalRenderingOptions: this.experimentalRenderingOptions,\n featureHighlighting: this.featureHighlighting,\n featureLines: this.featureLines,\n featureMaps: this.featureMaps,\n frames: {\n frameBackgroundColor: this.getBackgroundColor(),\n },\n noDefaultLights: this.noDefaultLights,\n phantom: this.phantom,\n sceneComparison: this.sceneComparison,\n selectionHighlighting: this.selectionHighlighting,\n };\n }\n\n private updateCanvasDimensions(dimensions: Dimensions.Dimensions): void {\n if (this.canvasElement != null) {\n this.canvasElement.width = dimensions.width;\n this.canvasElement.height = dimensions.height;\n }\n }\n\n private updateStreamAttributes(): void {\n this.stream?.update({ streamAttributes: this.getStreamAttributes() });\n }\n\n private updateEnableTemporalRefinement(): void {\n this.stream?.update({\n enableTemporalRefinement: this.enableTemporalRefinement,\n });\n }\n\n private updateInteractionApi(previousFrame?: Frame): void {\n if (this.frame != null) {\n const hasChangedFromPerspective =\n (previousFrame == null || previousFrame.scene.camera.isPerspective()) &&\n this.frame.scene.camera.isOrthographic();\n const hasChangedFromOrthographic =\n (previousFrame == null ||\n previousFrame.scene.camera.isOrthographic()) &&\n this.frame.scene.camera.isPerspective();\n\n if (hasChangedFromPerspective || hasChangedFromOrthographic) {\n this.interactionApi = this.createInteractionApi();\n this.cameraType = this.frame.scene.camera.isPerspective()\n ? 'perspective'\n : 'orthographic';\n this.cameraTypeChanged.emit(this.cameraType);\n\n this.interactionHandlers.forEach((handler) =>\n this.initializeInteractionHandler(handler)\n );\n }\n }\n }\n\n private updateCameraType(): void {\n if (this.frame != null) {\n if (\n this.cameraType === 'orthographic' &&\n this.frame.scene.camera.isPerspective()\n ) {\n this.stream?.replaceCamera({\n camera: FrameCamera.toProtobuf(\n FrameCamera.toOrthographic(\n this.frame.scene.camera,\n this.frame.scene.boundingBox\n )\n ),\n });\n } else if (\n this.cameraType === 'perspective' &&\n this.frame.scene.camera.isOrthographic()\n ) {\n this.stream?.replaceCamera({\n camera: FrameCamera.toProtobuf(\n FrameCamera.toPerspective(this.frame.scene.camera)\n ),\n });\n }\n }\n }\n\n private getDepthBufferStreamAttributesValue(): FrameType {\n const depthBuffer =\n this.depthBuffers ?? (this.rotateAroundTapPoint ? 'final' : undefined);\n return depthBuffer;\n }\n\n private updateResolvedConfig(): void {\n this.resolvedConfig = parseConfig(this.configEnv, this.config);\n }\n\n private getResolvedConfig(): Config {\n return getRequiredProp(\n 'Resolved config is undefined',\n () => this.resolvedConfig\n );\n }\n\n private getStream(): ViewerStream {\n return getRequiredProp('Stream is undefined', () => this.stream);\n }\n\n private getDeviceId(): string | undefined {\n if (this.deviceId == null) {\n try {\n this.deviceId = getStorageEntry(\n StorageKeys.DEVICE_ID,\n (entry) => entry['device-id']\n );\n } catch (e) {\n console.warn('Cannot read device ID. Local storage is not supported.');\n }\n\n if (this.deviceId == null) {\n this.deviceId = UUID.create();\n\n try {\n upsertStorageEntry(StorageKeys.DEVICE_ID, {\n ['device-id']: this.deviceId,\n });\n } catch (e) {\n console.warn(\n 'Cannot write device ID. Local storage is not supported.'\n );\n }\n }\n }\n return this.deviceId;\n }\n\n private async waitForConnectedState(): Promise<Connected> {\n if (this.stateMap.streamState.type !== 'connected') {\n console.debug(\n 'Stream was not in a connected state. Waiting for successful connection.'\n );\n return new Promise<Connected>((resolve, reject) => {\n const disposable = this.getStream().onStateChanged((state) => {\n if (state.type === 'connected') {\n resolve(state);\n }\n });\n\n setTimeout(() => {\n disposable.dispose();\n reject(new Error('Timed out waiting for connected state.'));\n }, DEFAULT_VIEWER_SCENE_WAIT_MS);\n });\n }\n\n return this.stateMap.streamState;\n }\n}\n\nfunction getRequiredProp<T>(errorMsg: string, getter: () => T | undefined): T {\n const value = getter();\n if (value != null) {\n return value;\n } else throw new Error(errorMsg);\n}\n"]}