@3cr/viewer-browser 0.0.196 → 0.0.220

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 (370) hide show
  1. package/.circleci/config.yml +46 -22
  2. package/.prettierrc +6 -0
  3. package/components.d.ts +23 -10
  4. package/dist/Viewer3CR.js +37 -46
  5. package/dist/Viewer3CR.mjs +22640 -20897
  6. package/dist/Viewer3CR.umd.js +37 -46
  7. package/dist/android-chrome-192x192.png +0 -0
  8. package/dist/android-chrome-512x512.png +0 -0
  9. package/dist/apple-touch-icon.png +0 -0
  10. package/dist/browserconfig.xml +9 -0
  11. package/dist/favicon-16x16.png +0 -0
  12. package/dist/favicon-32x32.png +0 -0
  13. package/dist/favicon.ico +0 -0
  14. package/dist/mstile-144x144.png +0 -0
  15. package/dist/mstile-150x150.png +0 -0
  16. package/dist/mstile-310x150.png +0 -0
  17. package/dist/mstile-310x310.png +0 -0
  18. package/dist/mstile-70x70.png +0 -0
  19. package/dist/safari-pinned-tab.svg +50 -0
  20. package/dist/site.webmanifest +19 -0
  21. package/index.html +34 -41
  22. package/package.json +23 -20
  23. package/playground/android-chrome-192x192.png +0 -0
  24. package/playground/android-chrome-512x512.png +0 -0
  25. package/playground/apple-touch-icon.png +0 -0
  26. package/playground/browserconfig.xml +9 -0
  27. package/playground/favicon-16x16.png +0 -0
  28. package/playground/favicon-32x32.png +0 -0
  29. package/playground/favicon.ico +0 -0
  30. package/playground/index.html +26 -29
  31. package/playground/mstile-144x144.png +0 -0
  32. package/playground/mstile-150x150.png +0 -0
  33. package/playground/mstile-310x150.png +0 -0
  34. package/playground/mstile-310x310.png +0 -0
  35. package/playground/mstile-70x70.png +0 -0
  36. package/playground/safari-pinned-tab.svg +50 -0
  37. package/playground/site.webmanifest +19 -0
  38. package/playground/sw.js +15 -1
  39. package/public/android-chrome-192x192.png +0 -0
  40. package/public/android-chrome-512x512.png +0 -0
  41. package/public/apple-touch-icon.png +0 -0
  42. package/public/browserconfig.xml +9 -0
  43. package/public/favicon-16x16.png +0 -0
  44. package/public/favicon-32x32.png +0 -0
  45. package/public/favicon.ico +0 -0
  46. package/public/mstile-144x144.png +0 -0
  47. package/public/mstile-150x150.png +0 -0
  48. package/public/mstile-310x150.png +0 -0
  49. package/public/mstile-310x310.png +0 -0
  50. package/public/mstile-70x70.png +0 -0
  51. package/public/safari-pinned-tab.svg +50 -0
  52. package/public/site.webmanifest +19 -0
  53. package/src/App.vue +35 -45
  54. package/src/__tests__/app.spec.ts +7 -8
  55. package/{__tests__/index.spec.ts → src/__tests__/main.spec.ts} +5 -6
  56. package/src/assets/logos/3dicom/white-mini.svg +20 -0
  57. package/src/assets/logos/3dicom/white.svg +30 -0
  58. package/src/assets/styles.scss +14 -4
  59. package/src/components/demo/__tests__/DemoModal.spec.ts +9 -8
  60. package/src/components/demo/__tests__/DemoPatientModal.spec.ts +11 -10
  61. package/src/components/demo/__tests__/options.spec.ts +1 -1
  62. package/src/components/demo/licence/__tests__/DemoLicenceEnableCloudStorageModal.spec.ts +11 -10
  63. package/src/components/demo/licence/__tests__/DemoLicenceInfoModal.spec.ts +21 -11
  64. package/src/components/demo/licence/__tests__/DemoLicenceSendToPartyModal.spec.ts +10 -10
  65. package/src/components/demo/licence/__tests__/DemoLicenceShareToMobileModal.spec.ts +14 -13
  66. package/src/components/demo/options.ts +54 -59
  67. package/src/components/demo/patient/__tests__/DemoPatientEnableCloudStorageModal.spec.ts +11 -10
  68. package/src/components/demo/patient/__tests__/DemoPatientInfoModal.spec.ts +12 -11
  69. package/src/components/demo/patient/__tests__/DemoPatientSendToPartyModal.spec.ts +10 -10
  70. package/src/components/demo/patient/__tests__/DemoPatientShareToMobileModal.spec.ts +14 -13
  71. package/src/components/modal/ActionRail.vue +7 -11
  72. package/src/components/modal/AskAI.vue +35 -50
  73. package/src/components/modal/CloseViewerModal.vue +22 -57
  74. package/src/components/modal/MftpWebGL3DRModal.vue +152 -570
  75. package/src/components/modal/ViewerActionRail.vue +50 -39
  76. package/src/components/modal/ViewerNavigationDrawer.vue +10 -8
  77. package/src/components/modal/ViewerNavigationDrawerContent.vue +82 -49
  78. package/src/components/modal/ViewerNavigationDrawerFooter.vue +57 -60
  79. package/src/components/modal/ViewerNavigationDrawerHeader.vue +13 -48
  80. package/src/components/modal/ViewerScanView.vue +114 -0
  81. package/src/components/modal/WebGL3DR.vue +84 -0
  82. package/src/components/modal/__tests__/ActionRail.spec.ts +10 -0
  83. package/src/components/modal/__tests__/AskAI.spec.ts +33 -0
  84. package/src/components/modal/__tests__/CloseViewerModal.spec.ts +24 -14
  85. package/src/components/modal/__tests__/MftpWebGL3DRModal.spec.ts +147 -176
  86. package/src/components/modal/__tests__/ViewerActionRail.spec.ts +11 -0
  87. package/src/components/modal/__tests__/ViewerNavigationDrawer.spec.ts +10 -12
  88. package/src/components/modal/__tests__/ViewerNavigationDrawerContent.spec.ts +4 -22
  89. package/src/components/modal/__tests__/ViewerNavigationDrawerFooter.spec.ts +35 -32
  90. package/src/components/modal/__tests__/ViewerNavigationDrawerHeader.spec.ts +11 -9
  91. package/src/components/modal/__tests__/ViewerScanView.spec.ts +60 -0
  92. package/src/components/modal/__tests__/WebGL3DR.spec.ts +57 -0
  93. package/src/components/modal/actions/Flip3dAction.vue +1 -1
  94. package/src/components/modal/actions/FlipHorizontalAction.vue +5 -10
  95. package/src/components/modal/actions/FlipVerticalAction.vue +5 -10
  96. package/src/components/modal/actions/FullscreenAction.vue +6 -11
  97. package/src/components/modal/actions/HideViewAction.vue +38 -0
  98. package/src/components/modal/actions/NavigationCubeAction.vue +7 -14
  99. package/src/components/modal/actions/PanAction.vue +4 -4
  100. package/src/components/modal/actions/ResetViewAction.vue +1 -1
  101. package/src/components/modal/actions/Rotate2dAction.vue +8 -20
  102. package/src/components/modal/actions/Slice3dAction.vue +10 -32
  103. package/src/components/modal/actions/ZoomAction.vue +1 -1
  104. package/src/components/modal/actions/__tests__/Action.spec.ts +8 -9
  105. package/src/components/modal/actions/__tests__/Flip3dAction.spec.ts +6 -8
  106. package/src/components/modal/actions/__tests__/FlipHorizontalAction.spec.ts +6 -7
  107. package/src/components/modal/actions/__tests__/FlipVerticalAction.spec.ts +6 -7
  108. package/src/components/modal/actions/__tests__/FullscreenAction.spec.ts +9 -10
  109. package/src/components/modal/actions/__tests__/NavigationCubeAction.spec.ts +11 -11
  110. package/src/components/modal/actions/__tests__/PanAction.spec.ts +9 -10
  111. package/src/components/modal/actions/__tests__/ResetViewAction.spec.ts +7 -7
  112. package/src/components/modal/actions/__tests__/Rotate2dAction.spec.ts +6 -8
  113. package/src/components/modal/actions/__tests__/Slice3dAction.spec.ts +23 -5
  114. package/src/components/modal/actions/__tests__/ZoomAction.spec.ts +8 -10
  115. package/src/components/modal/buttons/AutoAnnotateBtn.vue +29 -0
  116. package/src/components/modal/buttons/__tests__/AutoAnnotateBtn.spec.ts +28 -0
  117. package/src/components/modal/menus/FileMenu.vue +80 -0
  118. package/src/components/modal/menus/SettingsMenu.vue +111 -0
  119. package/src/components/modal/menus/__tests__/FileMenu.spec.ts +110 -0
  120. package/src/components/modal/menus/__tests__/SettingsMenu.spec.ts +71 -0
  121. package/src/components/shared/DoubleSliderSelector.vue +142 -0
  122. package/src/components/shared/UpdateSnackbar.vue +72 -0
  123. package/src/components/{selectors → shared}/ValueSelector.vue +9 -12
  124. package/src/components/shared/__tests__/DoubleSliderSelector.spec.ts +83 -0
  125. package/src/components/shared/__tests__/LoadingSpinner.spec.ts +9 -0
  126. package/src/components/shared/__tests__/UpdateSnackbar.spec.ts +116 -0
  127. package/src/components/shared/__tests__/ValueSelector.spec.ts +39 -0
  128. package/src/components/shared/__tests__/VerticalSliderSelector.spec.ts +50 -0
  129. package/src/components/views/AnnotationTreeView.vue +234 -0
  130. package/src/components/{modal/ViewerDisplaySettings.vue → views/DisplaySettings.vue} +7 -15
  131. package/src/components/views/MarkupTreeView.vue +199 -0
  132. package/src/components/views/McadObjectTreeView.vue +119 -0
  133. package/src/components/views/__tests__/AnnotationTreeView.spec.ts +62 -0
  134. package/src/components/{modal/__tests__/ViewerDisplaySettings.spec.ts → views/__tests__/DisplaySettings.spec.ts} +24 -20
  135. package/src/components/views/__tests__/MarkupTreeView.spec.ts +41 -0
  136. package/src/components/views/__tests__/McadObjectTreeView.spec.ts +47 -0
  137. package/src/components/views/modals/DataOverlayModal.vue +89 -0
  138. package/src/components/views/modals/DataOverlayModalManager.vue +104 -0
  139. package/src/components/views/modals/__tests__/DataOverlayModal.spec.ts +33 -0
  140. package/src/components/views/modals/__tests__/DataOverlayModalManager.spec.ts +93 -0
  141. package/src/components/views/shared/MaskIcon.vue +44 -0
  142. package/src/components/views/shared/ObjectColor.vue +31 -0
  143. package/src/components/views/shared/ObjectLabel.vue +30 -0
  144. package/src/components/views/shared/Opacity.vue +66 -0
  145. package/src/components/views/shared/VisibilityBtn.vue +25 -0
  146. package/src/components/views/shared/__tests__/MaskIcon.spec.ts +10 -0
  147. package/src/components/views/shared/__tests__/ObjectColor.spec.ts +10 -0
  148. package/src/components/views/shared/__tests__/ObjectLabel.spec.ts +10 -0
  149. package/src/components/views/shared/__tests__/Opacity.spec.ts +24 -0
  150. package/src/components/views/shared/__tests__/VisibilityBtn.spec.ts +11 -0
  151. package/src/components/views/types/annotation-tree-view-item-child-action.ts +6 -0
  152. package/src/components/views/types/annotation-tree-view-item-child.ts +9 -0
  153. package/src/components/views/types/annotation-tree-view-item.ts +13 -0
  154. package/src/components/views/types/markup-tree-view-item-child.ts +6 -0
  155. package/src/components/views/types/markup-tree-view-item.ts +14 -0
  156. package/src/components/views/types/mcad-object-tree-view-item.ts +13 -0
  157. package/src/composables/__tests__/useAnnotations.spec.ts +35 -0
  158. package/src/composables/__tests__/useEventListener.spec.ts +32 -0
  159. package/src/composables/__tests__/useIntroJs.spec.ts +51 -0
  160. package/src/composables/__tests__/useMarkups.spec.ts +39 -0
  161. package/src/composables/__tests__/useMcadObjects.spec.ts +36 -0
  162. package/src/composables/__tests__/useMouse.spec.ts +20 -0
  163. package/src/{components/modal/composables → composables}/__tests__/useNavigationCubeObserver.spec.ts +17 -12
  164. package/src/{dataLayer → composables}/__tests__/useViewer3cr.spec.ts +1 -2
  165. package/src/composables/useAnnotations.ts +37 -0
  166. package/src/composables/useEventListener.ts +25 -0
  167. package/src/composables/useIntroJs.ts +125 -0
  168. package/src/composables/useMarkups.ts +41 -0
  169. package/src/composables/useMcadObjects.ts +32 -0
  170. package/src/composables/useMouse.ts +14 -0
  171. package/src/{components/modal/composables → composables}/useNavigationCubeObserver.ts +35 -25
  172. package/src/composables/useScanMovement.ts +25 -0
  173. package/src/composables/useScanSliders.ts +36 -0
  174. package/src/composables/useVersion3cr.ts +7 -0
  175. package/src/composables/useViewer3cr.ts +7 -0
  176. package/src/composables/useViewerOptions.ts +35 -0
  177. package/src/{dataLayer → functions}/__tests__/clamp.spec.ts +1 -2
  178. package/src/functions/__tests__/layoutOverlayStyle.spec.ts +325 -0
  179. package/src/{helpers/__tests__/model-helper.spec.ts → functions/__tests__/modelHelper.spec.ts} +77 -40
  180. package/src/{notifications → functions}/__tests__/notification.spec.ts +19 -29
  181. package/src/functions/__tests__/parseAction.spec.ts +9 -0
  182. package/src/functions/__tests__/parseCallToAction.spec.ts +11 -0
  183. package/src/functions/__tests__/parseDataOverlay.spec.ts +15 -0
  184. package/src/functions/__tests__/parseDataOverlayData.spec.ts +9 -0
  185. package/src/functions/__tests__/parseDataOverlayEvent.spec.ts +10 -0
  186. package/src/functions/__tests__/parseMcadEvent.spec.ts +10 -0
  187. package/src/functions/layoutOverlayStyle.ts +84 -0
  188. package/src/{helpers → functions}/modelHelper.ts +79 -18
  189. package/src/{notifications → functions}/notification.ts +12 -14
  190. package/src/functions/parseAction.ts +9 -0
  191. package/src/functions/parseCallToAction.ts +9 -0
  192. package/src/functions/parseDataOverlay.ts +10 -0
  193. package/src/functions/parseDataOverlayData.ts +10 -0
  194. package/src/functions/parseDataOverlayEvent.ts +17 -0
  195. package/src/functions/parseMcadEvent.ts +10 -0
  196. package/src/functions/rgbaToCss.ts +13 -0
  197. package/src/main.ts +48 -9
  198. package/src/{dataLayer → models}/__tests__/eventHandlers.spec.ts +2 -3
  199. package/src/models/__tests__/loadViewerOptions.spec.ts +72 -0
  200. package/src/models/__tests__/loadViewerPayload.spec.ts +10 -0
  201. package/src/models/__tests__/scanState.spec.ts +190 -0
  202. package/src/models/callbacks.ts +4 -0
  203. package/src/models/loadViewerOptions.ts +40 -0
  204. package/src/models/loadViewerPayload.ts +24 -0
  205. package/src/{dataLayer → models}/scanState.ts +63 -74
  206. package/src/plugins/__tests__/usePlugins.spec.ts +12 -0
  207. package/src/plugins/__tests__/vuetify.spec.ts +3 -4
  208. package/src/plugins/usePlugins.ts +8 -0
  209. package/src/plugins/vuetify.ts +31 -65
  210. package/src/services/{gpt/__tests__ → __tests__}/gpt.service.spec.ts +2 -2
  211. package/src/services/__tests__/service-worker.service.spec.ts +32 -0
  212. package/src/{dataLayer/__tests__/viewer3cr.spec.ts → services/__tests__/viewer-3cr.service.spec.ts} +97 -36
  213. package/src/services/gpt.service.ts +17 -0
  214. package/src/services/service-worker.service.ts +16 -0
  215. package/src/{dataLayer/viewer3cr.ts → services/viewer-3cr.service.ts} +269 -150
  216. package/src/types/action.ts +13 -0
  217. package/src/types/call-to-action.ts +9 -0
  218. package/src/types/colour.ts +6 -0
  219. package/src/types/data-overlay-angle.ts +16 -0
  220. package/src/types/data-overlay-annotation.ts +18 -0
  221. package/src/types/data-overlay-data.ts +15 -0
  222. package/src/types/data-overlay-info.ts +14 -0
  223. package/src/types/data-overlay-interaction.ts +15 -0
  224. package/src/types/data-overlay-length.ts +16 -0
  225. package/src/types/data-overlay-markup.ts +7 -0
  226. package/src/types/data-overlay-mcad.ts +20 -0
  227. package/src/types/data-overlay-polygon.ts +18 -0
  228. package/src/types/data-overlay.ts +16 -0
  229. package/src/types/gpt-question.ts +4 -0
  230. package/src/types/gpt-response-payload.ts +6 -0
  231. package/src/types/mcad-object-interaction.ts +15 -0
  232. package/src/types/segment-angle.ts +5 -0
  233. package/src/types/vector2.ts +4 -0
  234. package/src/types/vector3.ts +5 -0
  235. package/test/fakers/action-data.faker.ts +11 -0
  236. package/test/fakers/action.faker.ts +19 -0
  237. package/test/fakers/call-to-action.faker.ts +17 -0
  238. package/test/fakers/colour.faker.ts +17 -0
  239. package/test/fakers/data-overlay-angle.faker.ts +37 -0
  240. package/test/fakers/data-overlay-annotation.faker.ts +41 -0
  241. package/test/fakers/data-overlay-data.faker.ts +97 -0
  242. package/test/fakers/data-overlay-info.faker.ts +29 -0
  243. package/test/fakers/data-overlay-interaction.faker.ts +62 -0
  244. package/test/fakers/data-overlay-length.faker.ts +37 -0
  245. package/test/fakers/data-overlay-mcad.faker.ts +40 -0
  246. package/test/fakers/data-overlay-polygon.faker.ts +39 -0
  247. package/test/fakers/gpt-question.faker.ts +11 -0
  248. package/test/fakers/gpt-response.faker.ts +12 -0
  249. package/test/fakers/invert-transform.faker.ts +16 -0
  250. package/test/fakers/mcad-object-interaction.faker.ts +22 -0
  251. package/test/fakers/orientation.faker.ts +17 -0
  252. package/test/fakers/segment-angle.faker.ts +12 -0
  253. package/test/fakers/vector2.faker.ts +12 -0
  254. package/test/fakers/vector3.faker.ts +16 -0
  255. package/test/plugins/findByTestId.ts +25 -0
  256. package/test/plugins/vuetify.ts +16 -0
  257. package/test/setup.ts +16 -5
  258. package/tsconfig.json +4 -15
  259. package/vite.config.mts +20 -46
  260. package/vitest.config.mts +24 -43
  261. package/index.ts +0 -72
  262. package/src/assets/images/dark/3DICOM.png +0 -0
  263. package/src/assets/images/dark/3dicom-logo.svg +0 -1
  264. package/src/assets/images/light/3DICOM.png +0 -0
  265. package/src/assets/images/light/3dicom-logo.svg +0 -1
  266. package/src/assets/logo.png +0 -0
  267. package/src/assets/logo.svg +0 -6
  268. package/src/components/WebGL3DR.vue +0 -102
  269. package/src/components/__tests__/webgl3dr.spec.ts +0 -37
  270. package/src/components/icons/liver.vue +0 -21
  271. package/src/components/loading/__tests__/loading-spinner.spec.ts +0 -11
  272. package/src/components/modal/ViewerAnnotationModal.vue +0 -115
  273. package/src/components/modal/ViewerAnnotations.vue +0 -283
  274. package/src/components/modal/__tests__/ViewerAnnotationModal.spec.ts +0 -79
  275. package/src/components/modal/composables/useEventListener.ts +0 -22
  276. package/src/components/selectors/__tests__/value-selector.spec.ts +0 -53
  277. package/src/components/sliders/DoubleSliderSelector.vue +0 -141
  278. package/src/components/sliders/__tests__/double-slider-selector.spec.ts +0 -104
  279. package/src/components/sliders/__tests__/vertical-slider-selector.spec.ts +0 -61
  280. package/src/dataLayer/__tests__/getIconForPreset.spec.ts +0 -40
  281. package/src/dataLayer/__tests__/patchDataOverlay.spec.ts +0 -88
  282. package/src/dataLayer/__tests__/scanState.spec.ts +0 -93
  283. package/src/dataLayer/getIconForPreset.ts +0 -11
  284. package/src/dataLayer/patchDataOverlay.ts +0 -101
  285. package/src/dataLayer/useViewer3cr.ts +0 -7
  286. package/src/helpers/__tests__/layout-overlay-style.spec.ts +0 -290
  287. package/src/helpers/__tests__/utils.spec.ts +0 -70
  288. package/src/helpers/layoutOverlayStyle.ts +0 -96
  289. package/src/helpers/utils.ts +0 -16
  290. package/src/models/Callbacks.ts +0 -2
  291. package/src/models/LoadViewerOptions.ts +0 -31
  292. package/src/models/LoadViewerPayload.ts +0 -9
  293. package/src/models/__tests__/load-viewer-options.spec.ts +0 -22
  294. package/src/plugins/__tests__/index.spec.ts +0 -19
  295. package/src/plugins/index.ts +0 -17
  296. package/src/services/gpt/gpt.service.ts +0 -27
  297. package/static/3cr-types-browser/index.ts +0 -74
  298. package/static/3cr-types-browser/types/Action.ts +0 -6
  299. package/static/3cr-types-browser/types/AlphaKeys.ts +0 -5
  300. package/static/3cr-types-browser/types/AnchorPoint.ts +0 -12
  301. package/static/3cr-types-browser/types/CallToAction.ts +0 -5
  302. package/static/3cr-types-browser/types/ColourData.ts +0 -7
  303. package/static/3cr-types-browser/types/ColourPresetData.ts +0 -9
  304. package/static/3cr-types-browser/types/CurrentDataOverlayState.ts +0 -6
  305. package/static/3cr-types-browser/types/CurrentScanState.ts +0 -22
  306. package/static/3cr-types-browser/types/DataOverlay.ts +0 -22
  307. package/static/3cr-types-browser/types/DataOverlayActions.ts +0 -14
  308. package/static/3cr-types-browser/types/DataOverlayData.ts +0 -8
  309. package/static/3cr-types-browser/types/DataOverlayEvent.ts +0 -8
  310. package/static/3cr-types-browser/types/DecryptionKey.ts +0 -4
  311. package/static/3cr-types-browser/types/DisplaySettings.ts +0 -10
  312. package/static/3cr-types-browser/types/EmptyPayload.ts +0 -3
  313. package/static/3cr-types-browser/types/EnumPayload.ts +0 -4
  314. package/static/3cr-types-browser/types/FileManagementActions.ts +0 -11
  315. package/static/3cr-types-browser/types/FlipValue.ts +0 -7
  316. package/static/3cr-types-browser/types/FrontEndInterfaces.ts +0 -14
  317. package/static/3cr-types-browser/types/GradientKeys.ts +0 -7
  318. package/static/3cr-types-browser/types/GreyscalePresetData.ts +0 -6
  319. package/static/3cr-types-browser/types/InitialDataOverlayState.ts +0 -6
  320. package/static/3cr-types-browser/types/InitialScanState.ts +0 -19
  321. package/static/3cr-types-browser/types/InteractionType.ts +0 -8
  322. package/static/3cr-types-browser/types/InteractivityActions.ts +0 -6
  323. package/static/3cr-types-browser/types/InteractivityState.ts +0 -4
  324. package/static/3cr-types-browser/types/InvertTransformData.ts +0 -6
  325. package/static/3cr-types-browser/types/LayoutActions.ts +0 -6
  326. package/static/3cr-types-browser/types/LayoutData.ts +0 -7
  327. package/static/3cr-types-browser/types/LoadDataSet.ts +0 -6
  328. package/static/3cr-types-browser/types/LoadSessionState.ts +0 -4
  329. package/static/3cr-types-browser/types/LocalLoadDataset.ts +0 -3
  330. package/static/3cr-types-browser/types/MovementData.ts +0 -7
  331. package/static/3cr-types-browser/types/NavigationCubeActions.ts +0 -8
  332. package/static/3cr-types-browser/types/NavigationCubeData.ts +0 -12
  333. package/static/3cr-types-browser/types/NavigationCubeTransform.ts +0 -9
  334. package/static/3cr-types-browser/types/NotificationPayload.ts +0 -7
  335. package/static/3cr-types-browser/types/NotificationsActions.ts +0 -6
  336. package/static/3cr-types-browser/types/Object.ts +0 -1
  337. package/static/3cr-types-browser/types/ObjectColour.ts +0 -7
  338. package/static/3cr-types-browser/types/ObjectIcon.ts +0 -5
  339. package/static/3cr-types-browser/types/ObjectInvert.ts +0 -7
  340. package/static/3cr-types-browser/types/ObjectSize.ts +0 -7
  341. package/static/3cr-types-browser/types/ObjectSize2D.ts +0 -7
  342. package/static/3cr-types-browser/types/ObjectVisible.ts +0 -5
  343. package/static/3cr-types-browser/types/PositionData.ts +0 -14
  344. package/static/3cr-types-browser/types/PresetsActions.ts +0 -4
  345. package/static/3cr-types-browser/types/RotationValue.ts +0 -7
  346. package/static/3cr-types-browser/types/ScanMovementActions.ts +0 -27
  347. package/static/3cr-types-browser/types/ScanMovementData.ts +0 -3
  348. package/static/3cr-types-browser/types/ScanOrientationActions.ts +0 -6
  349. package/static/3cr-types-browser/types/ScanStateActions.ts +0 -4
  350. package/static/3cr-types-browser/types/ScanView.ts +0 -6
  351. package/static/3cr-types-browser/types/SettingsData.ts +0 -12
  352. package/static/3cr-types-browser/types/SlicerData.ts +0 -9
  353. package/static/3cr-types-browser/types/SliderValue.ts +0 -4
  354. package/static/3cr-types-browser/types/SlidersActions.ts +0 -18
  355. package/static/3cr-types-browser/types/Vector2Data.ts +0 -5
  356. package/static/3cr-types-browser/types/Vector3Data.ts +0 -6
  357. package/static/3cr-types-browser/types/VectorMovementData.ts +0 -8
  358. package/static/3cr-types-browser/types/ViewInteractiveMode.ts +0 -5
  359. package/static/3cr-types-browser/types/ViewOrientation.ts +0 -8
  360. package/static/3cr-types-browser/types/ViewOrientations.ts +0 -10
  361. package/static/3cr-types-browser/types/ViewSelectionActions.ts +0 -9
  362. package/static/3cr-types-browser/types/ViewToggleData.ts +0 -7
  363. package/static/3cr-types-browser/types/VolumeOrientation.ts +0 -7
  364. package/test/helper.ts +0 -44
  365. /package/src/components/{loading → shared}/LoadingSpinner.vue +0 -0
  366. /package/src/components/{sliders → shared}/VerticalSliderSelector.vue +0 -0
  367. /package/{config.ts → src/config.ts} +0 -0
  368. /package/src/{dataLayer → functions}/clamp.ts +0 -0
  369. /package/src/{dataLayer → models}/eventHandlers.ts +0 -0
  370. /package/{static/3cr-types-browser/types/ActionData.ts → src/types/action-data.ts} +0 -0
@@ -1,195 +1,50 @@
1
1
  <template>
2
- <DemoLicenceInfoModal v-model:modal="m_demo" :is-modal-open="value" />
3
- <DemoLicenceShareToMobileModal v-model:modal="m_demoLicenceShareToMobile" />
4
- <DemoLicenceSendToPartyModal v-model:modal="m_demoLicenceSendToParty" />
5
- <DemoLicenceEnableCloudStorageModal v-model:modal="m_demoLicenseEnableCloudStorage" />
6
- <DemoPatientInfoModal v-model:modal="m_demoPatient" :is-modal-open="value" />
7
- <DemoPatientShareToMobileModal v-model:modal="m_demoPatientShareToMobile" />
8
- <DemoPatientSendToPartyModal v-model:modal="m_demoPatientSendToParty" />
9
- <DemoPatientEnableCloudStorageModal v-model:modal="m_demoPatientEnableCloudStorage" />
10
- <CloseViewerModal v-model:modal="m_closeDialog" :options="opts" @close="value = false"/>
11
- <v-dialog
12
- data-vuetify
13
- :model-value="value"
14
- :no-click-animation="true"
15
- fullscreen
16
- persistent
17
- >
18
- <v-card
19
- id="invoice-table-modal"
20
- class="pa-0 ma-0 position-relative motif-background overflow-y-hidden rounded-0"
21
- height="100vh"
22
- >
2
+ <v-dialog :model-value="value" :no-click-animation="true" fullscreen persistent>
3
+ <v-card class="pa-0 ma-0 position-relative motif-background overflow-y-hidden rounded-0" height="100vh">
23
4
  <v-app-bar density="compact">
24
- <v-menu :close-on-content-click="false">
25
- <template #activator="{ props, isActive }">
26
- <v-btn
27
- v-bind="props"
28
- class="mr-2"
29
- :color="isActive ? 'secondary' : 'primary'"
30
- prepend-icon="description"
31
- variant="flat"
32
- >
33
- File
34
- </v-btn>
35
- </template>
36
- <v-list>
37
- <v-list-item
38
- v-if="showOption('OnLoadNewDicomSeries')"
39
- @click="executeOption('OnLoadNewDicomSeries')"
40
- prepend-icon="upload"
41
- >
42
- <v-list-item-title>Load New DICOM Series</v-list-item-title>
43
- </v-list-item>
44
- <v-list-item
45
- v-if="showOption('OnDownloadDicomSeries')"
46
- @click="executeOption('OnDownloadDicomSeries')"
47
- prepend-icon="download"
48
- >
49
- <v-list-item-title>Download DICOM Series</v-list-item-title>
50
- </v-list-item>
51
- <v-list-item
52
- v-if="showOption('OnLoadSavedSession')"
53
- @click="executeOption('OnLoadSavedSession')"
54
- prepend-icon="sync"
55
- >
56
- <v-list-item-title> Load Saved Session </v-list-item-title>
57
- </v-list-item>
58
- <v-list-item
59
- v-if="showOption('OnSendTo3rdParty')"
60
- @click="executeOption('OnSendTo3rdParty')"
61
- prepend-icon="send"
62
- >
63
- <v-list-item-title>Send to 3rd Party</v-list-item-title>
64
- </v-list-item>
65
- <v-list-item
66
- v-if="showOption('OnShareToMobile')"
67
- @click="executeOption('OnShareToMobile')"
68
- prepend-icon="share"
69
- >
70
- <v-list-item-title>Share to Mobile / VR</v-list-item-title>
71
- </v-list-item>
72
-
73
- <v-list-item
74
- @click="
75
- executeOption('OnClosePopup');
76
- alterValue(false);
77
- "
78
- prepend-icon="close"
79
- >
80
- <v-list-item-title>Close Viewer</v-list-item-title>
81
- </v-list-item>
82
- </v-list>
83
- </v-menu>
84
- <v-menu
85
- v-model:model-value="introJsOpenMenu"
86
- :persistent="introJsDisableMenu"
87
- :no-click-animation="introJsDisableMenu"
88
- :close-on-content-click="false"
89
- >
90
- <template #activator="{ props, isActive }">
91
- <v-btn
92
- v-bind="props"
93
- :color="isActive ? 'secondary' : 'primary'"
94
- :disabled="introJsDisableMenu"
95
- prepend-icon="settings"
96
- variant="flat"
97
- >
98
- Settings
99
- </v-btn>
100
- </template>
101
- <v-card id="settings-card" width="350" class="pa-4">
102
- <ValueSelector
103
- v-model:value="scanState.Display.Brightness"
104
- label="Adjust Brightness"
105
- prepend="percent"
106
- />
107
- <ValueSelector
108
- v-model:value="scanState.Display.Contrast"
109
- label="Adjust Contrast"
110
- prepend="percent"
111
- />
112
- <ValueSelector
113
- v-model:value="scanState.Display.Opacity"
114
- label="Adjust Opacity"
115
- prepend="percent"
116
- />
117
- <v-divider class="my-4" />
118
- <ValueSelector
119
- v-model:value="scanState.InteractionSettings.PanSensivitity"
120
- :min="0"
121
- :max="100"
122
- label="Pan Sensitivity"
123
- prepend="percent"
124
- />
125
- <ValueSelector
126
- v-model:value="scanState.InteractionSettings.ZoomSensitivity"
127
- :min="0"
128
- :max="100"
129
- label="Zoom Sensitivity"
130
- prepend="percent"
131
- />
132
- <ValueSelector
133
- v-model:value="scanState.InteractionSettings.RotateSensitivity"
134
- :min="0"
135
- :max="100"
136
- label="Rotate Sensitivity"
137
- prepend="percent"
138
- />
139
- <ValueSelector
140
- v-model:value="
141
- scanState.InteractionSettings.CameraRotateSensitivity
142
- "
143
- :min="0"
144
- :max="100"
145
- label="Camera Rotate Sensitivity"
146
- prepend="percent"
147
- />
148
- <v-divider class="my-4" />
149
- <NavigationCubeAction />
150
- </v-card>
151
- </v-menu>
5
+ <file-menu @close="alterValue(false)" />
6
+ <settings-menu
7
+ v-model="introJsMenu"
8
+ :activator-props="{ disabled: introJsMenuDisabled }"
9
+ :persistent="introJsMenuDisabled"
10
+ :no-click-animation="introJsMenuDisabled"
11
+ />
12
+ <auto-annotate-btn class="mr-2 transparent" />
152
13
  <v-spacer />
153
14
  <div class="font-weight-bold">
154
- <span v-if="isDemo" class="text-capitalize">
155
- 3DICOM {{ demoType }} DEMO&nbsp;|
156
- </span>
157
- <span v-else class="text-capitalize">
158
- 3DICOM Patient Viewer&nbsp;|
159
- </span>
15
+ <span v-if="isDemo" class="text-capitalize">3DICOM {{ demoType }} DEMO |</span>
16
+ <span v-else class="text-capitalize">3DICOM Patient Viewer |</span>
160
17
  Not for Diagnostic Use
161
18
  </div>
162
19
  <v-spacer />
163
20
  <v-btn
164
21
  class="ma-1 mr-0 pa-1"
22
+ data-testid="layout-2x2"
165
23
  height="36"
166
24
  style="min-width: 36px !important"
167
25
  :color="isLayout2x2 ? 'secondary' : 'primary'"
168
26
  @click="viewer3cr.layouts(LayoutActions.lo02)"
169
- ><v-icon>grid_view</v-icon>
170
- <v-tooltip location="bottom" activator="parent">
171
- Change Layout to 2:2
172
- </v-tooltip>
27
+ >
28
+ <v-icon>grid_view</v-icon>
29
+ <v-tooltip location="bottom" activator="parent"> Change Layout to 2:2 </v-tooltip>
173
30
  </v-btn>
174
31
  <v-btn
175
32
  class="ma-1 mr-1 pa-1"
33
+ data-testid="layout-1x3"
176
34
  height="36"
177
35
  style="min-width: 36px !important"
178
36
  :color="isLayout1x3 ? 'secondary' : 'primary'"
179
37
  @click="viewer3cr.layouts(LayoutActions.lo03)"
180
- ><v-icon style="rotate: -90deg">view_comfy</v-icon>
181
- <v-tooltip location="bottom" activator="parent">
182
- Change Layout to 1:3
183
- </v-tooltip></v-btn
184
38
  >
185
- <v-btn variant="flat" color="red" @click="alterValue(false)">
186
- Close Viewer
39
+ <v-icon style="rotate: -90deg">view_comfy</v-icon>
40
+ <v-tooltip location="bottom" activator="parent"> Change Layout to 1:3 </v-tooltip>
187
41
  </v-btn>
42
+ <v-btn variant="flat" color="red" @click="alterValue(false)"> Close Viewer </v-btn>
188
43
  </v-app-bar>
189
- <ViewerNavigationDrawer v-model:drawer="drawer" :options="opts" @update:expanded="expanded = $event" />
44
+ <ViewerNavigationDrawer v-model:drawer="drawer" @update:expanded="expanded = $event" />
190
45
  <v-main>
191
46
  <WebGL3DR
192
- v-show="value && instanceLoaded && !scanLoading"
47
+ v-show="value && !scanLoading"
193
48
  ref="webGl3dr"
194
49
  @instance_loaded="load"
195
50
  @dblclick="viewer3cr.viewSelection(ViewSelectionActions.vs05)"
@@ -197,108 +52,42 @@
197
52
  @mouseleave="onMouseLeave"
198
53
  >
199
54
  <div
200
- v-for="(layout, index) in scanState.Layout.PositionData"
55
+ v-for="layout in scanState.Layout.PositionData"
201
56
  :key="getCurrentView(layout)"
202
- :id="`view-${getCurrentView(layout)}`"
203
- :ref="(el) => (elements[index] = el)"
204
- class="bordered-event-window"
205
57
  :style="generateDivStyleForLayout(layout, webGl3dr!.canvas)"
206
58
  >
207
- <v-hover>
208
- <template #default="{ isHovering, props }">
209
- <v-row v-bind="props" class="flex-nowrap h-100" no-gutters>
210
- <v-col style="min-width: 0">
211
- <v-row class="flex-column h-100" no-gutters>
212
- <v-col class="flex-grow-0">
213
- <div class="d-flex pa-2 pl-3 align-center">
214
- <span style="color: white">{{ getViewName(getCurrentView(layout)) }}</span>
215
- <v-tooltip v-if="isHorizontalFlip(getCurrentView(layout))" location="bottom">
216
- <template #activator="{ props }">
217
- <v-icon
218
- v-bind="props"
219
- icon="swap_horiz"
220
- color="blue-darken-1"
221
- class="ml-2"
222
- />
223
- </template>
224
- <span>This view has been flipped horizontally</span>
225
- </v-tooltip>
226
- <v-tooltip v-if="isVerticalFlip(getCurrentView(layout))" location="bottom">
227
- <template #activator="{ props }">
228
- <v-icon
229
- v-bind="props"
230
- icon="swap_vert"
231
- color="blue-darken-1"
232
- class="ml-2"
233
- />
234
- </template>
235
- <span>This view has been flipped vertically</span>
236
- </v-tooltip>
237
- </div>
238
- </v-col>
239
- <v-spacer />
240
- <v-col class="flex-grow-0">
241
- <Transition>
242
- <div v-show="isHovering || modals[getCurrentView(layout)]">
243
- <ViewerActionRail
244
- :view="getCurrentView(layout)"
245
- :element="elements[index]"
246
- @modal="onActionModal"
247
- />
248
- </div>
249
- </Transition>
250
- </v-col>
251
- </v-row>
252
- </v-col>
253
- <v-col class="flex-grow-0">
254
- <VerticalSliderSelector
255
- class="h-100 my-0 pa-2 pr-3"
256
- v-if="getCurrentView(layout) === ScanView.Transverse"
257
- v-model:value="scanState.Orientations.Transverse.Slice"
258
- v-bind="tMinMax"
259
- />
260
- <VerticalSliderSelector
261
- class="h-100 my-0 pa-2 pr-3"
262
- v-if="getCurrentView(layout) === ScanView.Coronal"
263
- v-model:value="scanState.Orientations.Coronal.Slice"
264
- v-bind="cMinMax"
265
- />
266
- <VerticalSliderSelector
267
- class="h-100 my-0 pa-2 pr-3"
268
- v-if="getCurrentView(layout) === ScanView.Sagittal"
269
- v-model:value="scanState.Orientations.Sagittal.Slice"
270
- v-bind="sMinMax"
271
- />
272
- </v-col>
273
- </v-row>
274
- </template>
275
- </v-hover>
59
+ <ViewerScanView class="w-100 h-100" :view="getCurrentView(layout)" />
276
60
  </div>
277
61
  </WebGL3DR>
278
- <ViewerAnnotationModal />
62
+ <data-overlay-modal-manager />
279
63
  </v-main>
280
- <LoadingSpinner v-if="!instanceLoaded" />
281
64
  <LoadingSpinner v-if="scanLoading" text="Rendering your scan in 3D" />
282
65
  </v-card>
283
66
  </v-dialog>
67
+ <DemoLicenceInfoModal v-model:modal="m_demo" :is-modal-open="value" />
68
+ <DemoLicenceShareToMobileModal v-model:modal="m_demoLicenceShareToMobile" />
69
+ <DemoLicenceSendToPartyModal v-model:modal="m_demoLicenceSendToParty" />
70
+ <DemoLicenceEnableCloudStorageModal v-model:modal="m_demoLicenseEnableCloudStorage" />
71
+ <DemoPatientInfoModal v-model:modal="m_demoPatient" :is-modal-open="value" />
72
+ <DemoPatientShareToMobileModal v-model:modal="m_demoPatientShareToMobile" />
73
+ <DemoPatientSendToPartyModal v-model:modal="m_demoPatientSendToParty" />
74
+ <DemoPatientEnableCloudStorageModal v-model:modal="m_demoPatientEnableCloudStorage" />
75
+ <CloseViewerModal v-model:modal="m_closeDialog" @close="value = false" />
284
76
  </template>
285
77
 
286
- <!-- /* c8 ignore stop */ -->
287
78
  <script setup lang="ts">
288
- import { generateDivStyleForLayout } from "@/helpers/layoutOverlayStyle";
79
+ import { generateDivStyleForLayout } from '@/functions/layoutOverlayStyle';
289
80
  import {
290
- DataOverlayActions,
81
+ DataOverlaysActions,
291
82
  FileManagementActions,
292
83
  FrontEndInterfaces,
293
84
  LayoutActions,
85
+ McadActions,
294
86
  NotificationsActions,
295
- ScanMovementActions,
296
87
  ScanStateActions,
297
- ScanView,
298
- SlidersActions,
299
- ViewSelectionActions,
300
- } from "@3cr/types-ts";
301
- import {ComponentInstance, computed, nextTick, onBeforeUnmount, onMounted, ref, unref, watch, WatchSource} from "vue";
88
+ ViewSelectionActions
89
+ } from '@3cr/types-ts';
90
+ import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
302
91
  import {
303
92
  checkIsDemo,
304
93
  demoOptions,
@@ -311,92 +100,85 @@ import {
311
100
  m_demoPatient,
312
101
  m_demoPatientEnableCloudStorage,
313
102
  m_demoPatientSendToParty,
314
- m_demoPatientShareToMobile,
315
- } from "@/components/demo/options";
316
- import { handleNotification } from "@/notifications/notification";
317
- import { LoadViewerPayload } from "@/models/LoadViewerPayload";
318
- import {
319
- defaultLoadViewerOptions,
320
- LoadViewerOptions,
321
- } from "@/models/LoadViewerOptions";
103
+ m_demoPatientShareToMobile
104
+ } from '@/components/demo/options';
105
+ import { handleNotification } from '@/functions/notification';
106
+ import { defaultLoadViewerPayload, LoadViewerPayload } from '@/models/loadViewerPayload';
107
+ import { defaultLoadViewerOptions, LoadViewerOptions } from '@/models/loadViewerOptions';
322
108
  import {
323
- cMinMax,
324
109
  getCurrentView,
325
- getViewName,
326
- initialScanState,
327
- isFullscreen,
328
- isHorizontalFlip,
329
110
  isLayout1x3,
330
111
  isLayout2x2,
331
- isVerticalFlip,
332
- previousLayout,
333
112
  scanState,
334
- setActiveAnnotation,
113
+ setDataOverlayEvent,
335
114
  setDataOverlayState,
336
115
  setInitialDataOverlayState,
116
+ setInitialMcadState,
337
117
  setInitialScanStateFromPayload,
118
+ setMcadEvent,
119
+ setMcadState,
338
120
  setScanStateFromPayload,
339
- sMinMax,
340
- thresholdSlider,
341
- tMinMax,
342
- transactionStarted,
343
- windowSlider,
344
- } from "@/dataLayer/scanState";
345
- import introJs from "intro.js";
346
- import type { IntroJs } from "intro.js/src/intro";
347
- import "intro.js/introjs.css";
348
- import WebGL3DR from "@/components/WebGL3DR.vue";
349
- import { useViewer3cr } from "@/dataLayer/useViewer3cr";
350
- import { useNavigationCubeObserver } from "@/components/modal/composables/useNavigationCubeObserver";
351
-
352
- export interface Props {
121
+ transactionStarted
122
+ } from '@/models/scanState';
123
+ import { useViewer3cr } from '@/composables/useViewer3cr';
124
+ import { useNavigationCubeObserver } from '@/composables/useNavigationCubeObserver';
125
+ import { mockDemoViewerStlDecimator, useViewerOptions } from '@/composables/useViewerOptions';
126
+ import { useScanMovement } from '@/composables/useScanMovement';
127
+ import { useScanSliders } from '@/composables/useScanSliders';
128
+ import { useIntroJs } from '@/composables/useIntroJs';
129
+ import WebGL3DR from '@/components/modal/WebGL3DR.vue';
130
+
131
+ interface Props {
353
132
  payload?: LoadViewerPayload;
354
133
  options?: LoadViewerOptions;
355
134
  }
356
135
 
357
- const emit = defineEmits<{
358
- instanceLoaded: [void];
359
- }>();
360
-
361
136
  const props = withDefaults(defineProps<Props>(), {
362
- payload: () => ({
363
- Url: "https://webgl-3dr.singular.health/test_scans/8bdddee1-e581-485d-827d-6aa12eef2fc8/Head+Axial+Axial.3vxl",
364
- DecryptionKey: {
365
- Iv: "x856FgjpYDsRhIa3BFj5cg==",
366
- Key: "OWjSMiL/ewUV1V6fGybhKcTyiysTPsIMp2DjdVoOUGI=",
367
- },
368
- }),
369
- options: () => defaultLoadViewerOptions,
137
+ payload: () => defaultLoadViewerPayload,
138
+ options: () => defaultLoadViewerOptions
370
139
  });
371
140
 
141
+ useScanMovement();
142
+ useScanSliders();
372
143
  const viewer3cr = useViewer3cr();
144
+ const opts = useViewerOptions();
145
+ const { intro } = useIntroJs();
373
146
  const webGl3dr = ref<typeof WebGL3DR>();
374
147
  const observer = ref<ResizeObserver>();
375
148
  const value = ref<boolean>(false);
376
149
  const drawer = ref<boolean>(false);
377
150
  const expanded = ref<number | undefined>();
378
151
  const scanLoading = ref<boolean>(true);
379
- const instanceLoaded = ref<boolean>(true);
380
- const elements = ref<ComponentInstance<any>[]>([]);
381
152
  const m_closeDialog = ref<boolean>(false);
382
- const introJsOpenMenu = ref<boolean>(false);
383
- const introJsDisableMenu = ref<boolean>(false);
384
- const modals = ref<Record<ScanView, boolean>>({
385
- [ScanView.Volume]: false,
386
- [ScanView.Sagittal]: false,
387
- [ScanView.Coronal]: false,
388
- [ScanView.Transverse]: false,
389
- });
390
-
391
- const tier = computed(() => {
392
- const value = demoType.value;
393
- return value.charAt(0).toUpperCase() + value.substring(1);
153
+ const introJsMenu = ref<boolean>(false);
154
+ const introJsMenuDisabled = ref<boolean>(false);
155
+
156
+ watch(
157
+ () => props.options,
158
+ (value: LoadViewerOptions) => {
159
+ opts.value = isDemo.value ? demoOptions.value : value;
160
+ },
161
+ { immediate: true }
162
+ );
163
+
164
+ watch(isDemo, (demo: boolean) => {
165
+ opts.value = demo ? demoOptions.value : props.options;
394
166
  });
395
167
 
396
- const opts = computed(() => {
397
- return unref(isDemo) ? demoOptions.value : props.options;
398
- });
168
+ /* istanbul ignore next -- @preserve */
169
+ watch(
170
+ () => intro.value.getCurrentStep(),
171
+ (step) => {
172
+ const lock = step === 4;
173
+ introJsMenu.value = lock;
174
+ introJsMenuDisabled.value = lock;
175
+ setTimeout(() => {
176
+ intro.value.refresh(true);
177
+ }, 400);
178
+ }
179
+ );
399
180
 
181
+ /* istanbul ignore next -- @preserve */
400
182
  onMounted(() => {
401
183
  viewer3cr.addInterfaceHandler(FrontEndInterfaces.notifications, async (message: string, action: string) => {
402
184
  await handleNotification(action as NotificationsActions, message);
@@ -404,17 +186,32 @@ onMounted(() => {
404
186
 
405
187
  viewer3cr.addActionHandler(FileManagementActions.fm02, async (message: string) => {
406
188
  setInitialScanStateFromPayload(message);
189
+ if (opts.value.OnScanLoaded) {
190
+ await opts.value.OnScanLoaded(scanState.value);
191
+ }
192
+
407
193
  await nextTick();
408
194
  transactionStarted.value = false;
409
195
  scanLoading.value = false;
410
196
  drawer.value = true;
411
- if (unref(isDemo)) {
412
- await viewer3cr.loadDataOverlay("https://webgl-3dr.singular.health/test_scans/sample_annotations.json");
413
- }
414
197
  observer.value = useNavigationCubeObserver(webGl3dr.value!.canvas);
415
- await startIntro();
198
+ await loadDemoData();
199
+ await intro.value.start();
416
200
  });
417
201
 
202
+ viewer3cr.addActionHandler(
203
+ FileManagementActions.fm09,
204
+ async (_1: string, returnChannel: string, returnTo: string) => {
205
+ if (opts.value.OnResolveUrls) {
206
+ const keys = JSON.parse(returnChannel) as string[];
207
+ const urls = await opts.value.OnResolveUrls(keys);
208
+ await viewer3cr.loadMcadObjects(undefined, urls, returnTo);
209
+ } else {
210
+ throw new Error('OnResolveUrls has not been defined in LoadViewerOptions');
211
+ }
212
+ }
213
+ );
214
+
418
215
  viewer3cr.addActionHandler(ScanStateActions.ss01, async (message: string) => {
419
216
  await setScanStateFromPayload(message);
420
217
  });
@@ -423,16 +220,36 @@ onMounted(() => {
423
220
  setDataOverlayState(message);
424
221
  });
425
222
 
426
- viewer3cr.addActionHandler(DataOverlayActions.do01, (message: string) => {
223
+ viewer3cr.addActionHandler(ScanStateActions.ss03, (message: string) => {
224
+ setMcadState(message);
225
+ });
226
+
227
+ viewer3cr.addActionHandler(DataOverlaysActions.do01, (message: string) => {
427
228
  setInitialDataOverlayState(message);
428
229
  });
429
230
 
430
- viewer3cr.addActionHandler(DataOverlayActions.do02, (message: string) => {
431
- setActiveAnnotation(message);
231
+ viewer3cr.addActionHandler(DataOverlaysActions.do02, (message: string) => {
232
+ setDataOverlayEvent(message);
233
+ });
234
+
235
+ viewer3cr.addActionHandler(DataOverlaysActions.do07, (message: string) => {
236
+ setDataOverlayEvent(message);
237
+ });
238
+
239
+ viewer3cr.addActionHandler('mu_17', (message: string) => {
240
+ setDataOverlayEvent(message);
241
+ });
242
+
243
+ viewer3cr.addActionHandler('mu_18', (message: string) => {
244
+ setDataOverlayEvent(message);
245
+ });
246
+
247
+ viewer3cr.addActionHandler(McadActions.mc01, (message: string) => {
248
+ setInitialMcadState(message);
432
249
  });
433
250
 
434
- viewer3cr.addActionHandler(DataOverlayActions.do07, (message: string) => {
435
- setActiveAnnotation(message);
251
+ viewer3cr.addActionHandler(McadActions.mc02, (message: string) => {
252
+ setMcadEvent(message);
436
253
  });
437
254
  });
438
255
 
@@ -442,78 +259,6 @@ onBeforeUnmount(() => {
442
259
  }
443
260
  });
444
261
 
445
- function showOption(key: keyof LoadViewerOptions): boolean {
446
- return opts.value[key] !== undefined;
447
- }
448
-
449
- async function executeOption(key: keyof LoadViewerOptions) {
450
- const functionToExecute = opts.value[key];
451
- if (functionToExecute !== undefined) {
452
- await functionToExecute();
453
- }
454
- }
455
-
456
- function onActionModal(value: boolean, view: ScanView): void {
457
- modals.value[view] = value;
458
- }
459
-
460
- type WatchSlidersType = { [key in SlidersActions]: WatchSource<number> };
461
- const watchSliders: WatchSlidersType = {
462
- [SlidersActions.sl01]: () => scanState.value.Display.Brightness,
463
- [SlidersActions.sl02]: () => scanState.value.Display.Contrast,
464
- [SlidersActions.sl03]: () => scanState.value.Display.Opacity,
465
- [SlidersActions.sl04]: () => scanState.value.Display.WindowLower,
466
- [SlidersActions.sl05]: () => scanState.value.Display.WindowUpper,
467
- [SlidersActions.sl06]: () => scanState.value.Display.ThresholdLower,
468
- [SlidersActions.sl07]: () => scanState.value.Display.ThresholdUpper,
469
- [SlidersActions.sl08]: () => scanState.value.Slice.TransverseLower,
470
- [SlidersActions.sl09]: () => scanState.value.Orientations.Transverse.Slice,
471
- [SlidersActions.sl10]: () => scanState.value.Slice.TransverseUpper,
472
- [SlidersActions.sl11]: () => scanState.value.Slice.SagittalLower,
473
- [SlidersActions.sl12]: () => scanState.value.Orientations.Sagittal.Slice,
474
- [SlidersActions.sl13]: () => scanState.value.Slice.SagittalUpper,
475
- [SlidersActions.sl14]: () => scanState.value.Slice.CoronalLower,
476
- [SlidersActions.sl15]: () => scanState.value.Orientations.Coronal.Slice,
477
- [SlidersActions.sl16]: () => scanState.value.Slice.CoronalUpper,
478
- };
479
-
480
- for (const slider of Object.keys(watchSliders)) {
481
- watch(
482
- watchSliders[slider as keyof WatchSlidersType],
483
- async (value: number) => {
484
- await viewer3cr.sliderHandler(slider as SlidersActions, value);
485
- }
486
- );
487
- }
488
-
489
- type WatchScanMovementType = {
490
- [key in ScanMovementActions]: WatchSource<number>;
491
- };
492
-
493
- //@ts-ignore
494
- const watchScanMovement: WatchScanMovementType = {
495
- [ScanMovementActions.sm05]: () =>
496
- scanState.value.InteractionSettings.PanSensivitity,
497
- [ScanMovementActions.sm08]: () =>
498
- scanState.value.InteractionSettings.ZoomSensitivity,
499
- [ScanMovementActions.sm10]: () =>
500
- scanState.value.InteractionSettings.RotateSensitivity,
501
- [ScanMovementActions.sm12]: () =>
502
- scanState.value.InteractionSettings.CameraRotateSensitivity,
503
- };
504
-
505
- for (const scanMovement of Object.keys(watchScanMovement)) {
506
- watch(
507
- watchScanMovement[scanMovement as keyof typeof watchScanMovement],
508
- async (value: number) => {
509
- await viewer3cr.scanMovementHandler(
510
- scanMovement as ScanMovementActions,
511
- value
512
- );
513
- }
514
- );
515
- }
516
-
517
262
  function alterValue(val: boolean) {
518
263
  if (!val) {
519
264
  m_closeDialog.value = true;
@@ -524,20 +269,20 @@ function alterValue(val: boolean) {
524
269
  value.value = val;
525
270
  }
526
271
 
272
+ /* istanbul ignore next -- @preserve */
527
273
  async function loadSession(url: string): Promise<void> {
528
- if (url.includes('3crds')) {
529
- await viewer3cr.loadDataOverlay(url);
274
+ if (url.includes('3crs')) {
275
+ await viewer3cr.loadScanSession({ Url: url });
276
+ } else if (url.includes('3crds')) {
277
+ await viewer3cr.setDataOverlaySession({ Url: url });
530
278
  } else if (url.includes('3crms')) {
531
- await viewer3cr.loadMcad(url);
532
- } else if (url.includes('3crs')) {
533
- await viewer3cr.loadScanSession(url);
279
+ await viewer3cr.loadMcadObjects({ Url: url });
534
280
  } else {
535
281
  throw new Error('Invalid URL type');
536
282
  }
537
283
  }
538
284
 
539
285
  async function load(): Promise<void> {
540
- instanceLoaded.value = true;
541
286
  scanLoading.value = true;
542
287
  await viewer3cr.loadScan(props.payload);
543
288
  }
@@ -550,192 +295,29 @@ async function onMouseLeave(): Promise<void> {
550
295
  await viewer3cr.hoverOverCanvas(false);
551
296
  }
552
297
 
553
- async function startIntro(): Promise<void> {
554
- let intro: IntroJs | null = null;
555
-
556
- const sleep = (delay: number) =>
557
- new Promise((resolve) => setTimeout(resolve, delay));
558
-
559
- const refreshHandle = watch(scanState, () => {
560
- intro?.refresh(true);
561
- });
562
-
563
- const expandHandle = watch(expanded, async () => {
564
- // For some reason introjs refresh by itself doesn't work here
565
- if (intro && intro.currentStep() === 1) {
566
- await sleep(400);
567
- const skinToBone = document.getElementById('skin-to-bone');
568
- const floatingElement = document.querySelector('.introjsFloatingElement') as HTMLElement | null;
569
- intro._introItems[1].element = skinToBone ?? floatingElement;
570
- intro.refresh(true);
571
- }
572
- });
573
-
574
- const blurActiveElement = () => {
575
- (document.activeElement as HTMLElement).blur();
576
- };
577
-
578
- intro = await introJs()
579
- .setOptions({
580
- exitOnOverlayClick: false,
581
- keyboardNavigation: false,
582
- dontShowAgain: true,
583
- steps: [
584
- {
585
- title: "Take the Viewer Tour",
586
- intro:
587
- `Welcome to the ${tier.value} Online DICOM Viewer.` +
588
- "<br/><br/>Take the short interative tour to better visualize your medical images in 2D and 3D.",
589
- position: "floating",
590
- },
591
- {
592
- title: "Density Slider",
593
- intro:
594
- "Move the <em>lower density slider</em> to the right to hide softer tissue like skin and view internal organs." +
595
- "<br/><br/>For more precise control, change the numbers in the boxes above or use the <em>Fine Adjustment</em> slider below.",
596
- element: "#skin-to-bone",
597
- position: "right",
598
- },
599
- {
600
- title: "3D Viewing Controls",
601
- intro:
602
- "With your cursor placed in the 3D view, <b>scroll to zoom</b> & <b>click and drag to rotate</b>." +
603
- "<br/><br/>You can also view the 3D view in full screen, reset the view, and cut into the 3D model from each side using the <em>3D slicing tool</em>.",
604
- element: `#view-${ScanView.Volume}`,
605
- },
606
- {
607
- title: "2D Viewing Controls",
608
- intro:
609
- "With your mouse in the 2D views, <b>scroll to navigate through the 2D images</b>, and use <b>Shift + Arrows to Pan and Zoom</b>." +
610
- "<br/><br/>Use the icons to <em>Fullscreen</em>, <em>Reset</em>, <em>Rotate</em>, and <em>Flip</em> each individual 2D view.",
611
- element: `#view-${ScanView.Sagittal}`,
612
- },
613
- {
614
- title: "Global settings",
615
- intro:
616
- "Accurately change the <b>brightness</b>, <b>contrast</b>, and <b>opacity</b> to enhance the appearance of your medical images." +
617
- "<br/><br/>Adjust the sensitivity of mouse and keyboard inputs to suit your preferences.",
618
- element: "#settings-card",
619
- position: "right",
620
- },
621
- {
622
- title: "Stay Tuned for Updates",
623
- intro:
624
- '<img src="https://c.tenor.com/S4Sz_yvlLn4AAAAC/cats-cat.gif" alt="cat" width="260" height="260">' +
625
- "<br/>Us working hard on new features",
626
- position: "floating",
627
- },
628
- ],
629
- })
630
- .onbeforechange(function (
631
- el: HTMLElement,
632
- step: number,
633
- direction: "forward" | "backward"
634
- ) {
635
- // Focus on volume view if moving to step 2
636
- modals.value[ScanView.Volume] = step === 2;
637
-
638
- // Focus on sagittal view if moving to step 3
639
- modals.value[ScanView.Sagittal] = step === 3;
640
-
641
- // If the user has enabled full-screen, turn it off for steps 2 and 3
642
- if (isFullscreen.value && (step === 2 || step === 3)) {
643
- viewer3cr
644
- .layouts(previousLayout.value)
645
- .then(() => nextTick())
646
- .then(() => this.refresh(true))
647
- .then(() => direction === "forward" ? this.nextStep() : this.previousStep());
648
- return false;
649
- }
650
-
651
- // Wait for menu animation before focusing if moving to step 4
652
- if (!introJsOpenMenu.value && step === 4) {
653
- introJsOpenMenu.value = true;
654
- introJsDisableMenu.value = true;
655
- sleep(400)
656
- .then(() => this.refresh(true))
657
- .then(() => direction === "forward" ? this.nextStep() : this.previousStep());
658
- return false;
659
- } else if (introJsOpenMenu.value && step !== 4) {
660
- introJsOpenMenu.value = false;
661
- introJsDisableMenu.value = false;
662
- }
663
-
664
- // Only show Don't Show Again on last step
665
- const introjsDontShowAgain = document.querySelector(".introjs-dontShowAgain") as HTMLElement | null;
666
- if (introjsDontShowAgain) {
667
- const lastStep = this._options.steps.length - 1;
668
- introjsDontShowAgain.style.display = step !== lastStep ? "none" : "block";
669
- }
670
-
671
- return true;
672
- })
673
- .onchange(() => {
674
- setTimeout(() => blurActiveElement(), 500);
675
- })
676
- .onexit(() => {
677
- introJsOpenMenu.value = false;
678
- introJsDisableMenu.value = false;
679
- setTimeout(() => blurActiveElement(), 500);
680
- refreshHandle();
681
- expandHandle();
682
- })
683
- .start();
298
+ /* istanbul ignore next -- @preserve */
299
+ async function loadDemoData(): Promise<void> {
300
+ if (isDemo.value) {
301
+ const BASE_STATE_URL = 'https://webgl-3dr.singular.health/demo';
302
+ mockDemoViewerStlDecimator();
303
+ await viewer3cr.addDataOverlaySession({ Url: `${BASE_STATE_URL}/state/data_overlay.3crds` });
304
+ await viewer3cr.addDataOverlaySession({ Url: `${BASE_STATE_URL}/state/markups.3crds` });
305
+ // await viewer3cr.loadMcadObjects({ Url: `${BASE_STATE_URL}/state/mcad.3crms` });
306
+ }
684
307
  }
685
308
 
686
309
  defineExpose({
687
310
  alterValue,
688
311
  loadSession,
689
312
  load,
690
- startIntro,
691
- thresholdSlider,
692
- windowSlider,
693
313
  m_closeDialog,
694
- scanState,
695
- initialScanState,
696
- value,
697
- transactionStarted,
314
+ value
698
315
  });
699
316
  </script>
700
317
 
701
318
  <style>
702
- #view-0 {
703
- cursor: grab;
704
- }
705
-
706
- .bordered-event-window {
707
- position: absolute;
708
- border: 1px rgba(128, 128, 128, 0.56) solid;
709
- transition: border 0.5s;
710
- }
711
-
712
- .bordered-event-window:hover {
713
- border: 1px dashed rgb(0, 152, 253);
714
- }
715
-
716
319
  .motif-background {
717
320
  background: url("data:image/svg+xml,%3Csvg width='992' height='560' viewBox='15 7 992 560' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='15' y='1' width='992' height='567' fill='url(%23paint0_linear_504_579)'/%3E%3Cg filter='url(%23filter0_i_504_579)'%3E%3Cpath d='M567.029 291.5C574.21 421.339 748.15 561 825.931 561H12L12.0001 0C153.713 0 580.363 0 580.363 0C684.258 142 560.918 181 567.029 291.5Z' fill='%231B2E43' fill-opacity='0.9'/%3E%3C/g%3E%3Cg filter='url(%23filter1_i_504_579)'%3E%3Cpath d='M435.911 260.5C462.579 433.5 652.034 561 729.815 561H12L12.0001 0C233.678 0 409.954 92.1126 435.911 260.5Z' fill='%231B2E43' fill-opacity='0.9'/%3E%3C/g%3E%3Cg filter='url(%23filter2_i_504_579)'%3E%3Ccircle cx='46' cy='521' r='93' fill='%231B2E43' fill-opacity='0.3'/%3E%3C/g%3E%3Cdefs%3E%3Cfilter id='filter0_i_504_579' x='12' y='0' width='858.931' height='606' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='BackgroundImageFix' result='shape'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' result='hardAlpha'/%3E%3CfeOffset dx='45' dy='45'/%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3CfeComposite in2='hardAlpha' operator='arithmetic' k2='-1' k3='1'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.653125 0 0 0 0 0.761642 0 0 0 0 0.916667 0 0 0 0.15 0'/%3E%3CfeBlend mode='normal' in2='shape' result='effect1_innerShadow_504_579'/%3E%3C/filter%3E%3Cfilter id='filter1_i_504_579' x='12' y='0' width='762.815' height='606' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='BackgroundImageFix' result='shape'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' result='hardAlpha'/%3E%3CfeOffset dx='45' dy='45'/%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3CfeComposite in2='hardAlpha' operator='arithmetic' k2='-1' k3='1'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.653125 0 0 0 0 0.761642 0 0 0 0 0.916667 0 0 0 0.25 0'/%3E%3CfeBlend mode='normal' in2='shape' result='effect1_innerShadow_504_579'/%3E%3C/filter%3E%3Cfilter id='filter2_i_504_579' x='-47' y='428' width='231' height='231' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='BackgroundImageFix' result='shape'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' result='hardAlpha'/%3E%3CfeOffset dx='45' dy='45'/%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3CfeComposite in2='hardAlpha' operator='arithmetic' k2='-1' k3='1'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.653125 0 0 0 0 0.761642 0 0 0 0 0.916667 0 0 0 0.15 0'/%3E%3CfeBlend mode='normal' in2='shape' result='effect1_innerShadow_504_579'/%3E%3C/filter%3E%3ClinearGradient id='paint0_linear_504_579' x1='1251.04' y1='696.83' x2='21.486' y2='-10.2783' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%230E141D'/%3E%3Cstop offset='1' stop-color='%2323405E'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E%0A") !important;
718
321
  background-size: cover !important;
719
322
  }
720
-
721
- .introjs-tooltipReferenceLayer {
722
- z-index: 2401;
723
- }
724
-
725
- .introjs-overlay, .introjs-helperLayer {
726
- pointer-events: none;
727
- z-index: 2401;
728
- }
729
-
730
- .introjs-dontShowAgain {
731
- display: none;
732
- }
733
-
734
- .v-enter-active, .v-leave-active {
735
- transition: opacity 0.5s ease;
736
- }
737
-
738
- .v-enter-from, .v-leave-to {
739
- opacity: 0;
740
- }
741
323
  </style>