@aics/vole-app 2.11.0 → 2.13.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 (27) hide show
  1. package/es/aics-image-viewer/components/App/ChannelUpdater.js +11 -12
  2. package/es/aics-image-viewer/components/App/index.js +62 -30
  3. package/es/aics-image-viewer/components/AxisClipSliders/index.js +34 -25
  4. package/es/aics-image-viewer/components/BottomPanel/index.js +12 -28
  5. package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +3 -12
  6. package/es/aics-image-viewer/components/ChannelsWidgetRow/index.js +6 -2
  7. package/es/aics-image-viewer/components/ChannelsWidgetRow/styles.css +5 -1
  8. package/es/aics-image-viewer/components/ErrorAlert/index.js +1 -1
  9. package/es/aics-image-viewer/components/ErrorAlert/styles.css +3 -0
  10. package/es/aics-image-viewer/components/StyleProvider/index.js +1 -1
  11. package/es/aics-image-viewer/components/TfEditor/index.js +229 -41
  12. package/es/aics-image-viewer/components/TfEditor/styles.css +19 -7
  13. package/es/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.js +1 -1
  14. package/es/aics-image-viewer/components/Toolbar/index.js +34 -30
  15. package/es/aics-image-viewer/components/ViewerStateProvider/index.js +11 -13
  16. package/es/aics-image-viewer/shared/constants.js +41 -1
  17. package/es/aics-image-viewer/shared/utils/hooks.js +3 -3
  18. package/es/aics-image-viewer/shared/utils/viewerState.js +3 -1
  19. package/package.json +4 -3
  20. package/type-declarations/aics-image-viewer/components/App/types.d.ts +1 -1
  21. package/type-declarations/aics-image-viewer/components/BottomPanel/index.d.ts +2 -2
  22. package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +2 -2
  23. package/type-declarations/aics-image-viewer/components/TfEditor/index.d.ts +2 -0
  24. package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +1 -1
  25. package/type-declarations/aics-image-viewer/components/ViewerStateProvider/types.d.ts +2 -0
  26. package/type-declarations/aics-image-viewer/shared/constants.d.ts +8 -1
  27. package/type-declarations/aics-image-viewer/shared/types.d.ts +2 -2
@@ -31,6 +31,8 @@ var ChannelUpdater = function ChannelUpdater(_ref) {
31
31
  if (image && version > 0) {
32
32
  return effect(image);
33
33
  }
34
+ // react-hooks will check that `deps` match `effect`'s dependencies, so we can safely exclude `effect` here
35
+ // eslint-disable-next-line react-hooks/exhaustive-deps
34
36
  }, [].concat(_toConsumableArray(deps), [image, version]));
35
37
  };
36
38
 
@@ -40,30 +42,30 @@ var ChannelUpdater = function ChannelUpdater(_ref) {
40
42
  view3d.setVolumeChannelEnabled(image, index, volumeEnabled);
41
43
  view3d.updateLuts(image);
42
44
  }
43
- }, [image, volumeEnabled]);
45
+ }, [image, volumeEnabled, index, view3d]);
44
46
  useEffect(function () {
45
47
  if (image) {
46
48
  view3d.setVolumeChannelOptions(image, index, {
47
49
  isosurfaceEnabled: isosurfaceEnabled
48
50
  });
49
51
  }
50
- }, [image, isosurfaceEnabled]);
52
+ }, [image, isosurfaceEnabled, index, view3d]);
51
53
  useImageEffect(function (currentImage) {
52
54
  return view3d.setVolumeChannelOptions(currentImage, index, {
53
55
  isovalue: isovalue
54
56
  });
55
- }, [isovalue]);
57
+ }, [isovalue, index, view3d]);
56
58
  useImageEffect(function (currentImage) {
57
59
  return view3d.setVolumeChannelOptions(currentImage, index, {
58
60
  isosurfaceOpacity: opacity
59
61
  });
60
- }, [opacity]);
62
+ }, [opacity, index, view3d]);
61
63
  useImageEffect(function (currentImage) {
62
64
  view3d.setVolumeChannelOptions(currentImage, index, {
63
65
  color: color
64
66
  });
65
67
  view3d.updateLuts(currentImage);
66
- }, [color]);
68
+ }, [color, index, view3d]);
67
69
  var controlPoints = channelState.controlPoints,
68
70
  ramp = channelState.ramp,
69
71
  useControlPoints = channelState.useControlPoints;
@@ -75,22 +77,19 @@ var ChannelUpdater = function ChannelUpdater(_ref) {
75
77
  var gradient = controlPointsToLut(controlPointsToUse);
76
78
  currentImage.setLut(index, gradient);
77
79
  view3d.updateLuts(currentImage);
78
- }, [controlPoints, ramp, useControlPoints]);
80
+ }, [controlPoints, ramp, useControlPoints, index, view3d]);
79
81
  useImageEffect(function (currentImage) {
80
82
  if (colorizeEnabled) {
81
83
  // TODO get the labelColors from the tf editor component
82
84
  var lut = new Lut().createLabelColors(currentImage.getHistogram(index));
83
85
  currentImage.setColorPalette(index, lut.lut);
84
- currentImage.setColorPaletteAlpha(index, colorizeAlpha);
85
- } else {
86
- currentImage.setColorPaletteAlpha(index, 0);
86
+ // following effect will also run and call `updateLuts`
87
87
  }
88
- view3d.updateLuts(currentImage);
89
- }, [colorizeEnabled]);
88
+ }, [colorizeEnabled, index, view3d]);
90
89
  useImageEffect(function (currentImage) {
91
90
  currentImage.setColorPaletteAlpha(index, colorizeEnabled ? colorizeAlpha : 0);
92
91
  view3d.updateLuts(currentImage);
93
- }, [colorizeAlpha]);
92
+ }, [colorizeEnabled, colorizeAlpha, index, view3d]);
94
93
  return null;
95
94
  };
96
95
  export default ChannelUpdater;
@@ -23,7 +23,7 @@ import { Layout } from "antd";
23
23
  import { debounce, isEqual } from "lodash";
24
24
  import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
25
25
  import { Box3, Vector3 } from "three";
26
- import { AXIS_MARGIN_DEFAULT, CACHE_MAX_SIZE, CLIPPING_PANEL_HEIGHT_DEFAULT, CLIPPING_PANEL_HEIGHT_TALL, CONTROL_PANEL_CLOSE_WIDTH, getDefaultChannelColor, getDefaultViewerState, QUEUE_MAX_LOW_PRIORITY_SIZE, QUEUE_MAX_SIZE, SCALE_BAR_MARGIN_DEFAULT } from "../../shared/constants";
26
+ import { AXIS_MARGIN_DEFAULT, CACHE_MAX_SIZE, CLIPPING_PANEL_HEIGHT_DEFAULT, CLIPPING_PANEL_HEIGHT_TALL, CONTROL_PANEL_CLOSE_WIDTH, DTYPE_RANGE, getDefaultChannelColor, getDefaultViewerState, QUEUE_MAX_LOW_PRIORITY_SIZE, QUEUE_MAX_SIZE, SCALE_BAR_MARGIN_DEFAULT } from "../../shared/constants";
27
27
  import { ImageType, RenderMode, ViewMode } from "../../shared/enums";
28
28
  import { activeAxisMap } from "../../shared/types";
29
29
  import { colorArrayToFloats } from "../../shared/utils/colorRepresentations";
@@ -87,6 +87,7 @@ var axisToLoaderPriority = {
87
87
  y: PrefetchDirection.Y_PLUS,
88
88
  x: PrefetchDirection.X_PLUS
89
89
  };
90
+ var CLIPPING_PANEL_ANIMATION_DURATION_MS = 300;
90
91
  var setIndicatorPositions = function setIndicatorPositions(view3d, panelOpen, hasTime, hasScenes, isMode3d) {
91
92
  // The height of the clipping panel includes the button, but we're trying to put these elements next to the button
92
93
  var CLIPPING_PANEL_BUTTON_HEIGHT = 40;
@@ -115,6 +116,11 @@ var setIndicatorPositions = function setIndicatorPositions(view3d, panelOpen, ha
115
116
  view3d.setTimestepIndicatorPosition(SCALE_BAR_MARGIN_DEFAULT[0], scaleBarY);
116
117
  view3d.setScaleBarPosition(scaleBarX, scaleBarY);
117
118
  };
119
+
120
+ // TODO this component, specifically its volume loading behavior, is way out of compliance with react-hooks lints
121
+ // and will need a larger refactoring pass to fix that.
122
+ /* eslint-disable react-hooks/exhaustive-deps */
123
+ /* eslint-disable react-hooks/rules-of-hooks */
118
124
  var App = function App(props) {
119
125
  var _scenes$length, _scenes, _image$imageInfo$volu, _image$imageInfo$subr, _image$imageInfo$time, _props$transform2, _props$transform4;
120
126
  props = _objectSpread(_objectSpread({}, defaultProps), props);
@@ -223,19 +229,21 @@ var App = function App(props) {
223
229
  _useState12 = _slicedToArray(_useState11, 2),
224
230
  hasAutoClosedControlPanel = _useState12[0],
225
231
  setHasAutoClosedControlPanel = _useState12[1];
226
-
227
- // Clipping panel state doesn't need to trigger renders on change, so it can go in a ref
228
- var clippingPanelOpenRef = useRef(true);
232
+ var _useState13 = useState(true),
233
+ _useState14 = _slicedToArray(_useState13, 2),
234
+ clippingPanelOpen = _useState14[0],
235
+ setClippingPanelOpen = _useState14[1];
236
+ var clippingPanelOpenTimeout = useRef(0);
229
237
 
230
238
  // `PlayControls` manages playing through time and spatial axes, which isn't practical with "pure" React
231
239
  // Playback state goes here, but the play/pause buttons that mainly control this class are down in `AxisClipSliders`
232
240
  var playControls = useConstructor(function () {
233
241
  return new PlayControls();
234
242
  });
235
- var _useState13 = useState(null),
236
- _useState14 = _slicedToArray(_useState13, 2),
237
- playingAxis = _useState14[0],
238
- setPlayingAxis = _useState14[1];
243
+ var _useState15 = useState(null),
244
+ _useState16 = _slicedToArray(_useState15, 2),
245
+ playingAxis = _useState16[0],
246
+ setPlayingAxis = _useState16[1];
239
247
  playControls.onPlayingAxisChanged = function (axis) {
240
248
  var _loader$current, _loader$current2;
241
249
  (_loader$current = loader.current) === null || _loader$current === void 0 || _loader$current.setPrefetchPriority(axis ? [axisToLoaderPriority[axis]] : []);
@@ -288,7 +296,10 @@ var App = function App(props) {
288
296
  controlPoints = _initializeLut.controlPoints;
289
297
  changeChannelSetting(channelIndex, {
290
298
  controlPoints: controlPoints,
291
- ramp: controlPointsToRamp(ramp)
299
+ ramp: controlPointsToRamp(ramp),
300
+ // set the default range of the transfer function editor to cover the full range of the data type
301
+ plotMin: DTYPE_RANGE[thisChannel.dtype].min,
302
+ plotMax: DTYPE_RANGE[thisChannel.dtype].max
292
303
  });
293
304
  onResetChannel(channelIndex);
294
305
  } else {
@@ -301,8 +312,8 @@ var App = function App(props) {
301
312
  var oldRange = channelRangesRef.current[channelIndex];
302
313
  if (thisChannelsSettings.useControlPoints) {
303
314
  // control points were just automatically remapped - update in state
304
- // now manually remap ramp using the channel's old range
305
315
  var rampControlPoints = rampToControlPoints(thisChannelsSettings.ramp);
316
+ // now manually remap ramp using the channel's old range
306
317
  var remappedRampControlPoints = remapControlPointsForChannel(rampControlPoints, oldRange, thisChannel);
307
318
  changeChannelSetting(channelIndex, {
308
319
  ramp: controlPointsToRamp(remappedRampControlPoints),
@@ -393,7 +404,7 @@ var App = function App(props) {
393
404
  })
394
405
  });
395
406
  var mode3d = viewerSettings.viewMode === ViewMode.threeD;
396
- setIndicatorPositions(view3d, clippingPanelOpenRef.current, aimg.imageInfo.times > 1, numScenes > 1, mode3d);
407
+ setIndicatorPositions(view3d, clippingPanelOpen, aimg.imageInfo.times > 1, numScenes > 1, mode3d);
397
408
  imageLoadHandlers.current.forEach(function (effect) {
398
409
  return effect(aimg);
399
410
  });
@@ -545,25 +556,31 @@ var App = function App(props) {
545
556
  anchor.click();
546
557
  });
547
558
  }, []);
548
- var resetCamera = useCallback(function () {
549
- return view3d.resetCamera();
550
- }, []);
551
- var onClippingPanelVisibleChange = useCallback(function (panelOpen, hasTime, hasScenes, mode3d) {
552
- clippingPanelOpenRef.current = panelOpen;
559
+ var onClippingPanelOpenChange = useCallback(function (panelOpen) {
560
+ if (panelOpen === clippingPanelOpen) {
561
+ return;
562
+ }
563
+ var hasTime = numTimesteps > 1;
564
+ var hasScenes = numScenes > 1;
565
+ var mode3d = viewerSettings.viewMode === ViewMode.threeD;
566
+ setClippingPanelOpen(panelOpen);
553
567
  setIndicatorPositions(view3d, panelOpen, hasTime, hasScenes, mode3d);
554
568
 
555
569
  // Hide indicators while clipping panel is in motion - otherwise they pop to the right place prematurely
556
- view3d.setShowScaleBar(false);
557
- view3d.setShowTimestepIndicator(false);
558
- view3d.setShowAxis(false);
559
- }, [viewerSettings.showAxes]);
560
- var onClippingPanelVisibleChangeEnd = useCallback(function () {
561
- view3d.setShowScaleBar(true);
562
- view3d.setShowTimestepIndicator(true);
563
- if (viewerSettings.showAxes) {
564
- view3d.setShowAxis(true);
570
+ if (panelOpen) {
571
+ view3d.setShowScaleBar(false);
572
+ view3d.setShowTimestepIndicator(false);
573
+ view3d.setShowAxis(false);
574
+ window.clearTimeout(clippingPanelOpenTimeout.current);
575
+ clippingPanelOpenTimeout.current = window.setTimeout(function () {
576
+ view3d.setShowScaleBar(true);
577
+ view3d.setShowTimestepIndicator(true);
578
+ if (viewerSettings.showAxes) {
579
+ view3d.setShowAxis(true);
580
+ }
581
+ }, CLIPPING_PANEL_ANIMATION_DURATION_MS);
565
582
  }
566
- }, [viewerSettings.showAxes]);
583
+ }, [view3d, numTimesteps, numScenes, viewerSettings.viewMode, viewerSettings.showAxes, clippingPanelOpen]);
567
584
  var getMetadata = useCallback(function () {
568
585
  var _props2 = props,
569
586
  metadata = _props2.metadata,
@@ -572,12 +589,24 @@ var App = function App(props) {
572
589
  if (imageMetadata && metadataFormatter) {
573
590
  imageMetadata = metadataFormatter(imageMetadata);
574
591
  }
592
+ var sceneMeta;
593
+ if (Array.isArray(metadata)) {
594
+ // If metadata is an array, try to index it by scene
595
+ if (metadata.length >= numScenes) {
596
+ sceneMeta = metadata[viewerState.current.scene];
597
+ } else {
598
+ sceneMeta = metadata[0];
599
+ }
600
+ } else {
601
+ sceneMeta = metadata;
602
+ }
575
603
  if (imageMetadata && Object.keys(imageMetadata).length > 0) {
576
604
  return _objectSpread({
577
605
  Image: imageMetadata
578
- }, metadata);
606
+ }, sceneMeta);
579
607
  } else {
580
- return metadata || {};
608
+ var _sceneMeta;
609
+ return (_sceneMeta = sceneMeta) !== null && _sceneMeta !== void 0 ? _sceneMeta : {};
581
610
  }
582
611
  }, [props.metadata, props.metadataFormatter, image]);
583
612
 
@@ -777,6 +806,9 @@ var App = function App(props) {
777
806
  var pixelSize = useMemo(function () {
778
807
  return image ? image.imageInfo.physicalPixelSize.toArray() : [1, 1, 1];
779
808
  }, [image === null || image === void 0 ? void 0 : image.imageInfo.physicalPixelSize]);
809
+ var resetCamera = useMemo(function () {
810
+ return view3d.resetCamera.bind(view3d);
811
+ }, [view3d]);
780
812
  return /*#__PURE__*/React.createElement(StyleProvider, null, errorAlert, /*#__PURE__*/React.createElement(Layout, {
781
813
  className: "cell-viewer-app",
782
814
  style: {
@@ -842,8 +874,8 @@ var App = function App(props) {
842
874
  playingAxis: playingAxis,
843
875
  appHeight: props.appHeight,
844
876
  visibleControls: visibleControls,
845
- onClippingPanelVisibleChange: onClippingPanelVisibleChange,
846
- onClippingPanelVisibleChangeEnd: onClippingPanelVisibleChangeEnd
877
+ clippingPanelOpen: clippingPanelOpen,
878
+ onClippingPanelOpenChange: onClippingPanelOpenChange
847
879
  })))));
848
880
  };
849
881
  export default App;
@@ -29,23 +29,30 @@ var SliderRow = function SliderRow(_ref) {
29
29
  onStart = _ref.onStart,
30
30
  onEnd = _ref.onEnd;
31
31
  var isRange = vals.length > 1;
32
- // If slider is a range, handles represent slice *edges*: the range around only the max slice is [max-1, max], e.g.
33
- // If slider is not a range, handle represents 0-indexed slices: last slice is at max-1
34
- var inputMax = isRange ? max : max - 1;
32
+ // If slider is a range, handles represent slice *edges*: the range around only the 1st slice is [0, 1]; the range
33
+ // around only the last is [max-1, max].
34
+ // If slider is not a range, just work with slices, but don't 0-index: 1st slice is 1, last is max
35
+ var min = isRange ? 0 : 1;
36
+ var wrappedOnSlide = isRange ? onSlide : function (values) {
37
+ return onSlide === null || onSlide === void 0 ? void 0 : onSlide([values[0] - 1]);
38
+ };
39
+ var wrappedOnChange = isRange ? _onChange : function (values) {
40
+ return _onChange === null || _onChange === void 0 ? void 0 : _onChange([values[0] - 1]);
41
+ };
35
42
  return /*#__PURE__*/React.createElement("span", {
36
43
  className: "axis-slider-container"
37
44
  }, /*#__PURE__*/React.createElement("span", {
38
45
  className: "slider-name"
39
- }, label), inputMax === 0 ? /*#__PURE__*/React.createElement("i", null, "No values to adjust") : /*#__PURE__*/React.createElement("span", {
46
+ }, label), max === 0 ? /*#__PURE__*/React.createElement("i", null, "No values to adjust") : /*#__PURE__*/React.createElement("span", {
40
47
  className: "axis-slider"
41
48
  }, /*#__PURE__*/React.createElement(SmarterSlider, {
42
49
  className: isRange ? "" : "slider-single-handle",
43
50
  connect: true,
44
51
  range: {
45
- min: 0,
46
- max: inputMax
52
+ min: min,
53
+ max: max
47
54
  },
48
- start: vals,
55
+ start: isRange ? vals : [vals[0] + 1],
49
56
  step: 1,
50
57
  margin: 1,
51
58
  behaviour: "drag",
@@ -66,28 +73,33 @@ var SliderRow = function SliderRow(_ref) {
66
73
  to: Math.round,
67
74
  from: parseInt
68
75
  },
69
- onSlide: onSlide,
70
- onChange: _onChange,
76
+ onSlide: wrappedOnSlide,
77
+ onChange: wrappedOnChange,
71
78
  onStart: onStart,
72
79
  onEnd: onEnd
73
- })), inputMax > 0 && /*#__PURE__*/React.createElement("span", {
80
+ })), max > 0 && /*#__PURE__*/React.createElement("span", {
74
81
  className: "slider-values"
75
82
  }, /*#__PURE__*/React.createElement(NumericInput, {
76
- max: inputMax,
77
- value: valsReadout[0],
83
+ min: min,
84
+ max: max,
85
+ value: valsReadout[0] + (isRange ? 0 : 1),
78
86
  onChange: function onChange(value) {
79
- return _onChange === null || _onChange === void 0 ? void 0 : _onChange(isRange ? [value, vals[1]] : [value]);
87
+ return _onChange === null || _onChange === void 0 ? void 0 : _onChange(isRange ? [value, vals[1]] : [value - 1]);
80
88
  }
81
89
  }), isRange && /*#__PURE__*/React.createElement(React.Fragment, null, " , ", /*#__PURE__*/React.createElement(NumericInput, {
82
- max: inputMax,
90
+ min: min,
91
+ max: max,
83
92
  value: valsReadout[1],
84
93
  onChange: function onChange(value) {
85
94
  return _onChange === null || _onChange === void 0 ? void 0 : _onChange([vals[0], value]);
86
95
  }
87
- })), " / ", max - 1));
96
+ })), " / ", max));
88
97
  };
89
98
  /** Wrapper around `SliderRow` that adds a play button and accounts for the case where not all of an axis is loaded */
90
99
  var PlaySliderRow = function PlaySliderRow(props) {
100
+ var onChange = props.onChange,
101
+ onStart = props.onStart,
102
+ onEnd = props.onEnd;
91
103
  // In partially-loaded axes, stores the displayed value of the slider while the user is sliding it
92
104
  var _useState = useState(props.val),
93
105
  _useState2 = _slicedToArray(_useState, 2),
@@ -99,27 +111,24 @@ var PlaySliderRow = function PlaySliderRow(props) {
99
111
  sliderHeld = _useState4[0],
100
112
  setSliderHeld = _useState4[1];
101
113
  var wrappedOnChange = useCallback(function (_ref2) {
102
- var _props$onChange;
103
114
  var _ref3 = _slicedToArray(_ref2, 1),
104
115
  val = _ref3[0];
105
- return (_props$onChange = props.onChange) === null || _props$onChange === void 0 ? void 0 : _props$onChange.call(props, val);
106
- }, [props.onChange]);
116
+ return onChange === null || onChange === void 0 ? void 0 : onChange(val);
117
+ }, [onChange]);
107
118
  var wrappedSetValReadout = useCallback(function (_ref4) {
108
119
  var _ref5 = _slicedToArray(_ref4, 1),
109
120
  val = _ref5[0];
110
121
  return setValReadout(val);
111
122
  }, []);
112
123
  var wrappedOnStart = useCallback(function () {
113
- var _props$onStart;
114
124
  setValReadout(props.val);
115
125
  setSliderHeld(true);
116
- (_props$onStart = props.onStart) === null || _props$onStart === void 0 || _props$onStart.call(props);
117
- }, [props.onStart]);
126
+ onStart === null || onStart === void 0 || onStart();
127
+ }, [onStart, props.val]);
118
128
  var wrappedOnEnd = useCallback(function () {
119
- var _props$onEnd;
120
129
  setSliderHeld(false);
121
- (_props$onEnd = props.onEnd) === null || _props$onEnd === void 0 || _props$onEnd.call(props);
122
- }, [props.onEnd]);
130
+ onEnd === null || onEnd === void 0 || onEnd();
131
+ }, [onEnd]);
123
132
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SliderRow, {
124
133
  label: props.label,
125
134
  vals: [props.val],
@@ -172,7 +181,7 @@ var AxisClipSliders = function AxisClipSliders(props) {
172
181
  // Pause when view mode or volume size has changed
173
182
  useEffect(function () {
174
183
  return props.playControls.pause();
175
- }, [props.mode, props.image]);
184
+ }, [props.mode, props.image, props.playControls]);
176
185
  var handlePlayPause = function handlePlayPause(axis, willPlay) {
177
186
  if (willPlay) {
178
187
  props.playControls.play(axis);
@@ -5,41 +5,26 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
5
5
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
6
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
7
  import { Button, Drawer } from "antd";
8
- import React, { useEffect, useState } from "react";
8
+ import React, { useCallback, useState } from "react";
9
9
  import ViewerIcon from "../shared/ViewerIcon";
10
10
  import "./styles.css";
11
11
  var BottomPanel = function BottomPanel(_ref) {
12
12
  var children = _ref.children,
13
+ openProp = _ref.open,
13
14
  title = _ref.title,
14
15
  height = _ref.height,
15
- onVisibleChange = _ref.onVisibleChange,
16
- onVisibleChangeEnd = _ref.onVisibleChangeEnd;
16
+ onOpenChange = _ref.onOpenChange;
17
17
  var _useState = useState(true),
18
18
  _useState2 = _slicedToArray(_useState, 2),
19
- isVisible = _useState2[0],
20
- setIsVisible = _useState2[1];
21
-
22
- // Call `onVisibleChange` on mount
23
- useEffect(function () {
24
- onVisibleChange === null || onVisibleChange === void 0 || onVisibleChange(isVisible);
25
- if (!isVisible) {
26
- onVisibleChangeEnd === null || onVisibleChangeEnd === void 0 || onVisibleChangeEnd(isVisible);
19
+ openState = _useState2[0],
20
+ setOpenState = _useState2[1];
21
+ var open = openProp !== null && openProp !== void 0 ? openProp : openState;
22
+ var toggleDrawer = useCallback(function () {
23
+ if (openProp === undefined) {
24
+ setOpenState(!open);
27
25
  }
28
- }, []);
29
-
30
- // Treat changes in height as a change in visibility if the panel is open
31
- useEffect(function () {
32
- onVisibleChange === null || onVisibleChange === void 0 || onVisibleChange(isVisible);
33
- window.setTimeout(function () {
34
- return onVisibleChangeEnd === null || onVisibleChangeEnd === void 0 ? void 0 : onVisibleChangeEnd(isVisible);
35
- }, 300);
36
- }, [height]);
37
- var toggleDrawer = function toggleDrawer() {
38
- setIsVisible(!isVisible);
39
- if (onVisibleChange) {
40
- onVisibleChange(!isVisible);
41
- }
42
- };
26
+ onOpenChange === null || onOpenChange === void 0 || onOpenChange(!open);
27
+ }, [open, openProp, onOpenChange]);
43
28
  var optionsButton = /*#__PURE__*/React.createElement(Button, {
44
29
  className: "options-button",
45
30
  size: "small",
@@ -58,10 +43,9 @@ var BottomPanel = function BottomPanel(_ref) {
58
43
  placement: "bottom",
59
44
  closable: false,
60
45
  getContainer: false,
61
- open: isVisible,
46
+ open: open,
62
47
  mask: false,
63
48
  title: optionsButton,
64
- afterOpenChange: onVisibleChangeEnd,
65
49
  height: height !== null && height !== void 0 ? height : 190
66
50
  }, /*#__PURE__*/React.createElement("div", {
67
51
  className: "drawer-body-wrapper"
@@ -16,13 +16,7 @@ var ViewerWrapper = function ViewerWrapper(props) {
16
16
  var view3dviewerRef = /*#__PURE__*/React.createRef();
17
17
  React.useEffect(function () {
18
18
  view3dviewerRef.current.appendChild(props.view3d.getDOMElement());
19
- props.view3d.setAutoRotate(props.autorotate);
20
- }, []);
21
-
22
- // TODO necessary?
23
- React.useEffect(function () {
24
- props.view3d.resize(null);
25
- });
19
+ }, [props.view3d, view3dviewerRef]);
26
20
  var renderOverlay = function renderOverlay() {
27
21
  // Don't show spinner during playback - we may be constantly loading new data, it'll block the view!
28
22
  var showSpinner = props.loadingImage && !props.playingAxis;
@@ -62,11 +56,8 @@ var ViewerWrapper = function ViewerWrapper(props) {
62
56
  style: STYLES.view3d
63
57
  }), /*#__PURE__*/React.createElement(BottomPanel, {
64
58
  title: "Clipping",
65
- onVisibleChange: function onVisibleChange(visible) {
66
- var _props$onClippingPane;
67
- (_props$onClippingPane = props.onClippingPanelVisibleChange) === null || _props$onClippingPane === void 0 || _props$onClippingPane.call(props, visible, numTimesteps > 1, numScenes > 1, viewMode === ViewMode.threeD);
68
- },
69
- onVisibleChangeEnd: props.onClippingPanelVisibleChangeEnd,
59
+ open: props.clippingPanelOpen,
60
+ onOpenChange: props.onClippingPanelOpenChange,
70
61
  height: clippingPanelTall ? CLIPPING_PANEL_HEIGHT_TALL : CLIPPING_PANEL_HEIGHT_DEFAULT
71
62
  }, visibleControls.axisClipSliders && !!props.image && /*#__PURE__*/React.createElement(AxisClipSliders, {
72
63
  mode: viewMode,
@@ -93,7 +93,9 @@ var ChannelsWidgetRow = function ChannelsWidgetRow(props) {
93
93
  colorizeEnabled = channelState.colorizeEnabled,
94
94
  colorizeAlpha = channelState.colorizeAlpha,
95
95
  useControlPoints = channelState.useControlPoints,
96
- ramp = channelState.ramp;
96
+ ramp = channelState.ramp,
97
+ plotMin = channelState.plotMin,
98
+ plotMax = channelState.plotMax;
97
99
  return /*#__PURE__*/React.createElement(TfEditor, {
98
100
  id: "TFEditor" + index,
99
101
  width: 418,
@@ -104,7 +106,9 @@ var ChannelsWidgetRow = function ChannelsWidgetRow(props) {
104
106
  colorizeEnabled: colorizeEnabled,
105
107
  colorizeAlpha: colorizeAlpha,
106
108
  useControlPoints: useControlPoints,
107
- ramp: ramp
109
+ ramp: ramp,
110
+ plotMin: plotMin,
111
+ plotMax: plotMax
108
112
  });
109
113
  };
110
114
  var renderSurfaceControls = function renderSurfaceControls() {
@@ -30,9 +30,13 @@
30
30
  display:flex;
31
31
  justify-content:start;
32
32
  align-items:end;
33
- gap:6px;
33
+ gap:5px;
34
34
  }
35
35
 
36
+ .channel-rows-list .ant-list-item.channel-row .button-row .ant-btn.ant-btn-sm{
37
+ padding:12px 8px;
38
+ }
39
+
36
40
  .channel-rows-list .ant-list-item.channel-row.controls-closed .ant-btn-text:not(:focus-visible){
37
41
  color:var(--color-controlpanel-text);
38
42
  }
@@ -119,7 +119,7 @@ export var useErrorAlert = function useErrorAlert() {
119
119
  return [].concat(_toConsumableArray(prev), [errorSeenCount]);
120
120
  });
121
121
  seenErrors.set(errorTitle, errorSeenCount);
122
- }, []);
122
+ }, [seenErrors]);
123
123
  var onSkipError = React.useCallback(function () {
124
124
  setErrorList(function (prev) {
125
125
  return prev.slice(1);
@@ -16,6 +16,9 @@
16
16
  .load-error-alert .ant-btn-text{
17
17
  color:var(--color-text-link);
18
18
  }
19
+ .load-error-alert .ant-btn-text:hover{
20
+ color:#25affe !important;
21
+ }
19
22
  .load-error-alert .ant-alert-message div:first-child{
20
23
  color:var(--color-text-section);
21
24
  font-weight:600;
@@ -134,7 +134,7 @@ var theme = {
134
134
  }
135
135
  };
136
136
  /** Makes theme styling available to child components via CSS variables. */
137
- var CssProvider = styled.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n width: 100%;\n height: 100%;\n\n ", "\n\n h1, h2, h3, h4, p {\n font-family: var(--font-family);\n }\n\n h1 {\n color: var(--color-text-header);\n font-size: 28px;\n font-weight: 400;\n }\n\n h2 {\n color: var(--color-text-section);\n font-size: 19px;\n font-weight: 400;\n }\n\n h3 {\n color: var(--color-text-header);\n font-size: 16px;\n font-weight: 600;\n }\n\n h4 {\n color: var(--color-text-header);\n font-size: 14px;\n font-weight: 400;\n }\n\n p {\n color: var(--color-text-body);\n font-size: 14px;\n font-weight: 400;\n }\n\n a {\n color: var(--color-text-link);\n &:not(:focus-visible) {\n text-decoration: none;\n }\n\n &:focus-visible {\n text-decoration: underline;\n }\n }\n\n & *::selection {\n background-color: var(--color-text-selection-bg);\n color: var(--color-text-selection-text);\n }\n\n /** TODO: Go through these styles and see if we can use Ant ConfigProvider for them instead. */\n .ant-btn-link,\n .ant-btn-text,\n .ant-btn-primary,\n .ant-btn-icon-only {\n box-shadow: none;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border-color: var(--color-button-primary-hover-bg);\n color: var(--color-button-primary-text);\n }\n\n &:active:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border: 1px solid var(--color-button-primary-active-outline);\n color: var(--color-button-primary-text);\n }\n }\n\n /* Let us use buttons with type=\"text\" as purely semantic containers - don't bring any styling! */\n .ant-btn-text {\n width: unset;\n height: unset;\n padding: unset;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: unset;\n border-color: transparent;\n }\n }\n\n .ant-btn-icon-only:disabled {\n color: var(--color-button-icon-disabled-text);\n }\n\n .ant-btn-link:not(:disabled) {\n // Change from default blue link text\n color: var(--color-button-link-text);\n }\n\n /**\n * Tertiary style buttons. Grey outline by default, turns to light\n * purple outline on hover.\n */\n .ant-btn-default:not(.ant-btn-icon-only) {\n background-color: var(--color-button-tertiary-bg);\n color: var(--color-button-tertiary-text);\n border-color: var(--color-button-tertiary-outline);\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: transparent;\n border-color: var(--color-button-tertiary-hover-bg);\n color: var(--color-button-tertiary-hover-text);\n }\n\n &:active:not(:disabled) {\n background-color: transparent;\n border-color: var(--color-button-tertiary-active-outline);\n color: var(--color-button-tertiary-active-text);\n }\n }\n\n // Overrides for checkbox styling\n & .ant-checkbox-input {\n &:hover,\n &:focus-visible {\n border: 1px solid white;\n }\n }\n\n & .ant-checkbox.ant-checkbox-checked {\n background-color: var(--color-checkbox-bg);\n }\n\n .ant-checkbox-inner {\n background-color: transparent;\n }\n\n & .ant-checkbox-indeterminate.checked .ant-checkbox-inner {\n background-color: var(--color-checkbox-bg);\n }\n\n // Add outlines to modals and dropdowns\n & .ant-select-dropdown,\n & .ant-dropdown-menu,\n & .ant-modal-content {\n border: 1px solid var(--color-modal-border);\n }\n\n // Force active/hovered text to be white instead of grey for better contrast\n & .ant-dropdown-menu-item-active {\n color: var(--color-menu-hover-text);\n }\n\n // Remove padding in dropdown menus and make items reactangular + flush with the edge\n & .ant-dropdown-menu,\n & .ant-select-dropdown {\n padding: 0;\n overflow: hidden;\n\n & .ant-dropdown-menu-item,\n & .ant-select-item {\n border-radius: 0;\n }\n }\n"])), function (_ref) {
137
+ var CssProvider = styled.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n width: 100%;\n height: 100%;\n\n ", "\n\n h1, h2, h3, h4, p {\n font-family: var(--font-family);\n }\n\n h1 {\n color: var(--color-text-header);\n font-size: 28px;\n font-weight: 400;\n }\n\n h2 {\n color: var(--color-text-section);\n font-size: 19px;\n font-weight: 400;\n }\n\n h3 {\n color: var(--color-text-header);\n font-size: 16px;\n font-weight: 600;\n }\n\n h4 {\n color: var(--color-text-header);\n font-size: 14px;\n font-weight: 400;\n }\n\n p {\n color: var(--color-text-body);\n font-size: 14px;\n font-weight: 400;\n }\n\n a {\n color: var(--color-text-link);\n }\n\n & *::selection {\n background-color: var(--color-text-selection-bg);\n color: var(--color-text-selection-text);\n }\n\n /** TODO: Go through these styles and see if we can use Ant ConfigProvider for them instead. */\n .ant-btn-link,\n .ant-btn-text,\n .ant-btn-primary,\n .ant-btn-icon-only {\n box-shadow: none;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border-color: var(--color-button-primary-hover-bg);\n color: var(--color-button-primary-text);\n }\n\n &:active:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border: 1px solid var(--color-button-primary-active-outline);\n color: var(--color-button-primary-text);\n }\n }\n\n /* Let us use buttons with type=\"text\" as purely semantic containers - don't bring any styling! */\n .ant-btn-text {\n width: unset;\n height: unset;\n padding: unset;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: unset;\n border-color: transparent;\n }\n }\n\n .ant-btn-icon-only:disabled {\n color: var(--color-button-icon-disabled-text);\n }\n\n .ant-btn-link:not(:disabled) {\n // Change from default blue link text\n color: var(--color-button-link-text);\n }\n\n /**\n * Tertiary style buttons. Grey outline by default, turns to light\n * purple outline on hover.\n */\n .ant-btn-default:not(.ant-btn-icon-only) {\n background-color: var(--color-button-tertiary-bg);\n color: var(--color-button-tertiary-text);\n border-color: var(--color-button-tertiary-outline);\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: transparent;\n border-color: var(--color-button-tertiary-hover-bg);\n color: var(--color-button-tertiary-hover-text);\n }\n\n &:active:not(:disabled) {\n background-color: transparent;\n border-color: var(--color-button-tertiary-active-outline);\n color: var(--color-button-tertiary-active-text);\n }\n }\n\n // Overrides for checkbox styling\n & .ant-checkbox-input {\n &:hover,\n &:focus-visible {\n border: 1px solid white;\n }\n }\n\n & .ant-checkbox.ant-checkbox-checked {\n background-color: var(--color-checkbox-bg);\n }\n\n .ant-checkbox-inner {\n background-color: transparent !important;\n }\n\n // Add outlines to modals and dropdowns\n & .ant-select-dropdown,\n & .ant-dropdown-menu,\n & .ant-modal-content {\n border: 1px solid var(--color-modal-border);\n }\n\n // Force active/hovered text to be white instead of grey for better contrast\n & .ant-dropdown-menu-item-active {\n color: var(--color-menu-hover-text);\n }\n\n // Remove padding in dropdown menus and make items reactangular + flush with the edge\n & .ant-dropdown-menu,\n & .ant-select-dropdown {\n padding: 0;\n overflow: hidden;\n\n & .ant-dropdown-menu-item,\n & .ant-select-item {\n border-radius: 0;\n }\n }\n"])), function (_ref) {
138
138
  var $theme = _ref.$theme;
139
139
  return css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n /* Component and color variables. */\n // TODO: Fix inconsistent use of border vs. outline\n // TODO: Remove variables that aren't used in other CSS files. These should be set directly\n // from the $theme object to reduce unnecessary variables.\n --color-text-link: ", ";\n --color-text-header: ", ";\n --color-text-section: ", ";\n --color-text-body: ", ";\n --color-text-error: ", ";\n\n --color-text-selection-bg: ", ";\n --color-text-selection-text: ", ";\n\n --color-header-title: ", ";\n --color-header-hover-title: ", ";\n --color-header-bg: ", ";\n --color-header-border: ", ";\n\n --color-button-primary-bg: ", ";\n --color-button-primary-text: ", ";\n --color-button-primary-hover-bg: ", ";\n --color-button-primary-active-bg: ", ";\n --color-button-primary-active-outline: ", ";\n --color-button-primary-disabled-bg: ", ";\n\n --color-button-link-text: ", ";\n\n --color-button-secondary-bg: ", ";\n --color-button-secondary-text: ", ";\n --color-button-secondary-outline: ", ";\n\n --color-button-tertiary-bg: transparent;\n --color-button-tertiary-text: ", ";\n --color-button-tertiary-outline: ", ";\n --color-button-tertiary-hover-outline: ", ";\n --color-button-tertiary-hover-text: ", ";\n --color-button-tertiary-active-outline: ", ";\n --color-button-tertiary-active-text: ", ";\n\n --color-button-icon-disabled-text: ", ";\n --color-button-icon-disabled-text: ", ";\n --color-button-icon-activated-text: ", ";\n --color-button-icon-activated-bg: ", ";\n --color-button-icon-activated-outline: ", ";\n\n --color-toolbar-button-bg: ", ";\n\n --color-controlpanel-bg: ", ";\n --color-controlpanel-border: ", ";\n --color-controlpanel-section-text: ", ";\n --color-controlpanel-text: ", ";\n --color-controlpanel-section-bg: ", ";\n --color-controlpanel-drawer-bg: ", ";\n --color-controlpanel-ramp-slider: ", ";\n\n --color-landingpage-bg: ", ";\n --color-landingpage-bg-alt: ", ";\n --color-landingpage-text: ", ";\n --color-landingpage-banner-highlight-bg: ", ";\n\n --color-statusflag-border: ", ";\n --color-statusflag-text: ", ";\n\n --color-layout-dividers: ", ";\n\n --color-modal-border: ", ";\n\n --color-menu-hover-text: ", ";\n --color-menu-selected-text: ", ";\n\n --color-checkbox-bg: ", ";\n\n --font-family: ", ";\n "])), $theme.colors.text.link, $theme.colors.text.header, $theme.colors.text.section, $theme.colors.text.body, $theme.colors.text.error, $theme.colors.text.selectionBg, $theme.colors.text.selectionText, $theme.colors.header.title, $theme.colors.header.hoverTitle, $theme.colors.header.bg, $theme.colors.header.border, $theme.colors.button.primary.bg, $theme.colors.button.primary.text, $theme.colors.button.primary.hoverBg, $theme.colors.button.primary.hoverBg, $theme.colors.button.primary.activeOutline, $theme.colors.button.primary.disabledBg, $theme.colors.button.link.text, $theme.colors.button.secondary.bg, $theme.colors.button.secondary.text, $theme.colors.button.secondary.outline, $theme.colors.button.tertiary.text, $theme.colors.button.tertiary.outline, $theme.colors.button.tertiary.hoverOutline, $theme.colors.button.tertiary.hoverText, $theme.colors.button.tertiary.activeOutline, $theme.colors.button.tertiary.hoverText, $theme.colors.button.tertiary.disabledText, $theme.colors.button.tertiary.disabledText, $theme.colors.button.tertiary.activatedText, $theme.colors.button.tertiary.activatedBg, $theme.colors.button.tertiary.activatedOutline, $theme.colors.toolbar.buttonBg, $theme.colors.controlPanel.bg, $theme.colors.controlPanel.border, $theme.colors.controlPanel.sectionText, $theme.colors.controlPanel.text, $theme.colors.controlPanel.sectionBg, $theme.colors.controlPanel.drawerBg, $theme.colors.controlPanel.rampSlider, $theme.colors.landingPage.bg, $theme.colors.landingPage.bgAlt, $theme.colors.landingPage.text, $theme.colors.landingPage.bannerBg, $theme.colors.statusFlag.border, $theme.colors.statusFlag.text, $theme.colors.layout.dividers, $theme.colors.modal.border, $theme.colors.menu.hoverText, $theme.colors.menu.selectedText, $theme.colors.checkbox.bg, $theme.fonts.family);
140
140
  });