@ohif/app 3.0.0 → 3.5.0

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 (125) hide show
  1. package/dist/151.bundle.07bac9172580a60fae7a.js +2579 -0
  2. package/dist/192.bundle.62be5f0ef9705a485071.js +894 -0
  3. package/dist/199.bundle.2286f24cf0a068e7f50c.js +480 -0
  4. package/dist/205.bundle.39e6c847d618ad2b1b7a.js +62 -0
  5. package/dist/208.bundle.23748a85dfdc79c05d3a.js +864 -0
  6. package/dist/270.bundle.abbdb5348274bae3e8bc.js +23906 -0
  7. package/dist/283.bundle.33f99a75a5e2d9333da2.js +2939 -0
  8. package/dist/295.bundle.5105ce962be15c92484d.js +48 -0
  9. package/dist/331.bundle.7ac7b142d249d14fd99e.js +73034 -0
  10. package/dist/351.bundle.c5d7279ef42e30f61e08.js +1471 -0
  11. package/dist/351.css +3 -0
  12. package/dist/36785fbd89b0e17f6099.wasm +0 -0
  13. package/dist/381.bundle.0905e683605fcbc0895f.js +1009 -0
  14. package/dist/404.bundle.0f7a500421f246153d89.js +706 -0
  15. package/dist/50.bundle.4cb103cd20f5ffccf927.js +324 -0
  16. package/dist/5004fdc02f329ce53b69.wasm +0 -0
  17. package/dist/531.bundle.1bc152c87c7e2e987d2b.js +5935 -0
  18. package/dist/55.bundle.a5a215e13a8511f7aee7.js +685 -0
  19. package/dist/55.css +3 -0
  20. package/dist/569.bundle.d147c0aa0604f8ea2094.js +514 -0
  21. package/dist/581.bundle.646c89c5c3e3ee096363.js +508 -0
  22. package/dist/606.bundle.5d876f5f3dd8287f0a28.js +4939 -0
  23. package/dist/610.min.worker.js +2 -0
  24. package/dist/610.min.worker.js.map +1 -0
  25. package/dist/616.bundle.bec4736d8c9513e62856.js +686 -0
  26. package/dist/62ab5d58a2bea7b5a1dc.wasm +0 -0
  27. package/dist/642.bundle.030d908e22c8ff5611f3.js +169 -0
  28. package/dist/65916ef3def695744bda.wasm +0 -0
  29. package/dist/664.bundle.4792c88ae0d6d4b5ed13.js +901 -0
  30. package/dist/707.bundle.0a74aa3e61ed002eb3c6.js +9049 -0
  31. package/dist/707.css +1 -0
  32. package/dist/728.bundle.d13856835357400fef82.js +26221 -0
  33. package/dist/744.bundle.53b07e48e07a11e920ac.js +2355 -0
  34. package/dist/75788f12450d4c5ed494.wasm +0 -0
  35. package/dist/75a0c2dfe07b824c7d21.wasm +0 -0
  36. package/dist/780.bundle.f60ac1906e0ae080dee8.js +4769 -0
  37. package/dist/790.bundle.b4df2c5d78a2a565b150.js +454 -0
  38. package/dist/799.bundle.3fff638815e355b0bdfd.js +271 -0
  39. package/dist/806.css +1 -0
  40. package/dist/82.bundle.a24015533196e05d190e.js +6104 -0
  41. package/dist/917.bundle.a094ae9e9de6df4119ae.js +196 -0
  42. package/dist/926.bundle.dbc9d0e591cb9217fda2.js +72552 -0
  43. package/dist/935.bundle.deeffff0e4f7b528e3c3.js +1849 -0
  44. package/dist/945.min.worker.js +2 -0
  45. package/dist/945.min.worker.js.map +1 -0
  46. package/dist/953.bundle.c14d9eb6400f697019ee.js +449 -0
  47. package/dist/973.bundle.4100cf103686b64938d1.js +261 -0
  48. package/dist/976.bundle.2720eb892514e1818018.js +2725 -0
  49. package/dist/984.bundle.157fc66ea5040e1364af.js +1842 -0
  50. package/dist/_headers +6 -0
  51. package/dist/_redirects +6 -0
  52. package/dist/app-config.js +215 -0
  53. package/dist/app.bundle.253eeb2a7ee986e89c50.js +154621 -0
  54. package/dist/app.bundle.css +21 -0
  55. package/dist/assets/android-chrome-144x144.png +0 -0
  56. package/dist/assets/android-chrome-192x192.png +0 -0
  57. package/dist/assets/android-chrome-256x256.png +0 -0
  58. package/dist/assets/android-chrome-36x36.png +0 -0
  59. package/dist/assets/android-chrome-384x384.png +0 -0
  60. package/dist/assets/android-chrome-48x48.png +0 -0
  61. package/dist/assets/android-chrome-512x512.png +0 -0
  62. package/dist/assets/android-chrome-72x72.png +0 -0
  63. package/dist/assets/android-chrome-96x96.png +0 -0
  64. package/dist/assets/apple-touch-icon-1024x1024.png +0 -0
  65. package/dist/assets/apple-touch-icon-114x114.png +0 -0
  66. package/dist/assets/apple-touch-icon-120x120.png +0 -0
  67. package/dist/assets/apple-touch-icon-144x144.png +0 -0
  68. package/dist/assets/apple-touch-icon-152x152.png +0 -0
  69. package/dist/assets/apple-touch-icon-167x167.png +0 -0
  70. package/dist/assets/apple-touch-icon-180x180.png +0 -0
  71. package/dist/assets/apple-touch-icon-57x57.png +0 -0
  72. package/dist/assets/apple-touch-icon-60x60.png +0 -0
  73. package/dist/assets/apple-touch-icon-72x72.png +0 -0
  74. package/dist/assets/apple-touch-icon-76x76.png +0 -0
  75. package/dist/assets/apple-touch-icon-precomposed.png +0 -0
  76. package/dist/assets/apple-touch-icon.png +0 -0
  77. package/dist/assets/apple-touch-startup-image-1182x2208.png +0 -0
  78. package/dist/assets/apple-touch-startup-image-1242x2148.png +0 -0
  79. package/dist/assets/apple-touch-startup-image-1496x2048.png +0 -0
  80. package/dist/assets/apple-touch-startup-image-1536x2008.png +0 -0
  81. package/dist/assets/apple-touch-startup-image-320x460.png +0 -0
  82. package/dist/assets/apple-touch-startup-image-640x1096.png +0 -0
  83. package/dist/assets/apple-touch-startup-image-640x920.png +0 -0
  84. package/dist/assets/apple-touch-startup-image-748x1024.png +0 -0
  85. package/dist/assets/apple-touch-startup-image-750x1294.png +0 -0
  86. package/dist/assets/apple-touch-startup-image-768x1004.png +0 -0
  87. package/dist/assets/browserconfig.xml +12 -0
  88. package/dist/assets/coast-228x228.png +0 -0
  89. package/dist/assets/favicon-16x16.png +0 -0
  90. package/dist/assets/favicon-32x32.png +0 -0
  91. package/dist/assets/favicon.ico +0 -0
  92. package/dist/assets/firefox_app_128x128.png +0 -0
  93. package/dist/assets/firefox_app_512x512.png +0 -0
  94. package/dist/assets/firefox_app_60x60.png +0 -0
  95. package/dist/assets/manifest.webapp +14 -0
  96. package/dist/assets/mstile-144x144.png +0 -0
  97. package/dist/assets/mstile-150x150.png +0 -0
  98. package/dist/assets/mstile-310x150.png +0 -0
  99. package/dist/assets/mstile-310x310.png +0 -0
  100. package/dist/assets/mstile-70x70.png +0 -0
  101. package/dist/assets/yandex-browser-50x50.png +0 -0
  102. package/dist/assets/yandex-browser-manifest.json +9 -0
  103. package/dist/b6b803111e2d06a825bd.wasm +0 -0
  104. package/dist/c22b37c3488e1d6c3aa4.wasm +0 -0
  105. package/dist/cornerstoneDICOMImageLoader.min.js +2 -0
  106. package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -0
  107. package/dist/dicom-microscopy-viewer.bundle.aa60bdf008c32c39cfd7.js +12 -0
  108. package/dist/dicomMicroscopyViewer.min.js +3 -0
  109. package/dist/dicomMicroscopyViewer.min.js.LICENSE.txt +29 -0
  110. package/dist/es6-shim.min.js +12 -0
  111. package/dist/google.js +75 -0
  112. package/dist/index.html +1 -0
  113. package/dist/index.worker.ea71efba2ce63c499055.worker.js +2 -0
  114. package/dist/index.worker.ea71efba2ce63c499055.worker.js.map +1 -0
  115. package/dist/index.worker.min.worker.js +2 -0
  116. package/dist/index.worker.min.worker.js.map +1 -0
  117. package/dist/init-service-worker.js +59 -0
  118. package/dist/manifest.json +59 -0
  119. package/dist/ohif-logo-light.svg +15 -0
  120. package/dist/ohif-logo.svg +15 -0
  121. package/dist/oidc-client.min.js +46 -0
  122. package/dist/polyfill.min.js +1 -0
  123. package/dist/silent-refresh.html +16 -0
  124. package/dist/sw.js +56 -0
  125. package/package.json +24 -23
@@ -0,0 +1,1471 @@
1
+ "use strict";
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[351],{
3
+
4
+ /***/ 30351:
5
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
6
+
7
+ // ESM COMPAT FLAG
8
+ __webpack_require__.r(__webpack_exports__);
9
+
10
+ // EXPORTS
11
+ __webpack_require__.d(__webpack_exports__, {
12
+ "default": () => (/* binding */ Viewport_OHIFCornerstoneViewport)
13
+ });
14
+
15
+ // EXTERNAL MODULE: ../../../node_modules/react/index.js
16
+ var react = __webpack_require__(32735);
17
+ // EXTERNAL MODULE: ../../../node_modules/react-resize-detector/build/index.esm.js
18
+ var index_esm = __webpack_require__(14664);
19
+ // EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
20
+ var prop_types = __webpack_require__(60216);
21
+ var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
22
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js + 321 modules
23
+ var esm = __webpack_require__(57270);
24
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 335 modules
25
+ var dist_esm = __webpack_require__(77331);
26
+ // EXTERNAL MODULE: ../../core/src/index.ts + 101 modules
27
+ var src = __webpack_require__(48501);
28
+ // EXTERNAL MODULE: ../../ui/src/index.js + 449 modules
29
+ var ui_src = __webpack_require__(43803);
30
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/state.ts
31
+ var state = __webpack_require__(21922);
32
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.css
33
+ // extracted by mini-css-extract-plugin
34
+
35
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/ViewportImageScrollbar.tsx
36
+
37
+
38
+
39
+
40
+
41
+ function CornerstoneImageScrollbar(_ref) {
42
+ let {
43
+ viewportData,
44
+ viewportIndex,
45
+ element,
46
+ imageSliceData,
47
+ setImageSliceData,
48
+ scrollbarHeight,
49
+ servicesManager
50
+ } = _ref;
51
+ const {
52
+ cineService,
53
+ cornerstoneViewportService
54
+ } = servicesManager.services;
55
+ const onImageScrollbarChange = (imageIndex, viewportIndex) => {
56
+ const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(viewportIndex);
57
+ const viewportId = viewportInfo.getViewportId();
58
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
59
+ const {
60
+ isCineEnabled
61
+ } = cineService.getState();
62
+ if (isCineEnabled) {
63
+ // on image scrollbar change, stop the CINE if it is playing
64
+ cineService.stopClip(element);
65
+ cineService.setCine({
66
+ id: viewportIndex,
67
+ isPlaying: false
68
+ });
69
+ }
70
+ esm.utilities.jumpToSlice(viewport.element, {
71
+ imageIndex,
72
+ debounceLoading: true
73
+ });
74
+ };
75
+ (0,react.useEffect)(() => {
76
+ if (!viewportData) {
77
+ return;
78
+ }
79
+ const viewport = cornerstoneViewportService.getCornerstoneViewportByIndex(viewportIndex);
80
+ if (!viewport) {
81
+ return;
82
+ }
83
+ if (viewportData.viewportType === dist_esm.Enums.ViewportType.STACK) {
84
+ const imageIndex = viewport.getCurrentImageIdIndex();
85
+ setImageSliceData({
86
+ imageIndex: imageIndex,
87
+ numberOfSlices: viewportData.data.imageIds.length
88
+ });
89
+ return;
90
+ }
91
+ if (viewportData.viewportType === dist_esm.Enums.ViewportType.ORTHOGRAPHIC) {
92
+ const sliceData = dist_esm.utilities.getImageSliceDataForVolumeViewport(viewport);
93
+ if (!sliceData) {
94
+ return;
95
+ }
96
+ const {
97
+ imageIndex,
98
+ numberOfSlices
99
+ } = sliceData;
100
+ setImageSliceData({
101
+ imageIndex,
102
+ numberOfSlices
103
+ });
104
+ }
105
+ }, [viewportIndex, viewportData]);
106
+ (0,react.useEffect)(() => {
107
+ if (viewportData?.viewportType !== dist_esm.Enums.ViewportType.STACK) {
108
+ return;
109
+ }
110
+ const updateStackIndex = event => {
111
+ const {
112
+ newImageIdIndex
113
+ } = event.detail;
114
+ // find the index of imageId in the imageIds
115
+ setImageSliceData({
116
+ imageIndex: newImageIdIndex,
117
+ numberOfSlices: viewportData.data.imageIds.length
118
+ });
119
+ };
120
+ element.addEventListener(dist_esm.Enums.Events.STACK_VIEWPORT_SCROLL, updateStackIndex);
121
+ return () => {
122
+ element.removeEventListener(dist_esm.Enums.Events.STACK_VIEWPORT_SCROLL, updateStackIndex);
123
+ };
124
+ }, [viewportData, element]);
125
+ (0,react.useEffect)(() => {
126
+ if (viewportData?.viewportType !== dist_esm.Enums.ViewportType.ORTHOGRAPHIC) {
127
+ return;
128
+ }
129
+ const updateVolumeIndex = event => {
130
+ const {
131
+ imageIndex,
132
+ numberOfSlices
133
+ } = event.detail;
134
+ // find the index of imageId in the imageIds
135
+ setImageSliceData({
136
+ imageIndex,
137
+ numberOfSlices
138
+ });
139
+ };
140
+ element.addEventListener(dist_esm.Enums.Events.VOLUME_NEW_IMAGE, updateVolumeIndex);
141
+ return () => {
142
+ element.removeEventListener(dist_esm.Enums.Events.VOLUME_NEW_IMAGE, updateVolumeIndex);
143
+ };
144
+ }, [viewportData, element]);
145
+ return /*#__PURE__*/react.createElement(ui_src/* ImageScrollbar */.Ln, {
146
+ onChange: evt => onImageScrollbarChange(evt, viewportIndex),
147
+ max: imageSliceData.numberOfSlices ? imageSliceData.numberOfSlices - 1 : 0,
148
+ height: scrollbarHeight,
149
+ value: imageSliceData.imageIndex
150
+ });
151
+ }
152
+ CornerstoneImageScrollbar.propTypes = {
153
+ viewportData: (prop_types_default()).object,
154
+ viewportIndex: (prop_types_default()).number.isRequired,
155
+ element: prop_types_default().instanceOf(Element),
156
+ scrollbarHeight: (prop_types_default()).string,
157
+ imageSliceData: (prop_types_default()).object.isRequired,
158
+ setImageSliceData: (prop_types_default()).func.isRequired,
159
+ servicesManager: (prop_types_default()).object.isRequired
160
+ };
161
+ /* harmony default export */ const ViewportImageScrollbar = (CornerstoneImageScrollbar);
162
+ // EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 10 modules
163
+ var gl_matrix_esm = __webpack_require__(88256);
164
+ // EXTERNAL MODULE: ../../../node_modules/moment/moment.js
165
+ var moment = __webpack_require__(53806);
166
+ var moment_default = /*#__PURE__*/__webpack_require__.n(moment);
167
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/utils.ts
168
+
169
+
170
+
171
+ /**
172
+ * Checks if value is valid.
173
+ *
174
+ * @param {number} value
175
+ * @returns {boolean} is valid.
176
+ */
177
+ function isValidNumber(value) {
178
+ return typeof value === 'number' && !isNaN(value);
179
+ }
180
+
181
+ /**
182
+ * Formats number precision.
183
+ *
184
+ * @param {number} number
185
+ * @param {number} precision
186
+ * @returns {number} formatted number.
187
+ */
188
+ function formatNumberPrecision(number) {
189
+ let precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
190
+ if (number !== null) {
191
+ return parseFloat(number).toFixed(precision);
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Formats DICOM date.
197
+ *
198
+ * @param {string} date
199
+ * @param {string} strFormat
200
+ * @returns {string} formatted date.
201
+ */
202
+ function formatDICOMDate(date) {
203
+ let strFormat = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'MMM D, YYYY';
204
+ return moment_default()(date, 'YYYYMMDD').format(strFormat);
205
+ }
206
+
207
+ /**
208
+ * DICOM Time is stored as HHmmss.SSS, where:
209
+ * HH 24 hour time:
210
+ * m mm 0..59 Minutes
211
+ * s ss 0..59 Seconds
212
+ * S SS SSS 0..999 Fractional seconds
213
+ *
214
+ * Goal: '24:12:12'
215
+ *
216
+ * @param {*} time
217
+ * @param {string} strFormat
218
+ * @returns {string} formatted name.
219
+ */
220
+ function formatDICOMTime(time) {
221
+ let strFormat = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'HH:mm:ss';
222
+ return moment_default()(time, 'HH:mm:ss').format(strFormat);
223
+ }
224
+
225
+ /**
226
+ * Formats a patient name for display purposes
227
+ *
228
+ * @param {string} name
229
+ * @returns {string} formatted name.
230
+ */
231
+ function formatPN(name) {
232
+ if (!name) {
233
+ return '';
234
+ }
235
+ const cleaned = name.split('^').filter(s => !!s).join(', ').trim();
236
+ return cleaned === ',' || cleaned === '' ? '' : cleaned;
237
+ }
238
+
239
+ /**
240
+ * Gets compression type
241
+ *
242
+ * @param {number} imageId
243
+ * @returns {string} comrpession type.
244
+ */
245
+ function getCompression(imageId) {
246
+ const generalImageModule = metaData.get('generalImageModule', imageId) || {};
247
+ const {
248
+ lossyImageCompression,
249
+ lossyImageCompressionRatio,
250
+ lossyImageCompressionMethod
251
+ } = generalImageModule;
252
+ if (lossyImageCompression === '01' && lossyImageCompressionRatio !== '') {
253
+ const compressionMethod = lossyImageCompressionMethod || 'Lossy: ';
254
+ const compressionRatio = formatNumberPrecision(lossyImageCompressionRatio, 2);
255
+ return compressionMethod + compressionRatio + ' : 1';
256
+ }
257
+ return 'Lossless / Uncompressed';
258
+ }
259
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/CustomizableViewportOverlay.css
260
+ // extracted by mini-css-extract-plugin
261
+
262
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/CustomizableViewportOverlay.tsx
263
+
264
+
265
+
266
+
267
+
268
+
269
+
270
+ const EPSILON = 1e-4;
271
+ /**
272
+ * Window Level / Center Overlay item
273
+ */
274
+ function VOIOverlayItem(_ref) {
275
+ let {
276
+ voi,
277
+ customization
278
+ } = _ref;
279
+ const {
280
+ windowWidth,
281
+ windowCenter
282
+ } = voi;
283
+ if (typeof windowCenter !== 'number' || typeof windowWidth !== 'number') {
284
+ return null;
285
+ }
286
+ return /*#__PURE__*/react.createElement("div", {
287
+ className: "overlay-item flex flex-row",
288
+ style: {
289
+ color: customization && customization.color || undefined
290
+ }
291
+ }, /*#__PURE__*/react.createElement("span", {
292
+ className: "mr-1 shrink-0"
293
+ }, "W:"), /*#__PURE__*/react.createElement("span", {
294
+ className: "ml-1 mr-2 font-light shrink-0"
295
+ }, windowWidth.toFixed(0)), /*#__PURE__*/react.createElement("span", {
296
+ className: "mr-1 shrink-0"
297
+ }, "L:"), /*#__PURE__*/react.createElement("span", {
298
+ className: "ml-1 font-light shrink-0"
299
+ }, windowCenter.toFixed(0)));
300
+ }
301
+
302
+ /**
303
+ * Zoom Level Overlay item
304
+ */
305
+ function ZoomOverlayItem(_ref2) {
306
+ let {
307
+ scale,
308
+ customization
309
+ } = _ref2;
310
+ return /*#__PURE__*/react.createElement("div", {
311
+ className: "overlay-item flex flex-row",
312
+ style: {
313
+ color: customization && customization.color || undefined
314
+ }
315
+ }, /*#__PURE__*/react.createElement("span", {
316
+ className: "mr-1 shrink-0"
317
+ }, "Zoom:"), /*#__PURE__*/react.createElement("span", {
318
+ className: "font-light"
319
+ }, scale.toFixed(2), "x"));
320
+ }
321
+
322
+ /**
323
+ * Instance Number Overlay Item
324
+ */
325
+ function InstanceNumberOverlayItem(_ref3) {
326
+ let {
327
+ instanceNumber,
328
+ imageSliceData,
329
+ customization
330
+ } = _ref3;
331
+ const {
332
+ imageIndex,
333
+ numberOfSlices
334
+ } = imageSliceData;
335
+ return /*#__PURE__*/react.createElement("div", {
336
+ className: "overlay-item flex flex-row",
337
+ style: {
338
+ color: customization && customization.color || undefined
339
+ }
340
+ }, /*#__PURE__*/react.createElement("span", {
341
+ className: "mr-1 shrink-0"
342
+ }, "I:"), /*#__PURE__*/react.createElement("span", {
343
+ className: "font-light"
344
+ }, instanceNumber !== undefined && instanceNumber !== null ? `${instanceNumber} (${imageIndex + 1}/${numberOfSlices})` : `${imageIndex + 1}/${numberOfSlices}`));
345
+ }
346
+
347
+ /**
348
+ * Customizable Viewport Overlay
349
+ */
350
+ function CustomizableViewportOverlay(_ref4) {
351
+ let {
352
+ element,
353
+ viewportData,
354
+ imageSliceData,
355
+ viewportIndex,
356
+ servicesManager
357
+ } = _ref4;
358
+ const {
359
+ toolbarService,
360
+ cornerstoneViewportService,
361
+ customizationService
362
+ } = servicesManager.services;
363
+ const [voi, setVOI] = (0,react.useState)({
364
+ windowCenter: null,
365
+ windowWidth: null
366
+ });
367
+ const [scale, setScale] = (0,react.useState)(1);
368
+ const [activeTools, setActiveTools] = (0,react.useState)([]);
369
+ const {
370
+ imageIndex
371
+ } = imageSliceData;
372
+ const topLeftCustomization = customizationService.getModeCustomization('cornerstoneOverlayTopLeft');
373
+ const topRightCustomization = customizationService.getModeCustomization('cornerstoneOverlayTopRight');
374
+ const bottomLeftCustomization = customizationService.getModeCustomization('cornerstoneOverlayBottomLeft');
375
+ const bottomRightCustomization = customizationService.getModeCustomization('cornerstoneOverlayBottomRight');
376
+ const instance = (0,react.useMemo)(() => {
377
+ if (viewportData != null) {
378
+ return _getViewportInstance(viewportData, imageIndex);
379
+ } else {
380
+ return null;
381
+ }
382
+ }, [viewportData, imageIndex]);
383
+ const instanceNumber = (0,react.useMemo)(() => {
384
+ if (viewportData != null) {
385
+ return _getInstanceNumber(viewportData, viewportIndex, imageIndex, cornerstoneViewportService);
386
+ }
387
+ return null;
388
+ }, [viewportData, viewportIndex, imageIndex, cornerstoneViewportService]);
389
+
390
+ /**
391
+ * Initial toolbar state
392
+ */
393
+ (0,react.useEffect)(() => {
394
+ setActiveTools(toolbarService.getActiveTools());
395
+ }, []);
396
+
397
+ /**
398
+ * Updating the VOI when the viewport changes its voi
399
+ */
400
+ (0,react.useEffect)(() => {
401
+ const updateVOI = eventDetail => {
402
+ const {
403
+ range
404
+ } = eventDetail.detail;
405
+ if (!range) {
406
+ return;
407
+ }
408
+ const {
409
+ lower,
410
+ upper
411
+ } = range;
412
+ const {
413
+ windowWidth,
414
+ windowCenter
415
+ } = dist_esm.utilities.windowLevel.toWindowLevel(lower, upper);
416
+ setVOI({
417
+ windowCenter,
418
+ windowWidth
419
+ });
420
+ };
421
+ element.addEventListener(dist_esm.Enums.Events.VOI_MODIFIED, updateVOI);
422
+ return () => {
423
+ element.removeEventListener(dist_esm.Enums.Events.VOI_MODIFIED, updateVOI);
424
+ };
425
+ }, [viewportIndex, viewportData, voi, element]);
426
+
427
+ /**
428
+ * Updating the scale when the viewport changes its zoom
429
+ */
430
+ (0,react.useEffect)(() => {
431
+ const updateScale = eventDetail => {
432
+ const {
433
+ previousCamera,
434
+ camera
435
+ } = eventDetail.detail;
436
+ if (previousCamera.parallelScale !== camera.parallelScale || previousCamera.scale !== camera.scale) {
437
+ const viewport = cornerstoneViewportService.getCornerstoneViewportByIndex(viewportIndex);
438
+ if (!viewport) {
439
+ return;
440
+ }
441
+ const imageData = viewport.getImageData();
442
+ if (!imageData) {
443
+ return;
444
+ }
445
+ if (camera.scale) {
446
+ setScale(camera.scale);
447
+ return;
448
+ }
449
+ const {
450
+ spacing
451
+ } = imageData;
452
+ // convert parallel scale to scale
453
+ const scale = element.clientHeight * spacing[0] * 0.5 / camera.parallelScale;
454
+ setScale(scale);
455
+ }
456
+ };
457
+ element.addEventListener(dist_esm.Enums.Events.CAMERA_MODIFIED, updateScale);
458
+ return () => {
459
+ element.removeEventListener(dist_esm.Enums.Events.CAMERA_MODIFIED, updateScale);
460
+ };
461
+ }, [viewportIndex, viewportData, cornerstoneViewportService, element]);
462
+
463
+ /**
464
+ * Updating the active tools when the toolbar changes
465
+ */
466
+ // Todo: this should act on the toolGroups instead of the toolbar state
467
+ (0,react.useEffect)(() => {
468
+ const {
469
+ unsubscribe
470
+ } = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, () => {
471
+ setActiveTools(toolbarService.getActiveTools());
472
+ });
473
+ return () => {
474
+ unsubscribe();
475
+ };
476
+ }, [toolbarService]);
477
+ const _renderOverlayItem = (0,react.useCallback)(item => {
478
+ const overlayItemProps = {
479
+ element,
480
+ viewportData,
481
+ imageSliceData,
482
+ viewportIndex,
483
+ servicesManager,
484
+ customization: item,
485
+ formatters: {
486
+ formatPN: formatPN,
487
+ formatDate: formatDICOMDate,
488
+ formatTime: formatDICOMTime,
489
+ formatNumberPrecision: formatNumberPrecision
490
+ },
491
+ instance,
492
+ // calculated
493
+ voi,
494
+ scale,
495
+ instanceNumber
496
+ };
497
+ if (item.customizationType === 'ohif.overlayItem.windowLevel') {
498
+ return /*#__PURE__*/react.createElement(VOIOverlayItem, overlayItemProps);
499
+ } else if (item.customizationType === 'ohif.overlayItem.zoomLevel') {
500
+ return /*#__PURE__*/react.createElement(ZoomOverlayItem, overlayItemProps);
501
+ } else if (item.customizationType === 'ohif.overlayItem.instanceNumber') {
502
+ return /*#__PURE__*/react.createElement(InstanceNumberOverlayItem, overlayItemProps);
503
+ } else {
504
+ const renderItem = customizationService.transform(item);
505
+ if (typeof renderItem.content === 'function') {
506
+ return renderItem.content(overlayItemProps);
507
+ }
508
+ }
509
+ }, [element, viewportData, imageSliceData, viewportIndex, servicesManager, customizationService, instance, voi, scale, instanceNumber]);
510
+ const getTopLeftContent = (0,react.useCallback)(() => {
511
+ const items = topLeftCustomization?.items || [{
512
+ id: 'WindowLevel',
513
+ customizationType: 'ohif.overlayItem.windowLevel'
514
+ }];
515
+ return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
516
+ key: `topLeftOverlayItem_${i}`
517
+ }, _renderOverlayItem(item))));
518
+ }, [topLeftCustomization, _renderOverlayItem]);
519
+ const getTopRightContent = (0,react.useCallback)(() => {
520
+ const items = topRightCustomization?.items || [{
521
+ id: 'InstanceNmber',
522
+ customizationType: 'ohif.overlayItem.instanceNumber'
523
+ }];
524
+ return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
525
+ key: `topRightOverlayItem_${i}`
526
+ }, _renderOverlayItem(item))));
527
+ }, [topRightCustomization, _renderOverlayItem]);
528
+ const getBottomLeftContent = (0,react.useCallback)(() => {
529
+ const items = bottomLeftCustomization?.items || [];
530
+ return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
531
+ key: `bottomLeftOverlayItem_${i}`
532
+ }, _renderOverlayItem(item))));
533
+ }, [bottomLeftCustomization, _renderOverlayItem]);
534
+ const getBottomRightContent = (0,react.useCallback)(() => {
535
+ const items = bottomRightCustomization?.items || [];
536
+ return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
537
+ key: `bottomRightOverlayItem_${i}`
538
+ }, _renderOverlayItem(item))));
539
+ }, [bottomRightCustomization, _renderOverlayItem]);
540
+ return /*#__PURE__*/react.createElement(ui_src/* ViewportOverlay */.No, {
541
+ topLeft: getTopLeftContent(),
542
+ topRight: getTopRightContent(),
543
+ bottomLeft: getBottomLeftContent(),
544
+ bottomRight: getBottomRightContent()
545
+ });
546
+ }
547
+ function _getViewportInstance(viewportData, imageIndex) {
548
+ let imageId = null;
549
+ if (viewportData.viewportType === dist_esm.Enums.ViewportType.STACK) {
550
+ imageId = viewportData.data.imageIds[imageIndex];
551
+ } else if (viewportData.viewportType === dist_esm.Enums.ViewportType.ORTHOGRAPHIC) {
552
+ const volumes = viewportData.volumes;
553
+ if (volumes && volumes.length == 1) {
554
+ const volume = volumes[0];
555
+ imageId = volume.imageIds[imageIndex];
556
+ }
557
+ }
558
+ return imageId ? dist_esm.metaData.get('instance', imageId) || {} : {};
559
+ }
560
+ function _getInstanceNumber(viewportData, viewportIndex, imageIndex, cornerstoneViewportService) {
561
+ let instanceNumber;
562
+ if (viewportData.viewportType === dist_esm.Enums.ViewportType.STACK) {
563
+ instanceNumber = _getInstanceNumberFromStack(viewportData, imageIndex);
564
+ if (!instanceNumber && instanceNumber !== 0) {
565
+ return null;
566
+ }
567
+ } else if (viewportData.viewportType === dist_esm.Enums.ViewportType.ORTHOGRAPHIC) {
568
+ instanceNumber = _getInstanceNumberFromVolume(viewportData, imageIndex, viewportIndex, cornerstoneViewportService);
569
+ }
570
+ return instanceNumber;
571
+ }
572
+ function _getInstanceNumberFromStack(viewportData, imageIndex) {
573
+ const imageIds = viewportData.data.imageIds;
574
+ const imageId = imageIds[imageIndex];
575
+ if (!imageId) {
576
+ return;
577
+ }
578
+ const generalImageModule = dist_esm.metaData.get('generalImageModule', imageId) || {};
579
+ const {
580
+ instanceNumber
581
+ } = generalImageModule;
582
+ const stackSize = imageIds.length;
583
+ if (stackSize <= 1) {
584
+ return;
585
+ }
586
+ return parseInt(instanceNumber);
587
+ }
588
+
589
+ // Since volume viewports can be in any view direction, they can render
590
+ // a reconstructed image which don't have imageIds; therefore, no instance and instanceNumber
591
+ // Here we check if viewport is in the acquisition direction and if so, we get the instanceNumber
592
+ function _getInstanceNumberFromVolume(viewportData, imageIndex, viewportIndex, cornerstoneViewportService) {
593
+ const volumes = viewportData.volumes;
594
+
595
+ // Todo: support fusion of acquisition plane which has instanceNumber
596
+ if (!volumes || volumes.length > 1) {
597
+ return;
598
+ }
599
+ const volume = volumes[0];
600
+ const {
601
+ direction,
602
+ imageIds
603
+ } = volume;
604
+ const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewportByIndex(viewportIndex);
605
+ if (!cornerstoneViewport) {
606
+ return;
607
+ }
608
+ const camera = cornerstoneViewport.getCamera();
609
+ const {
610
+ viewPlaneNormal
611
+ } = camera;
612
+ // checking if camera is looking at the acquisition plane (defined by the direction on the volume)
613
+
614
+ const scanAxisNormal = direction.slice(6, 9);
615
+
616
+ // check if viewPlaneNormal is parallel to scanAxisNormal
617
+ const cross = gl_matrix_esm/* vec3.cross */.R3.cross(gl_matrix_esm/* vec3.create */.R3.create(), viewPlaneNormal, scanAxisNormal);
618
+ const isAcquisitionPlane = gl_matrix_esm/* vec3.length */.R3.length(cross) < EPSILON;
619
+ if (isAcquisitionPlane) {
620
+ const imageId = imageIds[imageIndex];
621
+ if (!imageId) {
622
+ return {};
623
+ }
624
+ const {
625
+ instanceNumber
626
+ } = dist_esm.metaData.get('generalImageModule', imageId) || {};
627
+ return parseInt(instanceNumber);
628
+ }
629
+ }
630
+ CustomizableViewportOverlay.propTypes = {
631
+ viewportData: (prop_types_default()).object,
632
+ imageIndex: (prop_types_default()).number,
633
+ viewportIndex: (prop_types_default()).number
634
+ };
635
+ /* harmony default export */ const Overlays_CustomizableViewportOverlay = (CustomizableViewportOverlay);
636
+ // EXTERNAL MODULE: ../../../node_modules/classnames/index.js
637
+ var classnames = __webpack_require__(40841);
638
+ var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
639
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.css
640
+ // extracted by mini-css-extract-plugin
641
+
642
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.tsx
643
+
644
+
645
+
646
+
647
+
648
+
649
+
650
+ const {
651
+ getOrientationStringLPS,
652
+ invertOrientationStringLPS
653
+ } = esm.utilities.orientation;
654
+ function ViewportOrientationMarkers(_ref) {
655
+ let {
656
+ element,
657
+ viewportData,
658
+ imageSliceData,
659
+ viewportIndex,
660
+ servicesManager,
661
+ orientationMarkers = ['top', 'left']
662
+ } = _ref;
663
+ // Rotation is in degrees
664
+ const [rotation, setRotation] = (0,react.useState)(0);
665
+ const [flipHorizontal, setFlipHorizontal] = (0,react.useState)(false);
666
+ const [flipVertical, setFlipVertical] = (0,react.useState)(false);
667
+ const {
668
+ cornerstoneViewportService
669
+ } = servicesManager.services;
670
+ (0,react.useEffect)(() => {
671
+ const cameraModifiedListener = evt => {
672
+ const {
673
+ rotation,
674
+ previousCamera,
675
+ camera
676
+ } = evt.detail;
677
+ if (rotation !== undefined) {
678
+ setRotation(rotation);
679
+ }
680
+ if (camera.flipHorizontal !== undefined && previousCamera.flipHorizontal !== camera.flipHorizontal) {
681
+ setFlipHorizontal(camera.flipHorizontal);
682
+ }
683
+ if (camera.flipVertical !== undefined && previousCamera.flipVertical !== camera.flipVertical) {
684
+ setFlipVertical(camera.flipVertical);
685
+ }
686
+ };
687
+ element.addEventListener(dist_esm.Enums.Events.CAMERA_MODIFIED, cameraModifiedListener);
688
+ return () => {
689
+ element.removeEventListener(dist_esm.Enums.Events.CAMERA_MODIFIED, cameraModifiedListener);
690
+ };
691
+ }, []);
692
+ const markers = (0,react.useMemo)(() => {
693
+ if (!viewportData) {
694
+ return '';
695
+ }
696
+ let rowCosines, columnCosines;
697
+ if (viewportData.viewportType === 'stack') {
698
+ const imageIndex = imageSliceData.imageIndex;
699
+ const imageId = viewportData.data.imageIds?.[imageIndex];
700
+
701
+ // Workaround for below TODO stub
702
+ if (!imageId) {
703
+ return false;
704
+ }
705
+ ({
706
+ rowCosines,
707
+ columnCosines
708
+ } = dist_esm.metaData.get('imagePlaneModule', imageId) || {});
709
+ } else {
710
+ if (!element || !(0,dist_esm.getEnabledElement)(element)) {
711
+ return '';
712
+ }
713
+ const {
714
+ viewport
715
+ } = (0,dist_esm.getEnabledElement)(element);
716
+ const {
717
+ viewUp,
718
+ viewPlaneNormal
719
+ } = viewport.getCamera();
720
+ const viewRight = gl_matrix_esm/* vec3.create */.R3.create();
721
+ gl_matrix_esm/* vec3.cross */.R3.cross(viewRight, viewUp, viewPlaneNormal);
722
+ columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]];
723
+ rowCosines = viewRight;
724
+ }
725
+ if (!rowCosines || !columnCosines || rotation === undefined) {
726
+ return '';
727
+ }
728
+ const markers = _getOrientationMarkers(rowCosines, columnCosines, rotation, flipVertical, flipHorizontal);
729
+ const ohifViewport = cornerstoneViewportService.getViewportInfoByIndex(viewportIndex);
730
+ if (!ohifViewport) {
731
+ console.log('ViewportOrientationMarkers::No viewport');
732
+ return null;
733
+ }
734
+ const backgroundColor = ohifViewport.getViewportOptions().background;
735
+
736
+ // Todo: probably this can be done in a better way in which we identify bright
737
+ // background
738
+ const isLight = backgroundColor ? dist_esm.utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
739
+ return orientationMarkers.map((m, index) => /*#__PURE__*/react.createElement("div", {
740
+ className: classnames_default()(`${m}-mid orientation-marker`, isLight ? 'text-[#726F7E]' : 'text-[#ccc]'),
741
+ key: `${m}-mid orientation-marker`
742
+ }, /*#__PURE__*/react.createElement("div", {
743
+ className: "orientation-marker-value"
744
+ }, markers[m])));
745
+ }, [viewportData, imageSliceData, rotation, flipVertical, flipHorizontal, orientationMarkers, element]);
746
+ return /*#__PURE__*/react.createElement("div", {
747
+ className: "ViewportOrientationMarkers noselect"
748
+ }, markers);
749
+ }
750
+ ViewportOrientationMarkers.propTypes = {
751
+ percentComplete: (prop_types_default()).number,
752
+ error: (prop_types_default()).object
753
+ };
754
+ ViewportOrientationMarkers.defaultProps = {
755
+ percentComplete: 0,
756
+ error: null
757
+ };
758
+
759
+ /**
760
+ *
761
+ * Computes the orientation labels on a Cornerstone-enabled Viewport element
762
+ * when the viewport settings change (e.g. when a horizontal flip or a rotation occurs)
763
+ *
764
+ * @param {*} rowCosines
765
+ * @param {*} columnCosines
766
+ * @param {*} rotation in degrees
767
+ * @returns
768
+ */
769
+ function _getOrientationMarkers(rowCosines, columnCosines, rotation, flipVertical, flipHorizontal) {
770
+ const rowString = getOrientationStringLPS(rowCosines);
771
+ const columnString = getOrientationStringLPS(columnCosines);
772
+ const oppositeRowString = invertOrientationStringLPS(rowString);
773
+ const oppositeColumnString = invertOrientationStringLPS(columnString);
774
+ const markers = {
775
+ top: oppositeColumnString,
776
+ left: oppositeRowString,
777
+ right: rowString,
778
+ bottom: columnString
779
+ };
780
+
781
+ // If any vertical or horizontal flips are applied, change the orientation strings ahead of
782
+ // the rotation applications
783
+ if (flipVertical) {
784
+ markers.top = invertOrientationStringLPS(markers.top);
785
+ markers.bottom = invertOrientationStringLPS(markers.bottom);
786
+ }
787
+ if (flipHorizontal) {
788
+ markers.left = invertOrientationStringLPS(markers.left);
789
+ markers.right = invertOrientationStringLPS(markers.right);
790
+ }
791
+
792
+ // Swap the labels accordingly if the viewport has been rotated
793
+ // This could be done in a more complex way for intermediate rotation values (e.g. 45 degrees)
794
+ if (rotation === 90 || rotation === -270) {
795
+ return {
796
+ top: markers.left,
797
+ left: invertOrientationStringLPS(markers.top),
798
+ right: invertOrientationStringLPS(markers.bottom),
799
+ bottom: markers.right // left
800
+ };
801
+ } else if (rotation === -90 || rotation === 270) {
802
+ return {
803
+ top: invertOrientationStringLPS(markers.left),
804
+ left: markers.top,
805
+ bottom: markers.left,
806
+ right: markers.bottom
807
+ };
808
+ } else if (rotation === 180 || rotation === -180) {
809
+ return {
810
+ top: invertOrientationStringLPS(markers.top),
811
+ left: invertOrientationStringLPS(markers.left),
812
+ bottom: invertOrientationStringLPS(markers.bottom),
813
+ right: invertOrientationStringLPS(markers.right)
814
+ };
815
+ }
816
+ return markers;
817
+ }
818
+ /* harmony default export */ const Overlays_ViewportOrientationMarkers = (ViewportOrientationMarkers);
819
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/ViewportImageSliceLoadingIndicator.tsx
820
+
821
+
822
+
823
+ function ViewportImageSliceLoadingIndicator(_ref) {
824
+ let {
825
+ viewportData,
826
+ element
827
+ } = _ref;
828
+ const [loading, setLoading] = (0,react.useState)(false);
829
+ const [error, setError] = (0,react.useState)(false);
830
+ const loadIndicatorRef = (0,react.useRef)(null);
831
+ const imageIdToBeLoaded = (0,react.useRef)(null);
832
+ const setLoadingState = evt => {
833
+ clearTimeout(loadIndicatorRef.current);
834
+ loadIndicatorRef.current = setTimeout(() => {
835
+ setLoading(true);
836
+ }, 50);
837
+ };
838
+ const setFinishLoadingState = evt => {
839
+ clearTimeout(loadIndicatorRef.current);
840
+ setLoading(false);
841
+ };
842
+ const setErrorState = evt => {
843
+ clearTimeout(loadIndicatorRef.current);
844
+ if (imageIdToBeLoaded.current === evt.detail.imageId) {
845
+ setError(evt.detail.error);
846
+ imageIdToBeLoaded.current = null;
847
+ }
848
+ };
849
+ (0,react.useEffect)(() => {
850
+ element.addEventListener(dist_esm.Enums.Events.STACK_VIEWPORT_SCROLL, setLoadingState);
851
+ element.addEventListener(dist_esm.Enums.Events.IMAGE_LOAD_ERROR, setErrorState);
852
+ element.addEventListener(dist_esm.Enums.Events.STACK_NEW_IMAGE, setFinishLoadingState);
853
+ return () => {
854
+ element.removeEventListener(dist_esm.Enums.Events.STACK_VIEWPORT_SCROLL, setLoadingState);
855
+ element.removeEventListener(dist_esm.Enums.Events.STACK_NEW_IMAGE, setFinishLoadingState);
856
+ element.removeEventListener(dist_esm.Enums.Events.IMAGE_LOAD_ERROR, setErrorState);
857
+ };
858
+ }, [element, viewportData]);
859
+ if (error) {
860
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
861
+ className: "bg-black opacity-50 absolute h-full w-full top-0 left-0"
862
+ }, /*#__PURE__*/react.createElement("div", {
863
+ className: "flex transparent items-center justify-center w-full h-full"
864
+ }, /*#__PURE__*/react.createElement("p", {
865
+ className: "text-primary-light text-xl font-light"
866
+ }, /*#__PURE__*/react.createElement("h4", null, "Error Loading Image"), /*#__PURE__*/react.createElement("p", null, "An error has occurred."), /*#__PURE__*/react.createElement("p", null, error)))));
867
+ }
868
+ if (loading) {
869
+ return (
870
+ /*#__PURE__*/
871
+ // IMPORTANT: we need to use the pointer-events-none class to prevent the loading indicator from
872
+ // interacting with the mouse, since scrolling should propagate to the viewport underneath
873
+ react.createElement("div", {
874
+ className: "pointer-events-none bg-black opacity-50 absolute h-full w-full top-0 left-0"
875
+ }, /*#__PURE__*/react.createElement("div", {
876
+ className: "flex transparent items-center justify-center w-full h-full"
877
+ }, /*#__PURE__*/react.createElement("p", {
878
+ className: "text-primary-light text-xl font-light"
879
+ }, "Loading...")))
880
+ );
881
+ }
882
+ return null;
883
+ }
884
+ ViewportImageSliceLoadingIndicator.propTypes = {
885
+ percentComplete: (prop_types_default()).number,
886
+ error: (prop_types_default()).object,
887
+ element: (prop_types_default()).object
888
+ };
889
+ ViewportImageSliceLoadingIndicator.defaultProps = {
890
+ percentComplete: 0,
891
+ error: null
892
+ };
893
+ /* harmony default export */ const Overlays_ViewportImageSliceLoadingIndicator = (ViewportImageSliceLoadingIndicator);
894
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/CornerstoneOverlays.tsx
895
+
896
+
897
+
898
+
899
+
900
+ function CornerstoneOverlays(props) {
901
+ const {
902
+ viewportIndex,
903
+ element,
904
+ scrollbarHeight,
905
+ servicesManager
906
+ } = props;
907
+ const {
908
+ cornerstoneViewportService
909
+ } = servicesManager.services;
910
+ const [imageSliceData, setImageSliceData] = (0,react.useState)({
911
+ imageIndex: 0,
912
+ numberOfSlices: 0
913
+ });
914
+ const [viewportData, setViewportData] = (0,react.useState)(null);
915
+ (0,react.useEffect)(() => {
916
+ const {
917
+ unsubscribe
918
+ } = cornerstoneViewportService.subscribe(cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED, props => {
919
+ if (props.viewportIndex !== viewportIndex) {
920
+ return;
921
+ }
922
+ setViewportData(props.viewportData);
923
+ });
924
+ return () => {
925
+ unsubscribe();
926
+ };
927
+ }, [viewportIndex]);
928
+ if (!element) {
929
+ return null;
930
+ }
931
+ if (viewportData) {
932
+ const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(viewportIndex);
933
+ if (viewportInfo?.viewportOptions?.customViewportProps?.hideOverlays) {
934
+ return null;
935
+ }
936
+ }
937
+ return /*#__PURE__*/react.createElement("div", {
938
+ className: "noselect"
939
+ }, /*#__PURE__*/react.createElement(ViewportImageScrollbar, {
940
+ viewportIndex: viewportIndex,
941
+ viewportData: viewportData,
942
+ element: element,
943
+ imageSliceData: imageSliceData,
944
+ setImageSliceData: setImageSliceData,
945
+ scrollbarHeight: scrollbarHeight,
946
+ servicesManager: servicesManager
947
+ }), /*#__PURE__*/react.createElement(Overlays_CustomizableViewportOverlay, {
948
+ imageSliceData: imageSliceData,
949
+ viewportData: viewportData,
950
+ viewportIndex: viewportIndex,
951
+ servicesManager: servicesManager,
952
+ element: element
953
+ }), /*#__PURE__*/react.createElement(Overlays_ViewportImageSliceLoadingIndicator, {
954
+ viewportData: viewportData,
955
+ element: element
956
+ }), /*#__PURE__*/react.createElement(Overlays_ViewportOrientationMarkers, {
957
+ imageSliceData: imageSliceData,
958
+ element: element,
959
+ viewportData: viewportData,
960
+ servicesManager: servicesManager,
961
+ viewportIndex: viewportIndex
962
+ }));
963
+ }
964
+ /* harmony default export */ const Overlays_CornerstoneOverlays = (CornerstoneOverlays);
965
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js
966
+ var getSOPInstanceAttributes = __webpack_require__(63130);
967
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx
968
+
969
+
970
+
971
+
972
+
973
+
974
+
975
+
976
+
977
+
978
+
979
+ const STACK = 'stack';
980
+
981
+ /**
982
+ * Caches the jump to measurement operation, so that if display set is shown,
983
+ * it can jump to the measurement.
984
+ */
985
+ let cacheJumpToMeasurementEvent;
986
+ function areEqual(prevProps, nextProps) {
987
+ if (nextProps.needsRerendering) {
988
+ return false;
989
+ }
990
+ if (prevProps.displaySets.length !== nextProps.displaySets.length) {
991
+ return false;
992
+ }
993
+ if (prevProps.viewportOptions.orientation !== nextProps.viewportOptions.orientation) {
994
+ return false;
995
+ }
996
+ if (prevProps.viewportOptions.toolGroupId !== nextProps.viewportOptions.toolGroupId) {
997
+ return false;
998
+ }
999
+ if (prevProps.viewportOptions.viewportType !== nextProps.viewportOptions.viewportType) {
1000
+ return false;
1001
+ }
1002
+ const prevDisplaySets = prevProps.displaySets;
1003
+ const nextDisplaySets = nextProps.displaySets;
1004
+ if (prevDisplaySets.length !== nextDisplaySets.length) {
1005
+ return false;
1006
+ }
1007
+ for (let i = 0; i < prevDisplaySets.length; i++) {
1008
+ const prevDisplaySet = prevDisplaySets[i];
1009
+ const foundDisplaySet = nextDisplaySets.find(nextDisplaySet => nextDisplaySet.displaySetInstanceUID === prevDisplaySet.displaySetInstanceUID);
1010
+ if (!foundDisplaySet) {
1011
+ return false;
1012
+ }
1013
+
1014
+ // check they contain the same image
1015
+ if (foundDisplaySet.images?.length !== prevDisplaySet.images?.length) {
1016
+ return false;
1017
+ }
1018
+
1019
+ // check if their imageIds are the same
1020
+ if (foundDisplaySet.images?.length) {
1021
+ for (let j = 0; j < foundDisplaySet.images.length; j++) {
1022
+ if (foundDisplaySet.images[j].imageId !== prevDisplaySet.images[j].imageId) {
1023
+ return false;
1024
+ }
1025
+ }
1026
+ }
1027
+ }
1028
+ return true;
1029
+ }
1030
+
1031
+ // Todo: This should be done with expose of internal API similar to react-vtkjs-viewport
1032
+ // Then we don't need to worry about the re-renders if the props change.
1033
+ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1034
+ const {
1035
+ viewportIndex,
1036
+ displaySets,
1037
+ dataSource,
1038
+ viewportOptions,
1039
+ displaySetOptions,
1040
+ servicesManager,
1041
+ onElementEnabled,
1042
+ onElementDisabled,
1043
+ // Note: you SHOULD NOT use the initialImageIdOrIndex for manipulation
1044
+ // of the imageData in the OHIFCornerstoneViewport. This prop is used
1045
+ // to set the initial state of the viewport's first image to render
1046
+ initialImageIndex
1047
+ } = props;
1048
+ const [scrollbarHeight, setScrollbarHeight] = (0,react.useState)('100px');
1049
+ const [{
1050
+ isCineEnabled,
1051
+ cines
1052
+ }, cineService] = (0,ui_src/* useCine */.vQ)();
1053
+ const [{
1054
+ activeViewportIndex
1055
+ }] = (0,ui_src/* useViewportGrid */.O_)();
1056
+ const [enabledVPElement, setEnabledVPElement] = (0,react.useState)(null);
1057
+ const elementRef = (0,react.useRef)();
1058
+ const {
1059
+ measurementService,
1060
+ displaySetService,
1061
+ toolbarService,
1062
+ toolGroupService,
1063
+ syncGroupService,
1064
+ cornerstoneViewportService,
1065
+ cornerstoneCacheService,
1066
+ viewportGridService,
1067
+ stateSyncService
1068
+ } = servicesManager.services;
1069
+ const [viewportDialogState] = (0,ui_src/* useViewportDialog */.en)();
1070
+ const cineHandler = () => {
1071
+ if (!cines || !cines[viewportIndex] || !enabledVPElement) {
1072
+ return;
1073
+ }
1074
+ const cine = cines[viewportIndex];
1075
+ const isPlaying = cine.isPlaying || false;
1076
+ const frameRate = cine.frameRate || 24;
1077
+ const validFrameRate = Math.max(frameRate, 1);
1078
+ if (isPlaying) {
1079
+ cineService.playClip(enabledVPElement, {
1080
+ framesPerSecond: validFrameRate
1081
+ });
1082
+ } else {
1083
+ cineService.stopClip(enabledVPElement);
1084
+ }
1085
+ };
1086
+ (0,react.useEffect)(() => {
1087
+ dist_esm.eventTarget.addEventListener(dist_esm.Enums.Events.STACK_VIEWPORT_NEW_STACK, cineHandler);
1088
+ return () => {
1089
+ cineService.setCine({
1090
+ id: viewportIndex,
1091
+ isPlaying: false
1092
+ });
1093
+ dist_esm.eventTarget.removeEventListener(dist_esm.Enums.Events.STACK_VIEWPORT_NEW_STACK, cineHandler);
1094
+ };
1095
+ }, [enabledVPElement]);
1096
+ (0,react.useEffect)(() => {
1097
+ if (!cines || !cines[viewportIndex] || !enabledVPElement) {
1098
+ return;
1099
+ }
1100
+ cineHandler();
1101
+ return () => {
1102
+ if (enabledVPElement && cines?.[viewportIndex]?.isPlaying) {
1103
+ cineService.stopClip(enabledVPElement);
1104
+ }
1105
+ };
1106
+ }, [cines, viewportIndex, cineService, enabledVPElement, cineHandler]);
1107
+ const cine = cines[viewportIndex];
1108
+ const isPlaying = cine && cine.isPlaying || false;
1109
+ const handleCineClose = () => {
1110
+ toolbarService.recordInteraction({
1111
+ groupId: 'MoreTools',
1112
+ itemId: 'cine',
1113
+ interactionType: 'toggle',
1114
+ commands: [{
1115
+ commandName: 'toggleCine',
1116
+ commandOptions: {},
1117
+ context: 'CORNERSTONE'
1118
+ }]
1119
+ });
1120
+ };
1121
+
1122
+ // useCallback for scroll bar height calculation
1123
+ const setImageScrollBarHeight = (0,react.useCallback)(() => {
1124
+ const scrollbarHeight = `${elementRef.current.clientHeight - 20}px`;
1125
+ setScrollbarHeight(scrollbarHeight);
1126
+ }, [elementRef]);
1127
+
1128
+ // useCallback for onResize
1129
+ const onResize = (0,react.useCallback)(() => {
1130
+ if (elementRef.current) {
1131
+ cornerstoneViewportService.resize();
1132
+ setImageScrollBarHeight();
1133
+ }
1134
+ }, [elementRef]);
1135
+ const storePresentation = () => {
1136
+ const currentPresentation = cornerstoneViewportService.getPresentation(viewportIndex);
1137
+ if (!currentPresentation || !currentPresentation.presentationIds) return;
1138
+ const {
1139
+ lutPresentationStore,
1140
+ positionPresentationStore
1141
+ } = stateSyncService.getState();
1142
+ const {
1143
+ presentationIds
1144
+ } = currentPresentation;
1145
+ const {
1146
+ lutPresentationId,
1147
+ positionPresentationId
1148
+ } = presentationIds || {};
1149
+ const storeState = {};
1150
+ if (lutPresentationId) {
1151
+ storeState.lutPresentationStore = {
1152
+ ...lutPresentationStore,
1153
+ [lutPresentationId]: currentPresentation
1154
+ };
1155
+ }
1156
+ if (positionPresentationId) {
1157
+ storeState.positionPresentationStore = {
1158
+ ...positionPresentationStore,
1159
+ [positionPresentationId]: currentPresentation
1160
+ };
1161
+ }
1162
+ stateSyncService.store(storeState);
1163
+ };
1164
+ const cleanUpServices = (0,react.useCallback)(() => {
1165
+ const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(viewportIndex);
1166
+ if (!viewportInfo) {
1167
+ return;
1168
+ }
1169
+ const viewportId = viewportInfo.getViewportId();
1170
+ const renderingEngineId = viewportInfo.getRenderingEngineId();
1171
+ const syncGroups = viewportInfo.getSyncGroups();
1172
+ toolGroupService.removeViewportFromToolGroup(viewportId, renderingEngineId);
1173
+ syncGroupService.removeViewportFromSyncGroup(viewportId, renderingEngineId, syncGroups);
1174
+ }, [viewportIndex, viewportOptions.viewportId]);
1175
+ const elementEnabledHandler = (0,react.useCallback)(evt => {
1176
+ // check this is this element reference and return early if doesn't match
1177
+ if (evt.detail.element !== elementRef.current) {
1178
+ return;
1179
+ }
1180
+ const {
1181
+ viewportId,
1182
+ element
1183
+ } = evt.detail;
1184
+ const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
1185
+ const viewportIndex = viewportInfo.getViewportIndex();
1186
+ (0,state/* setEnabledElement */.Yc)(viewportIndex, element);
1187
+ setEnabledVPElement(element);
1188
+ const renderingEngineId = viewportInfo.getRenderingEngineId();
1189
+ const toolGroupId = viewportInfo.getToolGroupId();
1190
+ const syncGroups = viewportInfo.getSyncGroups();
1191
+ toolGroupService.addViewportToToolGroup(viewportId, renderingEngineId, toolGroupId);
1192
+ syncGroupService.addViewportToSyncGroup(viewportId, renderingEngineId, syncGroups);
1193
+ if (onElementEnabled) {
1194
+ onElementEnabled(evt);
1195
+ }
1196
+ }, [viewportIndex, onElementEnabled, toolGroupService]);
1197
+
1198
+ // disable the element upon unmounting
1199
+ (0,react.useEffect)(() => {
1200
+ cornerstoneViewportService.enableViewport(viewportIndex, viewportOptions, elementRef.current);
1201
+ dist_esm.eventTarget.addEventListener(dist_esm.Enums.Events.ELEMENT_ENABLED, elementEnabledHandler);
1202
+ setImageScrollBarHeight();
1203
+ return () => {
1204
+ storePresentation();
1205
+ cleanUpServices();
1206
+ const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(viewportIndex);
1207
+ cornerstoneViewportService.disableElement(viewportIndex);
1208
+ if (onElementDisabled) {
1209
+ onElementDisabled(viewportInfo);
1210
+ }
1211
+ dist_esm.eventTarget.removeEventListener(dist_esm.Enums.Events.ELEMENT_ENABLED, elementEnabledHandler);
1212
+ };
1213
+ }, []);
1214
+
1215
+ // subscribe to displaySet metadata invalidation (updates)
1216
+ // Currently, if the metadata changes we need to re-render the display set
1217
+ // for it to take effect in the viewport. As we deal with scaling in the loading,
1218
+ // we need to remove the old volume from the cache, and let the
1219
+ // viewport to re-add it which will use the new metadata. Otherwise, the
1220
+ // viewport will use the cached volume and the new metadata will not be used.
1221
+ // Note: this approach does not actually end of sending network requests
1222
+ // and it uses the network cache
1223
+ (0,react.useEffect)(() => {
1224
+ const {
1225
+ unsubscribe
1226
+ } = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED, async invalidatedDisplaySetInstanceUID => {
1227
+ const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(viewportIndex);
1228
+ if (viewportInfo.hasDisplaySet(invalidatedDisplaySetInstanceUID)) {
1229
+ const viewportData = viewportInfo.getViewportData();
1230
+ const newViewportData = await cornerstoneCacheService.invalidateViewportData(viewportData, invalidatedDisplaySetInstanceUID, dataSource, displaySetService);
1231
+ const keepCamera = true;
1232
+ cornerstoneViewportService.updateViewport(viewportIndex, newViewportData, keepCamera);
1233
+ }
1234
+ });
1235
+ return () => {
1236
+ unsubscribe();
1237
+ };
1238
+ }, [viewportIndex]);
1239
+ (0,react.useEffect)(() => {
1240
+ // handle the default viewportType to be stack
1241
+ if (!viewportOptions.viewportType) {
1242
+ viewportOptions.viewportType = STACK;
1243
+ }
1244
+ const loadViewportData = async () => {
1245
+ const viewportData = await cornerstoneCacheService.createViewportData(displaySets, viewportOptions, dataSource, initialImageIndex);
1246
+
1247
+ // The presentation state will have been stored previously by closing
1248
+ // a viewport. Otherwise, this viewport will be unchanged and the
1249
+ // presentation information will be directly carried over.
1250
+ const {
1251
+ lutPresentationStore,
1252
+ positionPresentationStore
1253
+ } = stateSyncService.getState();
1254
+ const {
1255
+ presentationIds
1256
+ } = viewportOptions;
1257
+ const presentations = {
1258
+ positionPresentation: positionPresentationStore[presentationIds?.positionPresentationId],
1259
+ lutPresentation: lutPresentationStore[presentationIds?.lutPresentationId]
1260
+ };
1261
+ let measurement;
1262
+ if (cacheJumpToMeasurementEvent?.viewportIndex === viewportIndex) {
1263
+ measurement = cacheJumpToMeasurementEvent.measurement;
1264
+ // Delete the position presentation so that viewport navigates direct
1265
+ presentations.positionPresentation = null;
1266
+ cacheJumpToMeasurementEvent = null;
1267
+ }
1268
+ cornerstoneViewportService.setViewportData(viewportIndex, viewportData, viewportOptions, displaySetOptions, presentations);
1269
+ if (measurement) {
1270
+ esm.annotation.selection.setAnnotationSelected(measurement.uid);
1271
+ }
1272
+ };
1273
+ loadViewportData();
1274
+ }, [viewportOptions, displaySets, dataSource]);
1275
+
1276
+ /**
1277
+ * There are two scenarios for jump to click
1278
+ * 1. Current viewports contain the displaySet that the annotation was drawn on
1279
+ * 2. Current viewports don't contain the displaySet that the annotation was drawn on
1280
+ * and we need to change the viewports displaySet for jumping.
1281
+ * Since measurement_jump happens via events and listeners, the former case is handled
1282
+ * by the measurement_jump direct callback, but the latter case is handled first by
1283
+ * the viewportGrid to set the correct displaySet on the viewport, AND THEN we check
1284
+ * the cache for jumping to see if there is any jump queued, then we jump to the correct slice.
1285
+ */
1286
+ (0,react.useEffect)(() => {
1287
+ const unsubscribeFromJumpToMeasurementEvents = _subscribeToJumpToMeasurementEvents(measurementService, displaySetService, elementRef, viewportIndex, displaySets, viewportGridService, cornerstoneViewportService);
1288
+ _checkForCachedJumpToMeasurementEvents(measurementService, displaySetService, elementRef, viewportIndex, displaySets, viewportGridService, cornerstoneViewportService);
1289
+ return () => {
1290
+ unsubscribeFromJumpToMeasurementEvents();
1291
+ };
1292
+ }, [displaySets, elementRef, viewportIndex]);
1293
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1294
+ className: "viewport-wrapper"
1295
+ }, /*#__PURE__*/react.createElement(index_esm/* default */.ZP, {
1296
+ handleWidth: true,
1297
+ handleHeight: true,
1298
+ skipOnMount: true // Todo: make these configurable
1299
+ ,
1300
+ refreshMode: 'debounce',
1301
+ refreshRate: 200 // transition amount in side panel
1302
+ ,
1303
+ onResize: onResize,
1304
+ targetRef: elementRef.current
1305
+ }), /*#__PURE__*/react.createElement("div", {
1306
+ className: "cornerstone-viewport-element",
1307
+ style: {
1308
+ height: '100%',
1309
+ width: '100%'
1310
+ },
1311
+ onContextMenu: e => e.preventDefault(),
1312
+ onMouseDown: e => e.preventDefault(),
1313
+ ref: elementRef
1314
+ }), /*#__PURE__*/react.createElement(Overlays_CornerstoneOverlays, {
1315
+ viewportIndex: viewportIndex,
1316
+ toolBarService: toolbarService,
1317
+ element: elementRef.current,
1318
+ scrollbarHeight: scrollbarHeight,
1319
+ servicesManager: servicesManager
1320
+ }), isCineEnabled && /*#__PURE__*/react.createElement(ui_src/* CinePlayer */.H6, {
1321
+ className: "absolute left-1/2 -translate-x-1/2 bottom-3",
1322
+ isPlaying: isPlaying,
1323
+ onClose: handleCineClose,
1324
+ onPlayPauseChange: isPlaying => cineService.setCine({
1325
+ id: activeViewportIndex,
1326
+ isPlaying
1327
+ }),
1328
+ onFrameRateChange: frameRate => cineService.setCine({
1329
+ id: activeViewportIndex,
1330
+ frameRate
1331
+ })
1332
+ })), /*#__PURE__*/react.createElement("div", {
1333
+ className: "absolute w-full"
1334
+ }, viewportDialogState.viewportIndex === viewportIndex && /*#__PURE__*/react.createElement(ui_src/* Notification */.P_, {
1335
+ id: "viewport-notification",
1336
+ message: viewportDialogState.message,
1337
+ type: viewportDialogState.type,
1338
+ actions: viewportDialogState.actions,
1339
+ onSubmit: viewportDialogState.onSubmit,
1340
+ onOutsideClick: viewportDialogState.onOutsideClick
1341
+ })));
1342
+ }, areEqual);
1343
+ function _subscribeToJumpToMeasurementEvents(measurementService, displaySetService, elementRef, viewportIndex, displaySets, viewportGridService, cornerstoneViewportService) {
1344
+ const displaysUIDs = displaySets.map(displaySet => displaySet.displaySetInstanceUID);
1345
+ const {
1346
+ unsubscribe
1347
+ } = measurementService.subscribe(src.MeasurementService.EVENTS.JUMP_TO_MEASUREMENT_VIEWPORT, props => {
1348
+ cacheJumpToMeasurementEvent = props;
1349
+ const {
1350
+ viewportIndex: jumpIndex,
1351
+ measurement,
1352
+ isConsumed
1353
+ } = props;
1354
+ if (!measurement || isConsumed) return;
1355
+ if (cacheJumpToMeasurementEvent.cornerstoneViewport === undefined) {
1356
+ // Decide on which viewport should handle this
1357
+ cacheJumpToMeasurementEvent.cornerstoneViewport = cornerstoneViewportService.getViewportIndexToJump(jumpIndex, measurement.displaySetInstanceUID, {
1358
+ referencedImageId: measurement.referencedImageId
1359
+ });
1360
+ }
1361
+ if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportIndex) {
1362
+ return;
1363
+ }
1364
+ _jumpToMeasurement(measurement, elementRef, viewportIndex, measurementService, displaySetService, viewportGridService, cornerstoneViewportService);
1365
+ });
1366
+ return unsubscribe;
1367
+ }
1368
+
1369
+ // Check if there is a queued jumpToMeasurement event
1370
+ function _checkForCachedJumpToMeasurementEvents(measurementService, displaySetService, elementRef, viewportIndex, displaySets, viewportGridService, cornerstoneViewportService) {
1371
+ if (!cacheJumpToMeasurementEvent) return;
1372
+ if (cacheJumpToMeasurementEvent.isConsumed) {
1373
+ cacheJumpToMeasurementEvent = null;
1374
+ return;
1375
+ }
1376
+ const displaysUIDs = displaySets.map(displaySet => displaySet.displaySetInstanceUID);
1377
+ if (!displaysUIDs?.length) return;
1378
+
1379
+ // Jump to measurement if the measurement exists
1380
+ const {
1381
+ measurement
1382
+ } = cacheJumpToMeasurementEvent;
1383
+ if (measurement && elementRef) {
1384
+ if (displaysUIDs.includes(measurement?.displaySetInstanceUID)) {
1385
+ _jumpToMeasurement(measurement, elementRef, viewportIndex, measurementService, displaySetService, viewportGridService, cornerstoneViewportService);
1386
+ }
1387
+ }
1388
+ }
1389
+ function _jumpToMeasurement(measurement, targetElementRef, viewportIndex, measurementService, displaySetService, viewportGridService, cornerstoneViewportService) {
1390
+ const targetElement = targetElementRef.current;
1391
+ const {
1392
+ displaySetInstanceUID,
1393
+ SOPInstanceUID,
1394
+ frameNumber
1395
+ } = measurement;
1396
+ if (!SOPInstanceUID) {
1397
+ console.warn('cannot jump in a non-acquisition plane measurements yet');
1398
+ return;
1399
+ }
1400
+ const referencedDisplaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
1401
+
1402
+ // Todo: setCornerstoneMeasurementActive should be handled by the toolGroupManager
1403
+ // to set it properly
1404
+ // setCornerstoneMeasurementActive(measurement);
1405
+
1406
+ viewportGridService.setActiveViewportIndex(viewportIndex);
1407
+ const enabledElement = (0,dist_esm.getEnabledElement)(targetElement);
1408
+ const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(viewportIndex);
1409
+ if (enabledElement) {
1410
+ // See how the jumpToSlice() of Cornerstone3D deals with imageIdx param.
1411
+ const viewport = enabledElement.viewport;
1412
+ let imageIdIndex = 0;
1413
+ let viewportCameraDirectionMatch = true;
1414
+ if (viewport instanceof dist_esm.StackViewport) {
1415
+ const imageIds = viewport.getImageIds();
1416
+ imageIdIndex = imageIds.findIndex(imageId => {
1417
+ const {
1418
+ SOPInstanceUID: aSOPInstanceUID,
1419
+ frameNumber: aFrameNumber
1420
+ } = (0,getSOPInstanceAttributes/* default */.Z)(imageId);
1421
+ return aSOPInstanceUID === SOPInstanceUID && (!frameNumber || frameNumber === aFrameNumber);
1422
+ });
1423
+ } else {
1424
+ // for volume viewport we can't rely on the imageIdIndex since it can be
1425
+ // a reconstructed view that doesn't match the original slice numbers etc.
1426
+ const {
1427
+ viewPlaneNormal: measurementViewPlane
1428
+ } = measurement.metadata;
1429
+ imageIdIndex = referencedDisplaySet.images.findIndex(i => i.SOPInstanceUID === SOPInstanceUID);
1430
+ const {
1431
+ viewPlaneNormal: viewportViewPlane
1432
+ } = viewport.getCamera();
1433
+
1434
+ // should compare abs for both planes since the direction can be flipped
1435
+ if (measurementViewPlane && !dist_esm.utilities.isEqual(measurementViewPlane.map(Math.abs), viewportViewPlane.map(Math.abs))) {
1436
+ viewportCameraDirectionMatch = false;
1437
+ }
1438
+ }
1439
+ if (!viewportCameraDirectionMatch || imageIdIndex === -1) {
1440
+ return;
1441
+ }
1442
+ esm.utilities.jumpToSlice(targetElement, {
1443
+ imageIndex: imageIdIndex
1444
+ });
1445
+ esm.annotation.selection.setAnnotationSelected(measurement.uid);
1446
+ // Jump to measurement consumed, remove.
1447
+ cacheJumpToMeasurementEvent?.consume?.();
1448
+ cacheJumpToMeasurementEvent = null;
1449
+ }
1450
+ }
1451
+
1452
+ // Component displayName
1453
+ OHIFCornerstoneViewport.displayName = 'OHIFCornerstoneViewport';
1454
+ OHIFCornerstoneViewport.propTypes = {
1455
+ viewportIndex: (prop_types_default()).number.isRequired,
1456
+ displaySets: (prop_types_default()).array.isRequired,
1457
+ dataSource: (prop_types_default()).object.isRequired,
1458
+ viewportOptions: (prop_types_default()).object,
1459
+ displaySetOptions: prop_types_default().arrayOf((prop_types_default()).any),
1460
+ servicesManager: (prop_types_default()).object.isRequired,
1461
+ onElementEnabled: (prop_types_default()).func,
1462
+ // Note: you SHOULD NOT use the initialImageIdOrIndex for manipulation
1463
+ // of the imageData in the OHIFCornerstoneViewport. This prop is used
1464
+ // to set the initial state of the viewport's first image to render
1465
+ initialImageIdOrIndex: prop_types_default().oneOfType([(prop_types_default()).string, (prop_types_default()).number])
1466
+ };
1467
+ /* harmony default export */ const Viewport_OHIFCornerstoneViewport = (OHIFCornerstoneViewport);
1468
+
1469
+ /***/ })
1470
+
1471
+ }]);