@ohif/app 3.8.0-beta.7 → 3.8.0-beta.70

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 (93) hide show
  1. package/dist/{220.bundle.f7e1c96c94245e70f2be.js → 109.bundle.b4fee2a22b622839baf5.js} +4466 -3715
  2. package/dist/{471.bundle.49c8d281adbae4a2c4df.js → 121.bundle.21827fec690c01ee9ab3.js} +85 -112
  3. package/dist/{19.bundle.e5579df6d7b74af50b1d.js → 155.bundle.0dabe8513b605b01ac3d.js} +334 -287
  4. package/dist/{687.bundle.9d0330ea5d61fe3117da.js → 164.bundle.0b1a2be351543c1433e8.js} +22 -38
  5. package/dist/17dd54813d5acc10bf8f.wasm +0 -0
  6. package/dist/{506.bundle.ab8226d3d81abe874544.js → 188.bundle.81e83b073b6fd4ae0058.js} +23 -28
  7. package/dist/191.bundle.7d89c921abefd1140d50.js +30360 -0
  8. package/dist/{221.bundle.c2dc03d8fa4235dc1285.js → 2.bundle.04dbbf67a52fe109749c.js} +351 -546
  9. package/dist/20fc4c659b85ccd2a9c0.wasm +0 -0
  10. package/dist/290.bundle.952de53057f98e2c5ef0.js +8883 -0
  11. package/dist/{451.bundle.57c21db5d003c75e9d61.js → 295.bundle.3a0d5062d65296c4bf5d.js} +102 -127
  12. package/dist/{125.bundle.253395f320b72180da63.js → 297.bundle.194d8985ab974839b5b6.js} +7 -8
  13. package/dist/{202.bundle.d3490836f71e001dd30f.js → 342.bundle.6e49f63ea7cea4645c0a.js} +544 -860
  14. package/dist/41.bundle.6ec0794a483e9a30eb94.js +831 -0
  15. package/dist/425.bundle.ffcdde2143a5757926b9.js +2957 -0
  16. package/dist/425.css +2 -0
  17. package/dist/{126.bundle.42df2dafc9c0310da188.js → 448.bundle.9177b9d909654efbc8d5.js} +316 -427
  18. package/dist/{957.bundle.9ea4506963ef8b2d84ba.js → 504.bundle.993d7e2dec36257d4ce4.js} +14338 -27291
  19. package/dist/{886.bundle.c8dd3ecc42a4253de278.js → 530.bundle.566bfd08dccb4cf6d98b.js} +75 -105
  20. package/dist/{250.bundle.aea3335667054bdefe36.js → 544.bundle.1110b24e96863d719a95.js} +39 -56
  21. package/dist/{663.bundle.9f359963019cd8ccf8f9.js → 559.bundle.4f111410af43324629ca.js} +151 -147
  22. package/dist/{181.bundle.a62b9f0ec692299acb35.js → 574.bundle.83afbc7922736fc6846d.js} +1246 -289
  23. package/dist/{181.css → 574.css} +1 -1
  24. package/dist/{410.bundle.38c9d3820e152e89288e.js → 594.bundle.ffeebda1bb9a81182a80.js} +183 -221
  25. package/dist/{776.bundle.004382036bdbd8ee2b95.js → 595.bundle.1c1a50c4ff87763b786a.js} +3128 -1028
  26. package/dist/{774.bundle.4b2dc46a35012b898e1a.js → 644.bundle.1e77691d2eeb96a423b0.js} +1852 -8945
  27. package/dist/699.bundle.db05df7b8e2ad605e928.js +767 -0
  28. package/dist/{359.bundle.8abe0036a7bf6b5fd115.js → 724.bundle.eada9d6c23678a5a2947.js} +130 -254
  29. package/dist/{757.bundle.ec8301d8e70d2b990f65.js → 726.bundle.c8de818cf1a3ff0cf7d2.js} +512 -879
  30. package/dist/{530.bundle.a03b6f942ace3e1baa1e.js → 835.bundle.15aff0b7433bb0dd6d6d.js} +37 -30
  31. package/dist/{822.bundle.82cdc418f8f56da6060b.js → 862.bundle.959ef65b18c1d3b5e2b4.js} +77 -96
  32. package/dist/{236.bundle.c9e70d55e7b2574c1ecd.js → 889.bundle.67c6e5f988c9b1d289ef.js} +198 -197
  33. package/dist/{342.bundle.d9668551811e3a88aaa4.js → 90.bundle.f41c8c4fc78cdfd4de30.js} +1430 -1055
  34. package/dist/{281.bundle.16a2933086a57e60c96c.js → 905.bundle.eb821474b36b96b897f9.js} +155 -122
  35. package/dist/{814.bundle.a1aba9c1e3d336008351.js → 907.bundle.ca904d9747480a0e4bf1.js} +16 -30
  36. package/dist/{417.bundle.af0a207c29b109f84159.js → 931.bundle.d270a1fda9a2836c3cc5.js} +26 -26
  37. package/dist/{686.bundle.dccef1f36e4bc79bcc48.js → 939.bundle.9d93b2e47c52338747a2.js} +7 -8
  38. package/dist/{12.bundle.37a8b47d2ae587cb9226.js → 961.bundle.65967b1a4af002af1d1d.js} +16 -31
  39. package/dist/987.bundle.6bdfb3cd8762b8889632.js +122950 -0
  40. package/dist/app-config.js +1 -0
  41. package/dist/app.bundle.css +15 -13
  42. package/dist/{app.bundle.437d085e13599d1e1ced.js → app.bundle.e21e5afd46fb064cb5de.js} +147713 -61638
  43. package/dist/assets/images/CT-AAA.png +0 -0
  44. package/dist/assets/images/CT-AAA2.png +0 -0
  45. package/dist/assets/images/CT-Air.png +0 -0
  46. package/dist/assets/images/CT-Bone.png +0 -0
  47. package/dist/assets/images/CT-Bones.png +0 -0
  48. package/dist/assets/images/CT-Cardiac.png +0 -0
  49. package/dist/assets/images/CT-Cardiac2.png +0 -0
  50. package/dist/assets/images/CT-Cardiac3.png +0 -0
  51. package/dist/assets/images/CT-Chest-Contrast-Enhanced.png +0 -0
  52. package/dist/assets/images/CT-Chest-Vessels.png +0 -0
  53. package/dist/assets/images/CT-Coronary-Arteries-2.png +0 -0
  54. package/dist/assets/images/CT-Coronary-Arteries-3.png +0 -0
  55. package/dist/assets/images/CT-Coronary-Arteries.png +0 -0
  56. package/dist/assets/images/CT-Cropped-Volume-Bone.png +0 -0
  57. package/dist/assets/images/CT-Fat.png +0 -0
  58. package/dist/assets/images/CT-Liver-Vasculature.png +0 -0
  59. package/dist/assets/images/CT-Lung.png +0 -0
  60. package/dist/assets/images/CT-MIP.png +0 -0
  61. package/dist/assets/images/CT-Muscle.png +0 -0
  62. package/dist/assets/images/CT-Pulmonary-Arteries.png +0 -0
  63. package/dist/assets/images/CT-Soft-Tissue.png +0 -0
  64. package/dist/assets/images/DTI-FA-Brain.png +0 -0
  65. package/dist/assets/images/MR-Angio.png +0 -0
  66. package/dist/assets/images/MR-Default.png +0 -0
  67. package/dist/assets/images/MR-MIP.png +0 -0
  68. package/dist/assets/images/MR-T2-Brain.png +0 -0
  69. package/dist/assets/images/VolumeRendering.png +0 -0
  70. package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
  71. package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
  72. package/dist/{dicom-microscopy-viewer.bundle.2c146384eb9466d02ff8.js → dicom-microscopy-viewer.bundle.d3a56dc9f62df5e11019.js} +3 -3
  73. package/dist/index.html +1 -1
  74. package/dist/{index.worker.e62ecca63f1a2e124230.worker.js → index.worker.64c896c4316fcd506666.worker.js} +2 -2
  75. package/dist/index.worker.64c896c4316fcd506666.worker.js.map +1 -0
  76. package/dist/polySeg.bundle.e7b4c29fb9173e8567b8.js +252 -0
  77. package/dist/serve.json +12 -0
  78. package/dist/sw.js +1 -1
  79. package/package.json +25 -22
  80. package/dist/23.bundle.e008ad788170f2ed5569.js +0 -900
  81. package/dist/604.bundle.a51f83e64004bca5f497.js +0 -1848
  82. package/dist/613.bundle.aed640a7900dbcb688f5.js +0 -532
  83. package/dist/743.bundle.489f7df3a089d4d374e1.js +0 -78007
  84. package/dist/75788f12450d4c5ed494.wasm +0 -0
  85. package/dist/775.bundle.2285e7e0e67878948c0d.js +0 -1009
  86. package/dist/788.bundle.dcd53828d1bb2ac64d04.js +0 -2682
  87. package/dist/82.bundle.5a94dd7645e5c5476f59.js +0 -1049
  88. package/dist/index.worker.e62ecca63f1a2e124230.worker.js.map +0 -1
  89. /package/dist/{19.css → 155.css} +0 -0
  90. /package/dist/{221.css → 2.css} +0 -0
  91. /package/dist/{579.css → 481.css} +0 -0
  92. /package/dist/{250.css → 544.css} +0 -0
  93. /package/dist/{776.css → 595.css} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
- (self["webpackChunk"] = self["webpackChunk"] || []).push([[181],{
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[574],{
3
3
 
4
- /***/ 86181:
4
+ /***/ 71574:
5
5
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
6
6
 
7
7
  // ESM COMPAT FLAG
@@ -13,22 +13,22 @@ __webpack_require__.d(__webpack_exports__, {
13
13
  });
14
14
 
15
15
  // EXTERNAL MODULE: ../../../node_modules/react/index.js
16
- var react = __webpack_require__(43001);
16
+ var react = __webpack_require__(41766);
17
17
  // EXTERNAL MODULE: ../../../node_modules/react-resize-detector/build/index.esm.js
18
- var index_esm = __webpack_require__(7023);
18
+ var index_esm = __webpack_require__(78668);
19
19
  // EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
20
- var prop_types = __webpack_require__(3827);
20
+ var prop_types = __webpack_require__(11374);
21
21
  var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
22
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js + 348 modules
23
- var esm = __webpack_require__(14957);
24
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 331 modules
25
- var dist_esm = __webpack_require__(3743);
26
- // EXTERNAL MODULE: ../../core/src/index.ts + 65 modules
27
- var src = __webpack_require__(71771);
28
- // EXTERNAL MODULE: ../../ui/src/index.js + 486 modules
29
- var ui_src = __webpack_require__(22582);
22
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js + 16 modules
23
+ var esm = __webpack_require__(20767);
24
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 383 modules
25
+ var dist_esm = __webpack_require__(50719);
26
+ // EXTERNAL MODULE: ../../core/src/index.ts + 68 modules
27
+ var src = __webpack_require__(85073);
28
+ // EXTERNAL MODULE: ../../ui/src/index.js + 542 modules
29
+ var ui_src = __webpack_require__(48804);
30
30
  // EXTERNAL MODULE: ../../../extensions/cornerstone/src/state.ts
31
- var state = __webpack_require__(73704);
31
+ var state = __webpack_require__(71353);
32
32
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.css
33
33
  // extracted by mini-css-extract-plugin
34
34
 
@@ -38,16 +38,15 @@ var state = __webpack_require__(73704);
38
38
 
39
39
 
40
40
 
41
- function CornerstoneImageScrollbar(_ref) {
42
- let {
43
- viewportData,
44
- viewportId,
45
- element,
46
- imageSliceData,
47
- setImageSliceData,
48
- scrollbarHeight,
49
- servicesManager
50
- } = _ref;
41
+ function CornerstoneImageScrollbar({
42
+ viewportData,
43
+ viewportId,
44
+ element,
45
+ imageSliceData,
46
+ setImageSliceData,
47
+ scrollbarHeight,
48
+ servicesManager
49
+ }) {
51
50
  const {
52
51
  cineService,
53
52
  cornerstoneViewportService
@@ -140,7 +139,7 @@ function CornerstoneImageScrollbar(_ref) {
140
139
  element.removeEventListener(dist_esm.Enums.Events.VOLUME_NEW_IMAGE, updateVolumeIndex);
141
140
  };
142
141
  }, [viewportData, element]);
143
- return /*#__PURE__*/react.createElement(ui_src/* ImageScrollbar */.Ln, {
142
+ return /*#__PURE__*/react.createElement(ui_src/* ImageScrollbar */.uq, {
144
143
  onChange: evt => onImageScrollbarChange(evt, viewportId),
145
144
  max: imageSliceData.numberOfSlices ? imageSliceData.numberOfSlices - 1 : 0,
146
145
  height: scrollbarHeight,
@@ -158,9 +157,9 @@ CornerstoneImageScrollbar.propTypes = {
158
157
  };
159
158
  /* harmony default export */ const ViewportImageScrollbar = (CornerstoneImageScrollbar);
160
159
  // EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 10 modules
161
- var gl_matrix_esm = __webpack_require__(45451);
160
+ var gl_matrix_esm = __webpack_require__(83636);
162
161
  // EXTERNAL MODULE: ../../../node_modules/moment/moment.js
163
- var moment = __webpack_require__(71271);
162
+ var moment = __webpack_require__(8291);
164
163
  var moment_default = /*#__PURE__*/__webpack_require__.n(moment);
165
164
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/utils.ts
166
165
 
@@ -183,8 +182,7 @@ function isValidNumber(value) {
183
182
  * @param {number} precision
184
183
  * @returns {number} formatted number.
185
184
  */
186
- function formatNumberPrecision(number) {
187
- let precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
185
+ function formatNumberPrecision(number, precision = 0) {
188
186
  if (number !== null) {
189
187
  return parseFloat(number).toFixed(precision);
190
188
  }
@@ -197,8 +195,7 @@ function formatNumberPrecision(number) {
197
195
  * @param {string} strFormat
198
196
  * @returns {string} formatted date.
199
197
  */
200
- function formatDICOMDate(date) {
201
- let strFormat = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'MMM D, YYYY';
198
+ function formatDICOMDate(date, strFormat = 'MMM D, YYYY') {
202
199
  return moment_default()(date, 'YYYYMMDD').format(strFormat);
203
200
  }
204
201
 
@@ -215,8 +212,7 @@ function formatDICOMDate(date) {
215
212
  * @param {string} strFormat
216
213
  * @returns {string} formatted name.
217
214
  */
218
- function formatDICOMTime(time) {
219
- let strFormat = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'HH:mm:ss';
215
+ function formatDICOMTime(time, strFormat = 'HH:mm:ss') {
220
216
  return moment_default()(time, 'HH:mm:ss').format(strFormat);
221
217
  }
222
218
 
@@ -266,104 +262,32 @@ function getCompression(imageId) {
266
262
 
267
263
 
268
264
  const EPSILON = 1e-4;
269
- /**
270
- * Window Level / Center Overlay item
271
- */
272
- function VOIOverlayItem(_ref) {
273
- let {
274
- voi,
275
- customization
276
- } = _ref;
277
- const {
278
- windowWidth,
279
- windowCenter
280
- } = voi;
281
- if (typeof windowCenter !== 'number' || typeof windowWidth !== 'number') {
282
- return null;
283
- }
284
- return /*#__PURE__*/react.createElement("div", {
285
- className: "overlay-item flex flex-row",
286
- style: {
287
- color: customization && customization.color || undefined
288
- }
289
- }, /*#__PURE__*/react.createElement("span", {
290
- className: "mr-1 shrink-0"
291
- }, "W:"), /*#__PURE__*/react.createElement("span", {
292
- className: "ml-1 mr-2 shrink-0 font-light"
293
- }, windowWidth.toFixed(0)), /*#__PURE__*/react.createElement("span", {
294
- className: "mr-1 shrink-0"
295
- }, "L:"), /*#__PURE__*/react.createElement("span", {
296
- className: "ml-1 shrink-0 font-light"
297
- }, windowCenter.toFixed(0)));
298
- }
299
-
300
- /**
301
- * Zoom Level Overlay item
302
- */
303
- function ZoomOverlayItem(_ref2) {
304
- let {
305
- scale,
306
- customization
307
- } = _ref2;
308
- return /*#__PURE__*/react.createElement("div", {
309
- className: "overlay-item flex flex-row",
310
- style: {
311
- color: customization && customization.color || undefined
312
- }
313
- }, /*#__PURE__*/react.createElement("span", {
314
- className: "mr-1 shrink-0"
315
- }, "Zoom:"), /*#__PURE__*/react.createElement("span", {
316
- className: "font-light"
317
- }, scale.toFixed(2), "x"));
318
- }
319
-
320
- /**
321
- * Instance Number Overlay Item
322
- */
323
- function InstanceNumberOverlayItem(_ref3) {
324
- let {
325
- instanceNumber,
326
- imageSliceData,
327
- customization
328
- } = _ref3;
329
- const {
330
- imageIndex,
331
- numberOfSlices
332
- } = imageSliceData;
333
- return /*#__PURE__*/react.createElement("div", {
334
- className: "overlay-item flex flex-row",
335
- style: {
336
- color: customization && customization.color || undefined
337
- }
338
- }, /*#__PURE__*/react.createElement("span", {
339
- className: "mr-1 shrink-0"
340
- }, "I:"), /*#__PURE__*/react.createElement("span", {
341
- className: "font-light"
342
- }, instanceNumber !== undefined && instanceNumber !== null ? `${instanceNumber} (${imageIndex + 1}/${numberOfSlices})` : `${imageIndex + 1}/${numberOfSlices}`));
343
- }
265
+ const OverlayItemComponents = {
266
+ 'ohif.overlayItem.windowLevel': VOIOverlayItem,
267
+ 'ohif.overlayItem.zoomLevel': ZoomOverlayItem,
268
+ 'ohif.overlayItem.instanceNumber': InstanceNumberOverlayItem
269
+ };
344
270
 
345
271
  /**
346
272
  * Customizable Viewport Overlay
347
273
  */
348
- function CustomizableViewportOverlay(_ref4) {
349
- let {
350
- element,
351
- viewportData,
352
- imageSliceData,
353
- viewportId,
354
- servicesManager
355
- } = _ref4;
274
+ function CustomizableViewportOverlay({
275
+ element,
276
+ viewportData,
277
+ imageSliceData,
278
+ viewportId,
279
+ servicesManager
280
+ }) {
356
281
  const {
357
- toolbarService,
358
282
  cornerstoneViewportService,
359
- customizationService
283
+ customizationService,
284
+ toolGroupService
360
285
  } = servicesManager.services;
361
286
  const [voi, setVOI] = (0,react.useState)({
362
287
  windowCenter: null,
363
288
  windowWidth: null
364
289
  });
365
290
  const [scale, setScale] = (0,react.useState)(1);
366
- const [activeTools, setActiveTools] = (0,react.useState)([]);
367
291
  const {
368
292
  imageIndex
369
293
  } = imageSliceData;
@@ -378,19 +302,7 @@ function CustomizableViewportOverlay(_ref4) {
378
302
  return null;
379
303
  }
380
304
  }, [viewportData, imageIndex]);
381
- const instanceNumber = (0,react.useMemo)(() => {
382
- if (viewportData != null) {
383
- return _getInstanceNumber(viewportData, viewportId, imageIndex, cornerstoneViewportService);
384
- }
385
- return null;
386
- }, [viewportData, viewportId, imageIndex, cornerstoneViewportService]);
387
-
388
- /**
389
- * Initial toolbar state
390
- */
391
- (0,react.useEffect)(() => {
392
- setActiveTools(toolbarService.getActiveTools());
393
- }, []);
305
+ const instanceNumber = (0,react.useMemo)(() => viewportData ? getInstanceNumber(viewportData, viewportId, imageIndex, cornerstoneViewportService) : null, [viewportData, viewportId, imageIndex, cornerstoneViewportService]);
394
306
 
395
307
  /**
396
308
  * Updating the VOI when the viewport changes its voi
@@ -457,21 +369,6 @@ function CustomizableViewportOverlay(_ref4) {
457
369
  element.removeEventListener(dist_esm.Enums.Events.CAMERA_MODIFIED, updateScale);
458
370
  };
459
371
  }, [viewportId, viewportData, cornerstoneViewportService, element]);
460
-
461
- /**
462
- * Updating the active tools when the toolbar changes
463
- */
464
- // Todo: this should act on the toolGroups instead of the toolbar state
465
- (0,react.useEffect)(() => {
466
- const {
467
- unsubscribe
468
- } = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, () => {
469
- setActiveTools(toolbarService.getActiveTools());
470
- });
471
- return () => {
472
- unsubscribe();
473
- };
474
- }, [toolbarService]);
475
372
  const _renderOverlayItem = (0,react.useCallback)(item => {
476
373
  const overlayItemProps = {
477
374
  element,
@@ -487,17 +384,19 @@ function CustomizableViewportOverlay(_ref4) {
487
384
  formatNumberPrecision: formatNumberPrecision
488
385
  },
489
386
  instance,
490
- // calculated
491
387
  voi,
492
388
  scale,
493
389
  instanceNumber
494
390
  };
495
- if (item.customizationType === 'ohif.overlayItem.windowLevel') {
496
- return /*#__PURE__*/react.createElement(VOIOverlayItem, overlayItemProps);
497
- } else if (item.customizationType === 'ohif.overlayItem.zoomLevel') {
498
- return /*#__PURE__*/react.createElement(ZoomOverlayItem, overlayItemProps);
499
- } else if (item.customizationType === 'ohif.overlayItem.instanceNumber') {
500
- return /*#__PURE__*/react.createElement(InstanceNumberOverlayItem, overlayItemProps);
391
+ if (!item) {
392
+ return null;
393
+ }
394
+ const {
395
+ customizationType
396
+ } = item;
397
+ const OverlayItemComponent = OverlayItemComponents[customizationType];
398
+ if (OverlayItemComponent) {
399
+ return /*#__PURE__*/react.createElement(OverlayItemComponent, overlayItemProps);
501
400
  } else {
502
401
  const renderItem = customizationService.transform(item);
503
402
  if (typeof renderItem.content === 'function') {
@@ -505,41 +404,62 @@ function CustomizableViewportOverlay(_ref4) {
505
404
  }
506
405
  }
507
406
  }, [element, viewportData, imageSliceData, viewportId, servicesManager, customizationService, instance, voi, scale, instanceNumber]);
508
- const getTopLeftContent = (0,react.useCallback)(() => {
509
- const items = topLeftCustomization?.items || [{
407
+ const getContent = (0,react.useCallback)((customization, defaultItems, keyPrefix) => {
408
+ const items = customization?.items ?? defaultItems;
409
+ return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, index) => /*#__PURE__*/react.createElement("div", {
410
+ key: `${keyPrefix}_${index}`
411
+ }, item?.condition ? item.condition({
412
+ instance,
413
+ formatters: {
414
+ formatDate: formatDICOMDate
415
+ }
416
+ }) ? _renderOverlayItem(item) : null : _renderOverlayItem(item))));
417
+ }, [_renderOverlayItem]);
418
+ return /*#__PURE__*/react.createElement(ui_src/* ViewportOverlay */.pU, {
419
+ topLeft:
420
+ /**
421
+ * Inline default overlay items for a more standard expansion
422
+ */
423
+ getContent(topLeftCustomization, [{
424
+ id: 'StudyDate',
425
+ customizationType: 'ohif.overlayItem',
426
+ label: '',
427
+ title: 'Study date',
428
+ condition: ({
429
+ instance
430
+ }) => instance && instance.StudyDate,
431
+ contentF: ({
432
+ instance,
433
+ formatters: {
434
+ formatDate
435
+ }
436
+ }) => formatDate(instance.StudyDate)
437
+ }, {
438
+ id: 'SeriesDescription',
439
+ customizationType: 'ohif.overlayItem',
440
+ label: '',
441
+ title: 'Series description',
442
+ attribute: 'SeriesDescription',
443
+ condition: ({
444
+ instance
445
+ }) => instance && instance.SeriesDescription
446
+ }], 'topLeftOverlayItem'),
447
+ topRight: getContent(topRightCustomization, [], 'topRightOverlayItem'),
448
+ bottomLeft: getContent(bottomLeftCustomization, [{
510
449
  id: 'WindowLevel',
511
450
  customizationType: 'ohif.overlayItem.windowLevel'
512
- }];
513
- return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
514
- key: `topLeftOverlayItem_${i}`
515
- }, _renderOverlayItem(item))));
516
- }, [topLeftCustomization, _renderOverlayItem]);
517
- const getTopRightContent = (0,react.useCallback)(() => {
518
- const items = topRightCustomization?.items || [{
519
- id: 'InstanceNmber',
451
+ }, {
452
+ id: 'ZoomLevel',
453
+ customizationType: 'ohif.overlayItem.zoomLevel',
454
+ condition: () => {
455
+ const activeToolName = toolGroupService.getActiveToolForViewport(viewportId);
456
+ return activeToolName === 'Zoom';
457
+ }
458
+ }], 'bottomLeftOverlayItem'),
459
+ bottomRight: getContent(bottomRightCustomization, [{
460
+ id: 'InstanceNumber',
520
461
  customizationType: 'ohif.overlayItem.instanceNumber'
521
- }];
522
- return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
523
- key: `topRightOverlayItem_${i}`
524
- }, _renderOverlayItem(item))));
525
- }, [topRightCustomization, _renderOverlayItem]);
526
- const getBottomLeftContent = (0,react.useCallback)(() => {
527
- const items = bottomLeftCustomization?.items || [];
528
- return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
529
- key: `bottomLeftOverlayItem_${i}`
530
- }, _renderOverlayItem(item))));
531
- }, [bottomLeftCustomization, _renderOverlayItem]);
532
- const getBottomRightContent = (0,react.useCallback)(() => {
533
- const items = bottomRightCustomization?.items || [];
534
- return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, i) => /*#__PURE__*/react.createElement("div", {
535
- key: `bottomRightOverlayItem_${i}`
536
- }, _renderOverlayItem(item))));
537
- }, [bottomRightCustomization, _renderOverlayItem]);
538
- return /*#__PURE__*/react.createElement(ui_src/* ViewportOverlay */.No, {
539
- topLeft: getTopLeftContent(),
540
- topRight: getTopRightContent(),
541
- bottomLeft: getBottomLeftContent(),
542
- bottomRight: getBottomRightContent()
462
+ }], 'bottomRightOverlayItem')
543
463
  });
544
464
  }
545
465
  function _getViewportInstance(viewportData, imageIndex) {
@@ -555,18 +475,18 @@ function _getViewportInstance(viewportData, imageIndex) {
555
475
  }
556
476
  return imageId ? dist_esm.metaData.get('instance', imageId) || {} : {};
557
477
  }
558
- function _getInstanceNumber(viewportData, viewportId, imageIndex, cornerstoneViewportService) {
478
+ const getInstanceNumber = (viewportData, viewportId, imageIndex, cornerstoneViewportService) => {
559
479
  let instanceNumber;
560
- if (viewportData.viewportType === dist_esm.Enums.ViewportType.STACK) {
561
- instanceNumber = _getInstanceNumberFromStack(viewportData, imageIndex);
562
- if (!instanceNumber && instanceNumber !== 0) {
563
- return null;
564
- }
565
- } else if (viewportData.viewportType === dist_esm.Enums.ViewportType.ORTHOGRAPHIC) {
566
- instanceNumber = _getInstanceNumberFromVolume(viewportData, imageIndex, viewportId, cornerstoneViewportService);
480
+ switch (viewportData.viewportType) {
481
+ case dist_esm.Enums.ViewportType.STACK:
482
+ instanceNumber = _getInstanceNumberFromStack(viewportData, imageIndex);
483
+ break;
484
+ case dist_esm.Enums.ViewportType.ORTHOGRAPHIC:
485
+ instanceNumber = _getInstanceNumberFromVolume(viewportData, viewportId, cornerstoneViewportService);
486
+ break;
567
487
  }
568
- return instanceNumber;
569
- }
488
+ return instanceNumber ?? null;
489
+ };
570
490
  function _getInstanceNumberFromStack(viewportData, imageIndex) {
571
491
  const imageIds = viewportData.data.imageIds;
572
492
  const imageId = imageIds[imageIndex];
@@ -612,8 +532,8 @@ function _getInstanceNumberFromVolume(viewportData, viewportId, cornerstoneViewp
612
532
  const scanAxisNormal = direction.slice(6, 9);
613
533
 
614
534
  // check if viewPlaneNormal is parallel to scanAxisNormal
615
- const cross = gl_matrix_esm/* vec3.cross */.R3.cross(gl_matrix_esm/* vec3.create */.R3.create(), viewPlaneNormal, scanAxisNormal);
616
- const isAcquisitionPlane = gl_matrix_esm/* vec3.length */.R3.length(cross) < EPSILON;
535
+ const cross = gl_matrix_esm/* vec3.cross */.eR.cross(gl_matrix_esm/* vec3.create */.eR.create(), viewPlaneNormal, scanAxisNormal);
536
+ const isAcquisitionPlane = gl_matrix_esm/* vec3.length */.eR.length(cross) < EPSILON;
617
537
  if (isAcquisitionPlane) {
618
538
  const imageId = imageIds[imageIndex];
619
539
  if (!imageId) {
@@ -625,6 +545,75 @@ function _getInstanceNumberFromVolume(viewportData, viewportId, cornerstoneViewp
625
545
  return parseInt(instanceNumber);
626
546
  }
627
547
  }
548
+
549
+ /**
550
+ * Window Level / Center Overlay item
551
+ */
552
+ function VOIOverlayItem({
553
+ voi,
554
+ customization
555
+ }) {
556
+ const {
557
+ windowWidth,
558
+ windowCenter
559
+ } = voi;
560
+ if (typeof windowCenter !== 'number' || typeof windowWidth !== 'number') {
561
+ return null;
562
+ }
563
+ return /*#__PURE__*/react.createElement("div", {
564
+ className: "overlay-item flex flex-row",
565
+ style: {
566
+ color: customization && customization.color || undefined
567
+ }
568
+ }, /*#__PURE__*/react.createElement("span", {
569
+ className: "mr-1 shrink-0"
570
+ }, "W:"), /*#__PURE__*/react.createElement("span", {
571
+ className: "ml-1 mr-2 shrink-0"
572
+ }, windowWidth.toFixed(0)), /*#__PURE__*/react.createElement("span", {
573
+ className: "mr-1 shrink-0"
574
+ }, "L:"), /*#__PURE__*/react.createElement("span", {
575
+ className: "ml-1 shrink-0"
576
+ }, windowCenter.toFixed(0)));
577
+ }
578
+
579
+ /**
580
+ * Zoom Level Overlay item
581
+ */
582
+ function ZoomOverlayItem({
583
+ scale,
584
+ customization
585
+ }) {
586
+ return /*#__PURE__*/react.createElement("div", {
587
+ className: "overlay-item flex flex-row",
588
+ style: {
589
+ color: customization && customization.color || undefined
590
+ }
591
+ }, /*#__PURE__*/react.createElement("span", {
592
+ className: "mr-1 shrink-0"
593
+ }, "Zoom:"), /*#__PURE__*/react.createElement("span", null, scale.toFixed(2), "x"));
594
+ }
595
+
596
+ /**
597
+ * Instance Number Overlay Item
598
+ */
599
+ function InstanceNumberOverlayItem({
600
+ instanceNumber,
601
+ imageSliceData,
602
+ customization
603
+ }) {
604
+ const {
605
+ imageIndex,
606
+ numberOfSlices
607
+ } = imageSliceData;
608
+ return /*#__PURE__*/react.createElement("div", {
609
+ className: "overlay-item flex flex-row",
610
+ style: {
611
+ color: customization && customization.color || undefined
612
+ }
613
+ }, /*#__PURE__*/react.createElement("span", {
614
+ className: "mr-1 shrink-0"
615
+ }, "I:"), /*#__PURE__*/react.createElement("span", null, instanceNumber !== undefined && instanceNumber !== null ? `${instanceNumber} (${imageIndex + 1}/${numberOfSlices})` : `${imageIndex + 1}/${numberOfSlices}`));
616
+ }
628
617
  CustomizableViewportOverlay.propTypes = {
629
618
  viewportData: (prop_types_default()).object,
630
619
  imageIndex: (prop_types_default()).number,
@@ -632,7 +621,7 @@ CustomizableViewportOverlay.propTypes = {
632
621
  };
633
622
  /* harmony default export */ const Overlays_CustomizableViewportOverlay = (CustomizableViewportOverlay);
634
623
  // EXTERNAL MODULE: ../../../node_modules/classnames/index.js
635
- var classnames = __webpack_require__(44921);
624
+ var classnames = __webpack_require__(61466);
636
625
  var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
637
626
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/Overlays/ViewportOrientationMarkers.css
638
627
  // extracted by mini-css-extract-plugin
@@ -649,15 +638,14 @@ const {
649
638
  getOrientationStringLPS,
650
639
  invertOrientationStringLPS
651
640
  } = esm.utilities.orientation;
652
- function ViewportOrientationMarkers(_ref) {
653
- let {
654
- element,
655
- viewportData,
656
- imageSliceData,
657
- viewportId,
658
- servicesManager,
659
- orientationMarkers = ['top', 'left']
660
- } = _ref;
641
+ function ViewportOrientationMarkers({
642
+ element,
643
+ viewportData,
644
+ imageSliceData,
645
+ viewportId,
646
+ servicesManager,
647
+ orientationMarkers = ['top', 'left']
648
+ }) {
661
649
  // Rotation is in degrees
662
650
  const [rotation, setRotation] = (0,react.useState)(0);
663
651
  const [flipHorizontal, setFlipHorizontal] = (0,react.useState)(false);
@@ -715,8 +703,8 @@ function ViewportOrientationMarkers(_ref) {
715
703
  viewUp,
716
704
  viewPlaneNormal
717
705
  } = viewport.getCamera();
718
- const viewRight = gl_matrix_esm/* vec3.create */.R3.create();
719
- gl_matrix_esm/* vec3.cross */.R3.cross(viewRight, viewUp, viewPlaneNormal);
706
+ const viewRight = gl_matrix_esm/* vec3.create */.eR.create();
707
+ gl_matrix_esm/* vec3.cross */.eR.cross(viewRight, viewUp, viewPlaneNormal);
720
708
  columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]];
721
709
  rowCosines = viewRight;
722
710
  }
@@ -729,20 +717,15 @@ function ViewportOrientationMarkers(_ref) {
729
717
  console.log('ViewportOrientationMarkers::No viewport');
730
718
  return null;
731
719
  }
732
- const backgroundColor = ohifViewport.getViewportOptions().background;
733
-
734
- // Todo: probably this can be done in a better way in which we identify bright
735
- // background
736
- const isLight = backgroundColor ? dist_esm.utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
737
720
  return orientationMarkers.map((m, index) => /*#__PURE__*/react.createElement("div", {
738
- className: classnames_default()(`${m}-mid orientation-marker`, isLight ? 'text-[#726F7E]' : 'text-[#ccc]'),
721
+ className: classnames_default()('overlay-text', `${m}-mid orientation-marker`, 'text-aqua-pale', 'text-[13px]', 'leading-5'),
739
722
  key: `${m}-mid orientation-marker`
740
723
  }, /*#__PURE__*/react.createElement("div", {
741
724
  className: "orientation-marker-value"
742
725
  }, markers[m])));
743
726
  }, [viewportData, imageSliceData, rotation, flipVertical, flipHorizontal, orientationMarkers, element]);
744
727
  return /*#__PURE__*/react.createElement("div", {
745
- className: "ViewportOrientationMarkers noselect"
728
+ className: "ViewportOrientationMarkers select-none"
746
729
  }, markers);
747
730
  }
748
731
  ViewportOrientationMarkers.propTypes = {
@@ -818,11 +801,10 @@ function _getOrientationMarkers(rowCosines, columnCosines, rotation, flipVertica
818
801
 
819
802
 
820
803
 
821
- function ViewportImageSliceLoadingIndicator(_ref) {
822
- let {
823
- viewportData,
824
- element
825
- } = _ref;
804
+ function ViewportImageSliceLoadingIndicator({
805
+ viewportData,
806
+ element
807
+ }) {
826
808
  const [loading, setLoading] = (0,react.useState)(false);
827
809
  const [error, setError] = (0,react.useState)(false);
828
810
  const loadIndicatorRef = (0,react.useRef)(null);
@@ -961,48 +943,34 @@ function CornerstoneOverlays(props) {
961
943
  }
962
944
  /* harmony default export */ const Overlays_CornerstoneOverlays = (CornerstoneOverlays);
963
945
  // EXTERNAL MODULE: ../../../extensions/cornerstone/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js
964
- var getSOPInstanceAttributes = __webpack_require__(87172);
946
+ var getSOPInstanceAttributes = __webpack_require__(1663);
965
947
  // EXTERNAL MODULE: ./state/index.js + 1 modules
966
- var state_0 = __webpack_require__(62657);
948
+ var state_0 = __webpack_require__(15575);
967
949
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/CinePlayer/CinePlayer.tsx
968
950
 
969
951
 
970
952
 
971
953
 
972
- function WrappedCinePlayer(_ref) {
973
- let {
974
- enabledVPElement,
975
- viewportId,
976
- servicesManager
977
- } = _ref;
954
+ function WrappedCinePlayer({
955
+ enabledVPElement,
956
+ viewportId,
957
+ servicesManager
958
+ }) {
978
959
  const {
979
- toolbarService,
980
960
  customizationService,
981
961
  displaySetService,
982
- viewportGridService,
983
- cineService
962
+ viewportGridService
984
963
  } = servicesManager.services;
985
964
  const [{
986
965
  isCineEnabled,
987
966
  cines
988
- }] = (0,ui_src/* useCine */.vQ)();
967
+ }, api] = (0,ui_src/* useCine */.tq)();
989
968
  const [newStackFrameRate, setNewStackFrameRate] = (0,react.useState)(24);
990
- const [appConfig] = (0,state_0/* useAppConfig */.M)();
969
+ const [appConfig] = (0,state_0/* useAppConfig */.r)();
970
+ const isMountedRef = (0,react.useRef)(null);
991
971
  const {
992
- component: CinePlayerComponent = ui_src/* CinePlayer */.H6
972
+ component: CinePlayerComponent = ui_src/* CinePlayer */.F0
993
973
  } = customizationService.get('cinePlayer') ?? {};
994
- const handleCineClose = () => {
995
- toolbarService.recordInteraction({
996
- groupId: 'MoreTools',
997
- interactionType: 'toggle',
998
- commands: [{
999
- commandName: 'toggleCine',
1000
- commandOptions: {},
1001
- toolName: 'cine',
1002
- context: 'CORNERSTONE'
1003
- }]
1004
- });
1005
- };
1006
974
  const cineHandler = () => {
1007
975
  if (!cines || !cines[viewportId] || !enabledVPElement) {
1008
976
  return;
@@ -1012,11 +980,11 @@ function WrappedCinePlayer(_ref) {
1012
980
  const frameRate = cine.frameRate || 24;
1013
981
  const validFrameRate = Math.max(frameRate, 1);
1014
982
  if (isPlaying) {
1015
- cineService.playClip(enabledVPElement, {
983
+ api.playClip(enabledVPElement, {
1016
984
  framesPerSecond: validFrameRate
1017
985
  });
1018
986
  } else {
1019
- cineService.stopClip(enabledVPElement);
987
+ api.stopClip(enabledVPElement);
1020
988
  }
1021
989
  };
1022
990
  const newStackCineHandler = (0,react.useCallback)(() => {
@@ -1038,19 +1006,22 @@ function WrappedCinePlayer(_ref) {
1038
1006
  }
1039
1007
  });
1040
1008
  if (isPlaying) {
1041
- cineService.setIsCineEnabled(isPlaying);
1009
+ api.setIsCineEnabled(isPlaying);
1042
1010
  }
1043
- cineService.setCine({
1011
+ api.setCine({
1044
1012
  id: viewportId,
1045
1013
  isPlaying,
1046
1014
  frameRate
1047
1015
  });
1048
1016
  setNewStackFrameRate(frameRate);
1049
- }, [cineService, displaySetService, viewportId, viewportGridService, cines]);
1017
+ }, [displaySetService, viewportId, viewportGridService, cines]);
1050
1018
  (0,react.useEffect)(() => {
1019
+ isMountedRef.current = true;
1051
1020
  dist_esm.eventTarget.addEventListener(dist_esm.Enums.Events.STACK_VIEWPORT_NEW_STACK, newStackCineHandler);
1052
1021
  return () => {
1053
- cineService.setCine({
1022
+ isMountedRef.current = false;
1023
+ api.stopClip(enabledVPElement);
1024
+ api.setCine({
1054
1025
  id: viewportId,
1055
1026
  isPlaying: false
1056
1027
  });
@@ -1058,28 +1029,35 @@ function WrappedCinePlayer(_ref) {
1058
1029
  };
1059
1030
  }, [enabledVPElement, newStackCineHandler]);
1060
1031
  (0,react.useEffect)(() => {
1061
- if (!cines || !cines[viewportId] || !enabledVPElement) {
1032
+ if (!cines || !cines[viewportId] || !enabledVPElement || !isMountedRef.current) {
1062
1033
  return;
1063
1034
  }
1064
1035
  cineHandler();
1065
1036
  return () => {
1066
- if (enabledVPElement && cines?.[viewportId]?.isPlaying) {
1067
- cineService.stopClip(enabledVPElement);
1068
- }
1037
+ api.stopClip(enabledVPElement);
1069
1038
  };
1070
- }, [cines, viewportId, cineService, enabledVPElement, cineHandler]);
1039
+ }, [cines, viewportId, enabledVPElement, cineHandler]);
1071
1040
  const cine = cines[viewportId];
1072
1041
  const isPlaying = cine && cine.isPlaying || false;
1073
1042
  return isCineEnabled && /*#__PURE__*/react.createElement(CinePlayerComponent, {
1074
1043
  className: "absolute left-1/2 bottom-3 -translate-x-1/2",
1075
1044
  frameRate: newStackFrameRate,
1076
1045
  isPlaying: isPlaying,
1077
- onClose: handleCineClose,
1078
- onPlayPauseChange: isPlaying => cineService.setCine({
1079
- id: viewportId,
1080
- isPlaying
1081
- }),
1082
- onFrameRateChange: frameRate => cineService.setCine({
1046
+ onClose: () => {
1047
+ // also stop the clip
1048
+ api.setCine({
1049
+ id: viewportId,
1050
+ isPlaying: false
1051
+ });
1052
+ api.setIsCineEnabled(false);
1053
+ },
1054
+ onPlayPauseChange: isPlaying => {
1055
+ api.setCine({
1056
+ id: viewportId,
1057
+ isPlaying
1058
+ });
1059
+ },
1060
+ onFrameRateChange: frameRate => api.setCine({
1083
1061
  id: viewportId,
1084
1062
  frameRate
1085
1063
  })
@@ -1089,6 +1067,908 @@ function WrappedCinePlayer(_ref) {
1089
1067
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/CinePlayer/index.ts
1090
1068
 
1091
1069
  /* harmony default export */ const components_CinePlayer = (CinePlayer);
1070
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/contextProviders/ViewportActionCornersProvider.tsx
1071
+ var ViewportActionCornersProvider = __webpack_require__(76255);
1072
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/OHIFViewportActionCorners.tsx
1073
+
1074
+
1075
+
1076
+ function OHIFViewportActionCorners({
1077
+ viewportId
1078
+ }) {
1079
+ const [viewportActionCornersState] = (0,ViewportActionCornersProvider/* useViewportActionCornersContext */.R4)();
1080
+ if (!viewportActionCornersState[viewportId]) {
1081
+ return null;
1082
+ }
1083
+ return /*#__PURE__*/react.createElement(ui_src/* ViewportActionCorners */.R2, {
1084
+ cornerComponents: viewportActionCornersState[viewportId]
1085
+ });
1086
+ }
1087
+ /* harmony default export */ const components_OHIFViewportActionCorners = (OHIFViewportActionCorners);
1088
+ // EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
1089
+ var es = __webpack_require__(80619);
1090
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx
1091
+
1092
+
1093
+
1094
+ function Colormap({
1095
+ colormaps,
1096
+ viewportId,
1097
+ displaySets,
1098
+ commandsManager,
1099
+ serviceManager
1100
+ }) {
1101
+ const {
1102
+ cornerstoneViewportService
1103
+ } = serviceManager.services;
1104
+ const [activeDisplaySet, setActiveDisplaySet] = (0,react.useState)(displaySets[0]);
1105
+ const [showPreview, setShowPreview] = (0,react.useState)(false);
1106
+ const [prePreviewColormap, setPrePreviewColormap] = (0,react.useState)(null);
1107
+ const showPreviewRef = (0,react.useRef)(showPreview);
1108
+ showPreviewRef.current = showPreview;
1109
+ const prePreviewColormapRef = (0,react.useRef)(prePreviewColormap);
1110
+ prePreviewColormapRef.current = prePreviewColormap;
1111
+ const activeDisplaySetRef = (0,react.useRef)(activeDisplaySet);
1112
+ activeDisplaySetRef.current = activeDisplaySet;
1113
+ const onSetColorLUT = (0,react.useCallback)(props => {
1114
+ // TODO: Better way to check if it's a fusion
1115
+ const oneOpacityColormaps = ['Grayscale', 'X Ray'];
1116
+ const opacity = displaySets.length > 1 && !oneOpacityColormaps.includes(props.colormap.name) ? 0.5 : 1;
1117
+ commandsManager.run({
1118
+ commandName: 'setViewportColormap',
1119
+ commandOptions: {
1120
+ ...props,
1121
+ opacity,
1122
+ immediate: true
1123
+ },
1124
+ context: 'CORNERSTONE'
1125
+ });
1126
+ }, [commandsManager]);
1127
+ const getViewportColormap = (viewportId, displaySet) => {
1128
+ const {
1129
+ displaySetInstanceUID
1130
+ } = displaySet;
1131
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1132
+ if (viewport instanceof dist_esm.StackViewport) {
1133
+ const {
1134
+ colormap
1135
+ } = viewport.getProperties();
1136
+ if (!colormap) {
1137
+ return colormaps.find(c => c.Name === 'Grayscale') || colormaps[0];
1138
+ }
1139
+ return colormap;
1140
+ }
1141
+ const actorEntries = viewport.getActors();
1142
+ const actorEntry = actorEntries.find(entry => entry.uid.includes(displaySetInstanceUID));
1143
+ const {
1144
+ colormap
1145
+ } = viewport.getProperties(actorEntry.uid);
1146
+ if (!colormap) {
1147
+ return colormaps.find(c => c.Name === 'Grayscale') || colormaps[0];
1148
+ }
1149
+ return colormap;
1150
+ };
1151
+ const buttons = (0,react.useMemo)(() => {
1152
+ return displaySets.map((displaySet, index) => ({
1153
+ children: displaySet.Modality,
1154
+ key: index,
1155
+ style: {
1156
+ minWidth: `calc(100% / ${displaySets.length})`
1157
+ }
1158
+ }));
1159
+ }, [displaySets]);
1160
+ (0,react.useEffect)(() => {
1161
+ setActiveDisplaySet(displaySets[displaySets.length - 1]);
1162
+ }, [displaySets]);
1163
+ return /*#__PURE__*/react.createElement(react.Fragment, null, buttons.length > 1 && /*#__PURE__*/react.createElement("div", {
1164
+ className: "all-in-one-menu-item flex w-full justify-center"
1165
+ }, /*#__PURE__*/react.createElement(ui_src/* ButtonGroup */.e2, {
1166
+ onActiveIndexChange: index => {
1167
+ setActiveDisplaySet(displaySets[index]);
1168
+ setPrePreviewColormap(null);
1169
+ },
1170
+ activeIndex: displaySets.findIndex(ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID) || 1,
1171
+ className: "w-[70%] text-[10px]"
1172
+ }, buttons.map(({
1173
+ children,
1174
+ key,
1175
+ style
1176
+ }) => /*#__PURE__*/react.createElement("div", {
1177
+ key: key,
1178
+ style: style
1179
+ }, children)))), /*#__PURE__*/react.createElement("div", {
1180
+ className: "all-in-one-menu-item flex w-full justify-center"
1181
+ }, /*#__PURE__*/react.createElement(ui_src/* SwitchButton */.L$, {
1182
+ label: "Preview in viewport",
1183
+ checked: showPreview,
1184
+ onChange: checked => {
1185
+ setShowPreview(checked);
1186
+ }
1187
+ })), /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.DividerItem */.se.VG, null), /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, colormaps.map((colormap, index) => /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.Item */.se.q7, {
1188
+ key: index,
1189
+ label: colormap.description,
1190
+ onClick: () => {
1191
+ onSetColorLUT({
1192
+ viewportId,
1193
+ colormap,
1194
+ displaySetInstanceUID: activeDisplaySetRef.current.displaySetInstanceUID
1195
+ });
1196
+ setPrePreviewColormap(null);
1197
+ },
1198
+ onMouseEnter: () => {
1199
+ if (showPreviewRef.current) {
1200
+ setPrePreviewColormap(getViewportColormap(viewportId, activeDisplaySetRef.current));
1201
+ onSetColorLUT({
1202
+ viewportId,
1203
+ colormap,
1204
+ displaySetInstanceUID: activeDisplaySetRef.current.displaySetInstanceUID
1205
+ });
1206
+ }
1207
+ },
1208
+ onMouseLeave: () => {
1209
+ if (showPreviewRef.current && prePreviewColormapRef.current) {
1210
+ onSetColorLUT({
1211
+ viewportId,
1212
+ colormap: prePreviewColormapRef.current,
1213
+ displaySetInstanceUID: activeDisplaySetRef.current.displaySetInstanceUID
1214
+ });
1215
+ }
1216
+ }
1217
+ }))));
1218
+ }
1219
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/Colorbar.tsx
1220
+
1221
+
1222
+
1223
+
1224
+ function setViewportColorbar(viewportId, displaySets, commandsManager, serviceManager, colorbarOptions) {
1225
+ const {
1226
+ cornerstoneViewportService
1227
+ } = serviceManager.services;
1228
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1229
+ const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
1230
+ const backgroundColor = viewportInfo.getViewportOptions().background;
1231
+ const isLight = backgroundColor ? dist_esm.utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
1232
+ if (isLight) {
1233
+ colorbarOptions.ticks = {
1234
+ position: 'left',
1235
+ style: {
1236
+ font: '12px Arial',
1237
+ color: '#000000',
1238
+ maxNumTicks: 8,
1239
+ tickSize: 5,
1240
+ tickWidth: 1,
1241
+ labelMargin: 3
1242
+ }
1243
+ };
1244
+ }
1245
+ const displaySetInstanceUIDs = [];
1246
+ if (viewport instanceof dist_esm.StackViewport) {
1247
+ displaySetInstanceUIDs.push(viewportId);
1248
+ }
1249
+ if (viewport instanceof dist_esm.VolumeViewport) {
1250
+ displaySets.forEach(ds => {
1251
+ displaySetInstanceUIDs.push(ds.displaySetInstanceUID);
1252
+ });
1253
+ }
1254
+ commandsManager.run({
1255
+ commandName: 'toggleViewportColorbar',
1256
+ commandOptions: {
1257
+ viewportId,
1258
+ options: colorbarOptions,
1259
+ displaySetInstanceUIDs
1260
+ },
1261
+ context: 'CORNERSTONE'
1262
+ });
1263
+ }
1264
+ function Colorbar({
1265
+ viewportId,
1266
+ displaySets,
1267
+ commandsManager,
1268
+ serviceManager,
1269
+ colorbarProperties
1270
+ }) {
1271
+ const {
1272
+ colorbarService
1273
+ } = serviceManager.services;
1274
+ const {
1275
+ width: colorbarWidth,
1276
+ colorbarTickPosition,
1277
+ colorbarContainerPosition,
1278
+ colormaps,
1279
+ colorbarInitialColormap
1280
+ } = colorbarProperties;
1281
+ const [showColorbar, setShowColorbar] = (0,react.useState)(colorbarService.hasColorbar(viewportId));
1282
+ const onSetColorbar = (0,react.useCallback)(() => {
1283
+ setViewportColorbar(viewportId, displaySets, commandsManager, serviceManager, {
1284
+ viewportId,
1285
+ colormaps,
1286
+ ticks: {
1287
+ position: colorbarTickPosition
1288
+ },
1289
+ width: colorbarWidth,
1290
+ position: colorbarContainerPosition,
1291
+ activeColormapName: colorbarInitialColormap
1292
+ });
1293
+ }, [commandsManager]);
1294
+ (0,react.useEffect)(() => {
1295
+ const updateColorbarState = () => {
1296
+ setShowColorbar(colorbarService.hasColorbar(viewportId));
1297
+ };
1298
+ const {
1299
+ unsubscribe
1300
+ } = colorbarService.subscribe(colorbarService.EVENTS.STATE_CHANGED, updateColorbarState);
1301
+ return () => {
1302
+ unsubscribe();
1303
+ };
1304
+ }, [viewportId]);
1305
+ return /*#__PURE__*/react.createElement("div", {
1306
+ className: "all-in-one-menu-item flex w-full justify-center"
1307
+ }, /*#__PURE__*/react.createElement(ui_src/* SwitchButton */.L$, {
1308
+ label: "Display Color bar",
1309
+ checked: showColorbar,
1310
+ onChange: () => {
1311
+ onSetColorbar();
1312
+ }
1313
+ }));
1314
+ }
1315
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx
1316
+
1317
+
1318
+
1319
+ function WindowLevel({
1320
+ viewportId,
1321
+ commandsManager,
1322
+ presets
1323
+ }) {
1324
+ const {
1325
+ t
1326
+ } = (0,es/* useTranslation */.Bd)('WindowLevelActionMenu');
1327
+ const onSetWindowLevel = (0,react.useCallback)(props => {
1328
+ commandsManager.run({
1329
+ commandName: 'setViewportWindowLevel',
1330
+ commandOptions: {
1331
+ ...props
1332
+ },
1333
+ context: 'CORNERSTONE'
1334
+ });
1335
+ }, [commandsManager]);
1336
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.HeaderItem */.se.N5, null, t('Modality Presets', {
1337
+ modality: Object.keys(presets)[0]
1338
+ })), Object.values(presets)[0].map((preset, index) => /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.Item */.se.q7, {
1339
+ key: index,
1340
+ label: preset.description,
1341
+ secondaryLabel: `${preset.window} / ${preset.level}`,
1342
+ onClick: () => onSetWindowLevel({
1343
+ ...preset,
1344
+ viewportId
1345
+ })
1346
+ })));
1347
+ }
1348
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresetsContent.tsx
1349
+
1350
+
1351
+
1352
+
1353
+ function VolumeRenderingPresetsContent({
1354
+ presets,
1355
+ viewportId,
1356
+ commandsManager,
1357
+ onClose
1358
+ }) {
1359
+ const [filteredPresets, setFilteredPresets] = (0,react.useState)(presets);
1360
+ const [searchValue, setSearchValue] = (0,react.useState)('');
1361
+ const [selectedPreset, setSelectedPreset] = (0,react.useState)(null);
1362
+ const handleSearchChange = (0,react.useCallback)(value => {
1363
+ setSearchValue(value);
1364
+ const filtered = value ? presets.filter(preset => preset.name.toLowerCase().includes(value.toLowerCase())) : presets;
1365
+ setFilteredPresets(filtered);
1366
+ }, [presets]);
1367
+ const handleApply = (0,react.useCallback)(props => {
1368
+ commandsManager.runCommand('setViewportPreset', {
1369
+ ...props
1370
+ });
1371
+ }, [commandsManager]);
1372
+ const formatLabel = (label, maxChars) => {
1373
+ return label.length > maxChars ? `${label.slice(0, maxChars)}...` : label;
1374
+ };
1375
+ return /*#__PURE__*/react.createElement("div", {
1376
+ className: "flex min-h-full w-full flex-col justify-between"
1377
+ }, /*#__PURE__*/react.createElement("div", {
1378
+ className: "border-secondary-light h-[433px] w-full overflow-hidden rounded border bg-black px-2.5"
1379
+ }, /*#__PURE__*/react.createElement("div", {
1380
+ className: "flex h-[46px] w-full items-center justify-start"
1381
+ }, /*#__PURE__*/react.createElement("div", {
1382
+ className: "h-[26px] w-[200px]"
1383
+ }, /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Cv, {
1384
+ value: searchValue,
1385
+ onDebounceChange: handleSearchChange,
1386
+ placeholder: 'Search all'
1387
+ }))), /*#__PURE__*/react.createElement("div", {
1388
+ className: "ohif-scrollbar overflow h-[385px] w-full overflow-y-auto"
1389
+ }, /*#__PURE__*/react.createElement("div", {
1390
+ className: "grid grid-cols-4 gap-3 pt-2 pr-3"
1391
+ }, filteredPresets.map((preset, index) => /*#__PURE__*/react.createElement("div", {
1392
+ key: index,
1393
+ className: "flex cursor-pointer flex-col items-start",
1394
+ onClick: () => {
1395
+ setSelectedPreset(preset);
1396
+ handleApply({
1397
+ preset: preset.name,
1398
+ viewportId
1399
+ });
1400
+ }
1401
+ }, /*#__PURE__*/react.createElement(ui_src/* Icon */.In, {
1402
+ name: preset.name,
1403
+ className: selectedPreset?.name === preset.name ? 'border-primary-light h-[75px] w-[95px] max-w-none rounded border-2' : 'hover:border-primary-light h-[75px] w-[95px] max-w-none rounded border-2 border-black'
1404
+ }), /*#__PURE__*/react.createElement("label", {
1405
+ className: "text-aqua-pale mt-2 text-left text-xs"
1406
+ }, formatLabel(preset.name, 11))))))), /*#__PURE__*/react.createElement("footer", {
1407
+ className: "flex h-[60px] w-full items-center justify-end"
1408
+ }, /*#__PURE__*/react.createElement("div", {
1409
+ className: "flex"
1410
+ }, /*#__PURE__*/react.createElement(ui_src/* Button */.$n, {
1411
+ name: "Cancel",
1412
+ size: ui_src/* ButtonEnums.size */.Ny.Ej.medium,
1413
+ type: ui_src/* ButtonEnums.type */.Ny.NW.secondary,
1414
+ onClick: onClose
1415
+ }, ' ', "Cancel", ' '))));
1416
+ }
1417
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresets.tsx
1418
+
1419
+
1420
+
1421
+ function VolumeRenderingPresets({
1422
+ viewportId,
1423
+ serviceManager,
1424
+ commandsManager,
1425
+ volumeRenderingPresets
1426
+ }) {
1427
+ const {
1428
+ uiModalService
1429
+ } = serviceManager.services;
1430
+ const onClickPresets = () => {
1431
+ uiModalService.show({
1432
+ content: VolumeRenderingPresetsContent,
1433
+ title: 'Rendering Presets',
1434
+ movable: true,
1435
+ contentProps: {
1436
+ onClose: uiModalService.hide,
1437
+ presets: volumeRenderingPresets,
1438
+ viewportId,
1439
+ commandsManager
1440
+ },
1441
+ containerDimensions: 'h-[543px] w-[460px]',
1442
+ contentDimensions: 'h-[493px] w-[460px] pl-[12px]'
1443
+ });
1444
+ };
1445
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.Item */.se.q7, {
1446
+ label: "Rendering Presets",
1447
+ icon: /*#__PURE__*/react.createElement(ui_src/* Icon */.In, {
1448
+ name: "VolumeRendering"
1449
+ }),
1450
+ rightIcon: /*#__PURE__*/react.createElement(ui_src/* Icon */.In, {
1451
+ name: "action-new-dialog"
1452
+ }),
1453
+ onClick: onClickPresets
1454
+ });
1455
+ }
1456
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingQuality.tsx
1457
+
1458
+ function VolumeRenderingQuality({
1459
+ volumeRenderingQualityRange,
1460
+ commandsManager,
1461
+ serviceManager,
1462
+ viewportId
1463
+ }) {
1464
+ const {
1465
+ cornerstoneViewportService
1466
+ } = serviceManager.services;
1467
+ const {
1468
+ min,
1469
+ max,
1470
+ step
1471
+ } = volumeRenderingQualityRange;
1472
+ const [quality, setQuality] = (0,react.useState)(null);
1473
+ const onChange = (0,react.useCallback)(value => {
1474
+ commandsManager.runCommand('setVolumeRenderingQulaity', {
1475
+ viewportId,
1476
+ volumeQuality: value
1477
+ });
1478
+ setQuality(value);
1479
+ }, [commandsManager, viewportId]);
1480
+ const calculateBackground = value => {
1481
+ const percentage = (value - 0) / (1 - 0) * 100;
1482
+ return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
1483
+ };
1484
+ (0,react.useEffect)(() => {
1485
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1486
+ const {
1487
+ actor
1488
+ } = viewport.getActors()[0];
1489
+ const mapper = actor.getMapper();
1490
+ const image = mapper.getInputData();
1491
+ const spacing = image.getSpacing();
1492
+ const sampleDistance = mapper.getSampleDistance();
1493
+ const averageSpacing = spacing.reduce((a, b) => a + b) / 3.0;
1494
+ if (sampleDistance === averageSpacing) {
1495
+ setQuality(1);
1496
+ } else {
1497
+ setQuality(Math.sqrt(averageSpacing / (sampleDistance * 0.5)));
1498
+ }
1499
+ }, [cornerstoneViewportService, viewportId]);
1500
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1501
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1502
+ }, /*#__PURE__*/react.createElement("label", {
1503
+ className: "block text-white",
1504
+ htmlFor: "volume"
1505
+ }, "Quality"), quality !== null && /*#__PURE__*/react.createElement("input", {
1506
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1507
+ value: quality,
1508
+ id: "volume",
1509
+ max: max,
1510
+ min: min,
1511
+ type: "range",
1512
+ step: step,
1513
+ onChange: e => onChange(parseInt(e.target.value, 10)),
1514
+ style: {
1515
+ background: calculateBackground((quality - min) / (max - min))
1516
+ }
1517
+ })));
1518
+ }
1519
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx
1520
+
1521
+ function VolumeShift({
1522
+ viewportId,
1523
+ commandsManager,
1524
+ serviceManager
1525
+ }) {
1526
+ const {
1527
+ cornerstoneViewportService
1528
+ } = serviceManager.services;
1529
+ const [minShift, setMinShift] = (0,react.useState)(null);
1530
+ const [maxShift, setMaxShift] = (0,react.useState)(null);
1531
+ const [shift, setShift] = (0,react.useState)(cornerstoneViewportService.getCornerstoneViewport(viewportId)?.shiftedBy || 0);
1532
+ const [step, setStep] = (0,react.useState)(null);
1533
+ const [isBlocking, setIsBlocking] = (0,react.useState)(false);
1534
+ const prevShiftRef = (0,react.useRef)(shift);
1535
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1536
+ const {
1537
+ actor
1538
+ } = viewport.getActors()[0];
1539
+ const ofun = actor.getProperty().getScalarOpacity(0);
1540
+ (0,react.useEffect)(() => {
1541
+ if (isBlocking) {
1542
+ return;
1543
+ }
1544
+ const range = ofun.getRange();
1545
+ const transferFunctionWidth = range[1] - range[0];
1546
+ const minShift = -transferFunctionWidth;
1547
+ const maxShift = transferFunctionWidth;
1548
+ setMinShift(minShift);
1549
+ setMaxShift(maxShift);
1550
+ setStep(Math.pow(10, Math.floor(Math.log10(transferFunctionWidth / 500))));
1551
+ }, [cornerstoneViewportService, viewportId, actor, ofun, isBlocking]);
1552
+ const onChangeRange = (0,react.useCallback)(newShift => {
1553
+ const shiftDifference = newShift - prevShiftRef.current;
1554
+ prevShiftRef.current = newShift;
1555
+ viewport.shiftedBy = newShift;
1556
+ commandsManager.runCommand('shiftVolumeOpacityPoints', {
1557
+ viewportId,
1558
+ shift: shiftDifference
1559
+ });
1560
+ }, [commandsManager, viewportId, viewport]);
1561
+ const calculateBackground = value => {
1562
+ const percentage = (value - 0) / (1 - 0) * 100;
1563
+ return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
1564
+ };
1565
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1566
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1567
+ }, /*#__PURE__*/react.createElement("label", {
1568
+ className: "block text-white",
1569
+ htmlFor: "shift"
1570
+ }, "Shift"), step !== null && /*#__PURE__*/react.createElement("input", {
1571
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1572
+ value: shift,
1573
+ onChange: e => {
1574
+ const shiftValue = parseInt(e.target.value, 10);
1575
+ setShift(shiftValue);
1576
+ onChangeRange(shiftValue);
1577
+ },
1578
+ id: "shift",
1579
+ onMouseDown: () => setIsBlocking(true),
1580
+ onMouseUp: () => setIsBlocking(false),
1581
+ max: maxShift,
1582
+ min: minShift,
1583
+ type: "range",
1584
+ step: step,
1585
+ style: {
1586
+ background: calculateBackground((shift - minShift) / (maxShift - minShift))
1587
+ }
1588
+ })));
1589
+ }
1590
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx
1591
+
1592
+ function VolumeLighting({
1593
+ serviceManager,
1594
+ commandsManager,
1595
+ viewportId
1596
+ }) {
1597
+ const {
1598
+ cornerstoneViewportService
1599
+ } = serviceManager.services;
1600
+ const [ambient, setAmbient] = (0,react.useState)(null);
1601
+ const [diffuse, setDiffuse] = (0,react.useState)(null);
1602
+ const [specular, setSpecular] = (0,react.useState)(null);
1603
+ const onAmbientChange = (0,react.useCallback)(() => {
1604
+ commandsManager.runCommand('setVolumeLighting', {
1605
+ viewportId,
1606
+ options: {
1607
+ ambient
1608
+ }
1609
+ });
1610
+ }, [ambient, commandsManager, viewportId]);
1611
+ const onDiffuseChange = (0,react.useCallback)(() => {
1612
+ commandsManager.runCommand('setVolumeLighting', {
1613
+ viewportId,
1614
+ options: {
1615
+ diffuse
1616
+ }
1617
+ });
1618
+ }, [diffuse, commandsManager, viewportId]);
1619
+ const onSpecularChange = (0,react.useCallback)(() => {
1620
+ commandsManager.runCommand('setVolumeLighting', {
1621
+ viewportId,
1622
+ options: {
1623
+ specular
1624
+ }
1625
+ });
1626
+ }, [specular, commandsManager, viewportId]);
1627
+ const calculateBackground = value => {
1628
+ const percentage = (value - 0) / (1 - 0) * 100;
1629
+ return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
1630
+ };
1631
+ (0,react.useEffect)(() => {
1632
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1633
+ const {
1634
+ actor
1635
+ } = viewport.getActors()[0];
1636
+ const ambient = actor.getProperty().getAmbient();
1637
+ const diffuse = actor.getProperty().getDiffuse();
1638
+ const specular = actor.getProperty().getSpecular();
1639
+ setAmbient(ambient);
1640
+ setDiffuse(diffuse);
1641
+ setSpecular(specular);
1642
+ }, [viewportId, cornerstoneViewportService]);
1643
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1644
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1645
+ }, /*#__PURE__*/react.createElement("label", {
1646
+ className: "block text-white",
1647
+ htmlFor: "ambient"
1648
+ }, "Ambient"), ambient !== null && /*#__PURE__*/react.createElement("input", {
1649
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1650
+ value: ambient,
1651
+ onChange: e => {
1652
+ setAmbient(e.target.value);
1653
+ onAmbientChange();
1654
+ },
1655
+ id: "ambient",
1656
+ max: 1,
1657
+ min: 0,
1658
+ type: "range",
1659
+ step: 0.1,
1660
+ style: {
1661
+ background: calculateBackground(ambient)
1662
+ }
1663
+ })), /*#__PURE__*/react.createElement("div", {
1664
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1665
+ }, /*#__PURE__*/react.createElement("label", {
1666
+ className: "block text-white",
1667
+ htmlFor: "diffuse"
1668
+ }, "Diffuse"), diffuse !== null && /*#__PURE__*/react.createElement("input", {
1669
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1670
+ value: diffuse,
1671
+ onChange: e => {
1672
+ setDiffuse(e.target.value);
1673
+ onDiffuseChange();
1674
+ },
1675
+ id: "diffuse",
1676
+ max: 1,
1677
+ min: 0,
1678
+ type: "range",
1679
+ step: 0.1,
1680
+ style: {
1681
+ background: calculateBackground(diffuse)
1682
+ }
1683
+ })), /*#__PURE__*/react.createElement("div", {
1684
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1685
+ }, /*#__PURE__*/react.createElement("label", {
1686
+ className: "block text-white",
1687
+ htmlFor: "specular"
1688
+ }, "Specular"), specular !== null && /*#__PURE__*/react.createElement("input", {
1689
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1690
+ value: specular,
1691
+ onChange: e => {
1692
+ setSpecular(e.target.value);
1693
+ onSpecularChange();
1694
+ },
1695
+ id: "specular",
1696
+ max: 1,
1697
+ min: 0,
1698
+ type: "range",
1699
+ step: 0.1,
1700
+ style: {
1701
+ background: calculateBackground(specular)
1702
+ }
1703
+ })));
1704
+ }
1705
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShade.tsx
1706
+
1707
+
1708
+ function VolumeShade({
1709
+ commandsManager,
1710
+ viewportId,
1711
+ serviceManager
1712
+ }) {
1713
+ const {
1714
+ cornerstoneViewportService
1715
+ } = serviceManager.services;
1716
+ const [shade, setShade] = (0,react.useState)(true);
1717
+ const [key, setKey] = (0,react.useState)(0);
1718
+ const onShadeChange = (0,react.useCallback)(checked => {
1719
+ commandsManager.runCommand('setVolumeLighting', {
1720
+ viewportId,
1721
+ options: {
1722
+ shade: checked
1723
+ }
1724
+ });
1725
+ }, [commandsManager, viewportId]);
1726
+ (0,react.useEffect)(() => {
1727
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1728
+ const {
1729
+ actor
1730
+ } = viewport.getActors()[0];
1731
+ const shade = actor.getProperty().getShade();
1732
+ setShade(shade);
1733
+ setKey(key + 1);
1734
+ }, [viewportId, cornerstoneViewportService]);
1735
+ return /*#__PURE__*/react.createElement(ui_src/* SwitchButton */.L$, {
1736
+ key: key,
1737
+ label: "Shade",
1738
+ checked: shade,
1739
+ onChange: () => {
1740
+ setShade(!shade);
1741
+ onShadeChange(!shade);
1742
+ }
1743
+ });
1744
+ }
1745
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx
1746
+
1747
+
1748
+
1749
+
1750
+
1751
+
1752
+ function VolumeRenderingOptions({
1753
+ viewportId,
1754
+ commandsManager,
1755
+ volumeRenderingQualityRange,
1756
+ serviceManager
1757
+ }) {
1758
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, /*#__PURE__*/react.createElement(VolumeRenderingQuality, {
1759
+ viewportId: viewportId,
1760
+ commandsManager: commandsManager,
1761
+ serviceManager: serviceManager,
1762
+ volumeRenderingQualityRange: volumeRenderingQualityRange
1763
+ }), /*#__PURE__*/react.createElement(VolumeShift, {
1764
+ viewportId: viewportId,
1765
+ commandsManager: commandsManager,
1766
+ serviceManager: serviceManager
1767
+ }), /*#__PURE__*/react.createElement("div", {
1768
+ className: "all-in-one-menu-item flex w-full justify-start"
1769
+ }, /*#__PURE__*/react.createElement("div", {
1770
+ className: "text-aqua-pale text-[13px]"
1771
+ }, "LIGHTING")), /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.DividerItem */.se.VG, null), /*#__PURE__*/react.createElement("div", {
1772
+ className: "all-in-one-menu-item flex w-full justify-center"
1773
+ }, /*#__PURE__*/react.createElement(VolumeShade, {
1774
+ commandsManager: commandsManager,
1775
+ serviceManager: serviceManager,
1776
+ viewportId: viewportId
1777
+ })), /*#__PURE__*/react.createElement(VolumeLighting, {
1778
+ viewportId: viewportId,
1779
+ commandsManager: commandsManager,
1780
+ serviceManager: serviceManager
1781
+ }));
1782
+ }
1783
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+
1791
+
1792
+
1793
+
1794
+
1795
+
1796
+ function WindowLevelActionMenu({
1797
+ viewportId,
1798
+ element,
1799
+ presets,
1800
+ verticalDirection,
1801
+ horizontalDirection,
1802
+ commandsManager,
1803
+ serviceManager,
1804
+ colorbarProperties,
1805
+ displaySets,
1806
+ volumeRenderingPresets,
1807
+ volumeRenderingQualityRange
1808
+ }) {
1809
+ const {
1810
+ colormaps,
1811
+ colorbarContainerPosition,
1812
+ colorbarInitialColormap,
1813
+ colorbarTickPosition,
1814
+ width: colorbarWidth
1815
+ } = colorbarProperties;
1816
+ const {
1817
+ colorbarService,
1818
+ cornerstoneViewportService
1819
+ } = serviceManager.services;
1820
+ const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
1821
+ const backgroundColor = viewportInfo.getViewportOptions().background;
1822
+ const isLight = backgroundColor ? dist_esm.utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
1823
+ const nonImageModalities = ['SR', 'SEG', 'SM', 'RTSTRUCT', 'RTPLAN', 'RTDOSE'];
1824
+ const {
1825
+ t
1826
+ } = (0,es/* useTranslation */.Bd)('WindowLevelActionMenu');
1827
+ const [viewportGrid] = (0,ui_src/* useViewportGrid */.ih)();
1828
+ const {
1829
+ activeViewportId
1830
+ } = viewportGrid;
1831
+ const [vpHeight, setVpHeight] = (0,react.useState)(element?.clientHeight);
1832
+ const [menuKey, setMenuKey] = (0,react.useState)(0);
1833
+ const [is3DVolume, setIs3DVolume] = (0,react.useState)(false);
1834
+ const onSetColorbar = (0,react.useCallback)(() => {
1835
+ setViewportColorbar(viewportId, displaySets, commandsManager, serviceManager, {
1836
+ colormaps,
1837
+ ticks: {
1838
+ position: colorbarTickPosition
1839
+ },
1840
+ width: colorbarWidth,
1841
+ position: colorbarContainerPosition,
1842
+ activeColormapName: colorbarInitialColormap
1843
+ });
1844
+ }, [commandsManager]);
1845
+ (0,react.useEffect)(() => {
1846
+ const newVpHeight = element?.clientHeight;
1847
+ if (vpHeight !== newVpHeight) {
1848
+ setVpHeight(newVpHeight);
1849
+ }
1850
+ }, [element, vpHeight]);
1851
+ (0,react.useEffect)(() => {
1852
+ if (!colorbarService.hasColorbar(viewportId)) {
1853
+ return;
1854
+ }
1855
+ window.setTimeout(() => {
1856
+ colorbarService.removeColorbar(viewportId);
1857
+ onSetColorbar();
1858
+ }, 0);
1859
+ }, [viewportId]);
1860
+ (0,react.useEffect)(() => {
1861
+ if (colorbarService.hasColorbar(viewportId)) {
1862
+ colorbarService.removeColorbar(viewportId);
1863
+ }
1864
+ }, [displaySets]);
1865
+ (0,react.useEffect)(() => {
1866
+ setMenuKey(menuKey + 1);
1867
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1868
+ if (viewport instanceof dist_esm.VolumeViewport3D) {
1869
+ setIs3DVolume(true);
1870
+ } else {
1871
+ setIs3DVolume(false);
1872
+ }
1873
+ }, [displaySets, viewportId, presets, volumeRenderingQualityRange, volumeRenderingPresets, colorbarProperties, activeViewportId, viewportGrid]);
1874
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.IconMenu */.se.dd, {
1875
+ icon: "viewport-window-level",
1876
+ verticalDirection: verticalDirection,
1877
+ horizontalDirection: horizontalDirection,
1878
+ iconClassName: classnames_default()(
1879
+ // Visible on hover and for the active viewport
1880
+ activeViewportId === viewportId ? 'visible' : 'invisible group-hover:visible', 'flex shrink-0 cursor-pointer rounded active:text-white', isLight ? 'text-aqua-pale hover:bg-secondary-dark' : 'text-primary-light hover:bg-secondary-light/60'),
1881
+ menuStyle: {
1882
+ maxHeight: vpHeight - 32,
1883
+ minWidth: 218
1884
+ },
1885
+ onVisibilityChange: () => {
1886
+ setVpHeight(element.clientHeight);
1887
+ },
1888
+ menuKey: menuKey
1889
+ }, /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, !is3DVolume && /*#__PURE__*/react.createElement(Colorbar, {
1890
+ viewportId: viewportId,
1891
+ displaySets: displaySets.filter(ds => !nonImageModalities.includes(ds.Modality)),
1892
+ commandsManager: commandsManager,
1893
+ serviceManager: serviceManager,
1894
+ colorbarProperties: colorbarProperties
1895
+ }), colormaps && !is3DVolume && /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.SubMenu */.se.g8, {
1896
+ key: "colorLUTPresets",
1897
+ itemLabel: "Color LUT",
1898
+ itemIcon: "icon-color-lut"
1899
+ }, /*#__PURE__*/react.createElement(Colormap, {
1900
+ colormaps: colormaps,
1901
+ viewportId: viewportId,
1902
+ displaySets: displaySets.filter(ds => !nonImageModalities.includes(ds.Modality)),
1903
+ commandsManager: commandsManager,
1904
+ serviceManager: serviceManager
1905
+ })), presets && !is3DVolume && /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.SubMenu */.se.g8, {
1906
+ key: "windowLevelPresets",
1907
+ itemLabel: t('Modality Window Presets', {
1908
+ modality: Object.keys(presets)[0]
1909
+ }),
1910
+ itemIcon: "viewport-window-level"
1911
+ }, /*#__PURE__*/react.createElement(WindowLevel, {
1912
+ viewportId: viewportId,
1913
+ commandsManager: commandsManager,
1914
+ presets: presets
1915
+ })), volumeRenderingPresets && is3DVolume && /*#__PURE__*/react.createElement(VolumeRenderingPresets, {
1916
+ serviceManager: serviceManager,
1917
+ viewportId: viewportId,
1918
+ commandsManager: commandsManager,
1919
+ volumeRenderingPresets: volumeRenderingPresets
1920
+ }), volumeRenderingQualityRange && is3DVolume && /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.SubMenu */.se.g8, {
1921
+ itemLabel: "Rendering Options"
1922
+ }, /*#__PURE__*/react.createElement(VolumeRenderingOptions, {
1923
+ viewportId: viewportId,
1924
+ commandsManager: commandsManager,
1925
+ volumeRenderingQualityRange: volumeRenderingQualityRange,
1926
+ serviceManager: serviceManager
1927
+ }))));
1928
+ }
1929
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/getWindowLevelActionMenu.tsx
1930
+
1931
+
1932
+ function getWindowLevelActionMenu({
1933
+ viewportId,
1934
+ element,
1935
+ displaySets,
1936
+ servicesManager,
1937
+ commandsManager,
1938
+ verticalDirection,
1939
+ horizontalDirection
1940
+ }) {
1941
+ const {
1942
+ customizationService
1943
+ } = servicesManager.services;
1944
+ const {
1945
+ presets
1946
+ } = customizationService.get('cornerstone.windowLevelPresets');
1947
+ const colorbarProperties = customizationService.get('cornerstone.colorbar');
1948
+ const {
1949
+ volumeRenderingPresets,
1950
+ volumeRenderingQualityRange
1951
+ } = customizationService.get('cornerstone.3dVolumeRendering');
1952
+ const displaySetPresets = displaySets.filter(displaySet => presets[displaySet.Modality]).map(displaySet => {
1953
+ return {
1954
+ [displaySet.Modality]: presets[displaySet.Modality]
1955
+ };
1956
+ });
1957
+ const hasMenu = displaySetPresets.length > 0;
1958
+ return hasMenu ? /*#__PURE__*/react.createElement(WindowLevelActionMenu, {
1959
+ viewportId: viewportId,
1960
+ element: element,
1961
+ presets: displaySetPresets[0],
1962
+ verticalDirection: verticalDirection,
1963
+ horizontalDirection: horizontalDirection,
1964
+ commandsManager: commandsManager,
1965
+ serviceManager: servicesManager,
1966
+ colorbarProperties: colorbarProperties,
1967
+ displaySets: displaySets,
1968
+ volumeRenderingPresets: volumeRenderingPresets,
1969
+ volumeRenderingQualityRange: volumeRenderingQualityRange
1970
+ }) : null;
1971
+ }
1092
1972
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx
1093
1973
 
1094
1974
 
@@ -1102,6 +1982,9 @@ function WrappedCinePlayer(_ref) {
1102
1982
 
1103
1983
 
1104
1984
 
1985
+
1986
+
1987
+
1105
1988
  const STACK = 'stack';
1106
1989
 
1107
1990
  /**
@@ -1166,19 +2049,20 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1166
2049
  viewportOptions,
1167
2050
  displaySetOptions,
1168
2051
  servicesManager,
1169
- commandsManager,
1170
2052
  onElementEnabled,
1171
2053
  onElementDisabled,
1172
2054
  isJumpToMeasurementDisabled,
1173
2055
  // Note: you SHOULD NOT use the initialImageIdOrIndex for manipulation
1174
2056
  // of the imageData in the OHIFCornerstoneViewport. This prop is used
1175
2057
  // to set the initial state of the viewport's first image to render
1176
- initialImageIndex
2058
+ initialImageIndex,
2059
+ onReady
1177
2060
  } = props;
1178
2061
  const viewportId = viewportOptions.viewportId;
1179
2062
  const [scrollbarHeight, setScrollbarHeight] = (0,react.useState)('100px');
1180
2063
  const [enabledVPElement, setEnabledVPElement] = (0,react.useState)(null);
1181
2064
  const elementRef = (0,react.useRef)();
2065
+ const [appConfig] = (0,state_0/* useAppConfig */.r)();
1182
2066
  const {
1183
2067
  measurementService,
1184
2068
  displaySetService,
@@ -1188,12 +2072,14 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1188
2072
  cornerstoneViewportService,
1189
2073
  cornerstoneCacheService,
1190
2074
  viewportGridService,
1191
- stateSyncService
2075
+ stateSyncService,
2076
+ viewportActionCornersService,
2077
+ customizationService
1192
2078
  } = servicesManager.services;
1193
- const [viewportDialogState] = (0,ui_src/* useViewportDialog */.en)();
2079
+ const [viewportDialogState] = (0,ui_src/* useViewportDialog */.OR)();
1194
2080
  // useCallback for scroll bar height calculation
1195
2081
  const setImageScrollBarHeight = (0,react.useCallback)(() => {
1196
- const scrollbarHeight = `${elementRef.current.clientHeight - 20}px`;
2082
+ const scrollbarHeight = `${elementRef.current.clientHeight - 40}px`;
1197
2083
  setScrollbarHeight(scrollbarHeight);
1198
2084
  }, [elementRef]);
1199
2085
 
@@ -1209,6 +2095,7 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1209
2095
  const syncGroups = viewportInfo.getSyncGroups();
1210
2096
  toolGroupService.removeViewportFromToolGroup(viewportId, renderingEngineId);
1211
2097
  syncGroupService.removeViewportFromSyncGroup(viewportId, renderingEngineId, syncGroups);
2098
+ viewportActionCornersService.clear(viewportId);
1212
2099
  }, [viewportId]);
1213
2100
  const elementEnabledHandler = (0,react.useCallback)(evt => {
1214
2101
  // check this is this element reference and return early if doesn't match
@@ -1220,15 +2107,21 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1220
2107
  element
1221
2108
  } = evt.detail;
1222
2109
  const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
1223
- (0,state/* setEnabledElement */.Yc)(viewportId, element);
2110
+ (0,state/* setEnabledElement */.ye)(viewportId, element);
1224
2111
  setEnabledVPElement(element);
1225
2112
  const renderingEngineId = viewportInfo.getRenderingEngineId();
1226
2113
  const toolGroupId = viewportInfo.getToolGroupId();
1227
2114
  const syncGroups = viewportInfo.getSyncGroups();
1228
2115
  toolGroupService.addViewportToToolGroup(viewportId, renderingEngineId, toolGroupId);
1229
2116
  syncGroupService.addViewportToSyncGroup(viewportId, renderingEngineId, syncGroups);
2117
+ const synchronizersStore = stateSyncService.getState().synchronizersStore;
2118
+ if (synchronizersStore?.[viewportId]?.length) {
2119
+ // If the viewport used to have a synchronizer, re apply it again
2120
+ _rehydrateSynchronizers(synchronizersStore, viewportId, syncGroupService);
2121
+ }
1230
2122
  if (onElementEnabled) {
1231
2123
  onElementEnabled(evt);
2124
+ onReady?.(evt);
1232
2125
  }
1233
2126
  }, [viewportId, onElementEnabled, toolGroupService]);
1234
2127
 
@@ -1242,13 +2135,17 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1242
2135
  if (!viewportInfo) {
1243
2136
  return;
1244
2137
  }
1245
- cleanUpServices(viewportInfo);
1246
2138
  cornerstoneViewportService.storePresentation({
1247
2139
  viewportId
1248
2140
  });
2141
+
2142
+ // This should be done after the store presentation since synchronizers
2143
+ // will get cleaned up and they need the viewportInfo to be present
2144
+ cleanUpServices(viewportInfo);
1249
2145
  if (onElementDisabled) {
1250
2146
  onElementDisabled(viewportInfo);
1251
2147
  }
2148
+ cornerstoneViewportService.disableElement(viewportId);
1252
2149
  dist_esm.eventTarget.removeEventListener(dist_esm.Enums.Events.ELEMENT_ENABLED, elementEnabledHandler);
1253
2150
  };
1254
2151
  }, []);
@@ -1264,11 +2161,10 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1264
2161
  (0,react.useEffect)(() => {
1265
2162
  const {
1266
2163
  unsubscribe
1267
- } = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED, async _ref => {
1268
- let {
1269
- displaySetInstanceUID: invalidatedDisplaySetInstanceUID,
1270
- invalidateData
1271
- } = _ref;
2164
+ } = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED, async ({
2165
+ displaySetInstanceUID: invalidatedDisplaySetInstanceUID,
2166
+ invalidateData
2167
+ }) => {
1272
2168
  if (!invalidateData) {
1273
2169
  return;
1274
2170
  }
@@ -1295,10 +2191,9 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1295
2191
  // The presentation state will have been stored previously by closing
1296
2192
  // a viewport. Otherwise, this viewport will be unchanged and the
1297
2193
  // presentation information will be directly carried over.
1298
- const {
1299
- lutPresentationStore,
1300
- positionPresentationStore
1301
- } = stateSyncService.getState();
2194
+ const state = stateSyncService.getState();
2195
+ const lutPresentationStore = state.lutPresentationStore;
2196
+ const positionPresentationStore = state.positionPresentationStore;
1302
2197
  const {
1303
2198
  presentationIds
1304
2199
  } = viewportOptions;
@@ -1351,12 +2246,36 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1351
2246
  unsubscribeFromJumpToMeasurementEvents();
1352
2247
  };
1353
2248
  }, [displaySets, elementRef, viewportId]);
2249
+
2250
+ // Set up the window level action menu in the viewport action corners.
2251
+ (0,react.useEffect)(() => {
2252
+ // Doing an === check here because the default config value when not set is true
2253
+ if (appConfig.addWindowLevelActionMenu === false) {
2254
+ return;
2255
+ }
2256
+
2257
+ // TODO: In the future we should consider using the customization service
2258
+ // to determine if and in which corner various action components should go.
2259
+ const wlActionMenu = getWindowLevelActionMenu({
2260
+ viewportId,
2261
+ element: elementRef.current,
2262
+ displaySets,
2263
+ servicesManager,
2264
+ commandsManager,
2265
+ verticalDirection: ui_src/* AllInOneMenu.VerticalDirection */.se.mq.TopToBottom,
2266
+ horizontalDirection: ui_src/* AllInOneMenu.HorizontalDirection */.se.Iu.RightToLeft
2267
+ });
2268
+ viewportActionCornersService.setComponent({
2269
+ viewportId,
2270
+ id: 'windowLevelActionMenu',
2271
+ component: wlActionMenu,
2272
+ location: viewportActionCornersService.LOCATIONS.topRight,
2273
+ indexPriority: -100
2274
+ });
2275
+ }, [displaySets, viewportId, viewportActionCornersService, servicesManager, commandsManager]);
1354
2276
  return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1355
2277
  className: "viewport-wrapper"
1356
- }, /*#__PURE__*/react.createElement(index_esm/* default */.ZP, {
1357
- refreshMode: "debounce",
1358
- refreshRate: 50 // Wait 50 ms after last move to render
1359
- ,
2278
+ }, /*#__PURE__*/react.createElement(index_esm/* default */.Ay, {
1360
2279
  onResize: onResize,
1361
2280
  targetRef: elementRef.current
1362
2281
  }), /*#__PURE__*/react.createElement("div", {
@@ -1379,15 +2298,17 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1379
2298
  viewportId: viewportId,
1380
2299
  servicesManager: servicesManager
1381
2300
  })), /*#__PURE__*/react.createElement("div", {
1382
- className: "absolute w-full"
1383
- }, viewportDialogState.viewportId === viewportId && /*#__PURE__*/react.createElement(ui_src/* Notification */.P_, {
2301
+ className: "absolute top-[24px] w-full"
2302
+ }, viewportDialogState.viewportId === viewportId && /*#__PURE__*/react.createElement(ui_src/* Notification */.Eg, {
1384
2303
  id: "viewport-notification",
1385
2304
  message: viewportDialogState.message,
1386
2305
  type: viewportDialogState.type,
1387
2306
  actions: viewportDialogState.actions,
1388
2307
  onSubmit: viewportDialogState.onSubmit,
1389
2308
  onOutsideClick: viewportDialogState.onOutsideClick
1390
- })));
2309
+ })), /*#__PURE__*/react.createElement(components_OHIFViewportActionCorners, {
2310
+ viewportId: viewportId
2311
+ }));
1391
2312
  }, areEqual);
1392
2313
  function _subscribeToJumpToMeasurementEvents(measurementService, displaySetService, elementRef, viewportId, displaySets, viewportGridService, cornerstoneViewportService) {
1393
2314
  const {
@@ -1470,7 +2391,7 @@ function _jumpToMeasurement(measurement, targetElementRef, viewportId, measureme
1470
2391
  const {
1471
2392
  SOPInstanceUID: aSOPInstanceUID,
1472
2393
  frameNumber: aFrameNumber
1473
- } = (0,getSOPInstanceAttributes/* default */.Z)(imageId);
2394
+ } = (0,getSOPInstanceAttributes/* default */.A)(imageId);
1474
2395
  return aSOPInstanceUID === SOPInstanceUID && (!frameNumber || frameNumber === aFrameNumber);
1475
2396
  });
1476
2397
  } else {
@@ -1501,6 +2422,42 @@ function _jumpToMeasurement(measurement, targetElementRef, viewportId, measureme
1501
2422
  cacheJumpToMeasurementEvent = null;
1502
2423
  }
1503
2424
  }
2425
+ function _rehydrateSynchronizers(synchronizersStore, viewportId, syncGroupService) {
2426
+ synchronizersStore[viewportId].forEach(synchronizerObj => {
2427
+ if (!synchronizerObj.id) {
2428
+ return;
2429
+ }
2430
+ const {
2431
+ id,
2432
+ sourceViewports,
2433
+ targetViewports
2434
+ } = synchronizerObj;
2435
+ const synchronizer = syncGroupService.getSynchronizer(id);
2436
+ if (!synchronizer) {
2437
+ return;
2438
+ }
2439
+ const sourceViewportInfo = sourceViewports.find(sourceViewport => sourceViewport.viewportId === viewportId);
2440
+ const targetViewportInfo = targetViewports.find(targetViewport => targetViewport.viewportId === viewportId);
2441
+ const isSourceViewportInSynchronizer = synchronizer.getSourceViewports().find(sourceViewport => sourceViewport.viewportId === viewportId);
2442
+ const isTargetViewportInSynchronizer = synchronizer.getTargetViewports().find(targetViewport => targetViewport.viewportId === viewportId);
2443
+
2444
+ // if the viewport was previously a source viewport, add it again
2445
+ if (sourceViewportInfo && !isSourceViewportInSynchronizer) {
2446
+ synchronizer.addSource({
2447
+ viewportId: sourceViewportInfo.viewportId,
2448
+ renderingEngineId: sourceViewportInfo.renderingEngineId
2449
+ });
2450
+ }
2451
+
2452
+ // if the viewport was previously a target viewport, add it again
2453
+ if (targetViewportInfo && !isTargetViewportInSynchronizer) {
2454
+ synchronizer.addTarget({
2455
+ viewportId: targetViewportInfo.viewportId,
2456
+ renderingEngineId: targetViewportInfo.renderingEngineId
2457
+ });
2458
+ }
2459
+ });
2460
+ }
1504
2461
 
1505
2462
  // Component displayName
1506
2463
  OHIFCornerstoneViewport.displayName = 'OHIFCornerstoneViewport';