@aics/vole-app 3.3.0 → 3.4.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 (60) hide show
  1. package/LICENSE +21 -25
  2. package/es/aics-image-viewer/components/App/index.js +11 -9
  3. package/es/aics-image-viewer/components/BottomPanel/index.js +48 -19
  4. package/es/aics-image-viewer/components/BottomPanel/styles.css +16 -7
  5. package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +39 -19
  6. package/es/aics-image-viewer/components/ChannelsWidget.js +2 -2
  7. package/es/aics-image-viewer/components/ControlPanel/index.js +17 -11
  8. package/es/aics-image-viewer/components/ControlPanel/styles.css +5 -5
  9. package/es/aics-image-viewer/components/ErrorAlert/index.js +91 -64
  10. package/es/aics-image-viewer/components/ErrorAlert/styles.css +33 -4
  11. package/es/aics-image-viewer/components/StyleProvider/index.js +42 -22
  12. package/es/aics-image-viewer/components/TfEditor/index.js +8 -1
  13. package/es/aics-image-viewer/components/Toolbar/index.js +33 -12
  14. package/es/aics-image-viewer/components/Toolbar/styles.css +21 -130
  15. package/es/aics-image-viewer/components/dimension_sliders/AxisClipSliders.js +148 -0
  16. package/es/aics-image-viewer/components/dimension_sliders/RotationSliders.js +165 -0
  17. package/es/aics-image-viewer/components/dimension_sliders/SliderRows.js +167 -0
  18. package/es/aics-image-viewer/components/{AxisClipSliders → dimension_sliders}/styles.css +7 -1
  19. package/es/aics-image-viewer/components/shared/ControlPanelRow/styles.css +1 -1
  20. package/es/aics-image-viewer/components/shared/NumericInput/index.js +4 -2
  21. package/es/aics-image-viewer/components/shared/SliderRow/index.js +2 -0
  22. package/es/aics-image-viewer/components/shared/SliderRow/styles.css +2 -1
  23. package/es/aics-image-viewer/components/useVolume.js +3 -0
  24. package/es/aics-image-viewer/shared/constants.js +2 -2
  25. package/es/aics-image-viewer/shared/utils/camera.js +122 -0
  26. package/es/aics-image-viewer/shared/utils/playControls.js +12 -1
  27. package/es/aics-image-viewer/shared/utils/sceneStore.js +8 -0
  28. package/es/aics-image-viewer/shared/utils/test/camera.test.js +127 -0
  29. package/es/aics-image-viewer/shared/utils/test/urlParsing.test.js +23 -702
  30. package/es/aics-image-viewer/shared/utils/urlParsing.js +14 -828
  31. package/es/aics-image-viewer/shared/utils/viewerChannelSettings.js +3 -4
  32. package/es/aics-image-viewer/state/deserialize.js +437 -0
  33. package/es/aics-image-viewer/state/serialize.js +145 -0
  34. package/es/aics-image-viewer/state/test/deserialize.test.js +432 -0
  35. package/es/aics-image-viewer/state/test/serialize.test.js +97 -0
  36. package/es/aics-image-viewer/state/test/test_data.js +168 -0
  37. package/es/aics-image-viewer/state/types.js +265 -1
  38. package/package.json +6 -5
  39. package/type-declarations/aics-image-viewer/components/App/types.d.ts +2 -2
  40. package/type-declarations/aics-image-viewer/components/BottomPanel/index.d.ts +6 -3
  41. package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +1 -0
  42. package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +4 -5
  43. package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +8 -5
  44. package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +2 -1
  45. package/type-declarations/aics-image-viewer/components/{AxisClipSliders/index.d.ts → dimension_sliders/AxisClipSliders.d.ts} +2 -3
  46. package/type-declarations/aics-image-viewer/components/dimension_sliders/RotationSliders.d.ts +6 -0
  47. package/type-declarations/aics-image-viewer/components/dimension_sliders/SliderRows.d.ts +31 -0
  48. package/type-declarations/aics-image-viewer/components/shared/NumericInput/index.d.ts +1 -0
  49. package/type-declarations/aics-image-viewer/components/shared/SliderRow/index.d.ts +3 -1
  50. package/type-declarations/aics-image-viewer/components/useVolume.d.ts +1 -1
  51. package/type-declarations/aics-image-viewer/shared/constants.d.ts +1 -1
  52. package/type-declarations/aics-image-viewer/shared/utils/camera.d.ts +19 -0
  53. package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +1 -0
  54. package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +2 -1
  55. package/type-declarations/aics-image-viewer/shared/utils/urlParsing.d.ts +1 -307
  56. package/type-declarations/aics-image-viewer/state/deserialize.d.ts +70 -0
  57. package/type-declarations/aics-image-viewer/state/serialize.d.ts +20 -0
  58. package/type-declarations/aics-image-viewer/state/types.d.ts +216 -0
  59. package/LICENSE.txt +0 -26
  60. package/es/aics-image-viewer/components/AxisClipSliders/index.js +0 -295
@@ -108,155 +108,46 @@
108
108
  margin-right:6px;
109
109
  }
110
110
 
111
+ .viewer-toolbar .btn-borderless,
112
+ .viewer-toolbar .ant-select.ant-select-outlined .ant-select-selector,
113
+ .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-checked){
114
+ background-color:var(--color-toolbar-button-bg);
115
+ }
116
+
111
117
  .viewer-toolbar .ant-btn-icon-only{
112
118
  padding-bottom:4px;
113
119
  padding-left:1px;
114
120
  }
115
121
 
116
122
  .viewer-toolbar .btn-borderless{
117
- background-color:var(--color-toolbar-button-bg);
118
123
  border-color:transparent;
119
124
  color:var(--color-text-body);
120
125
  }
121
126
 
122
127
  .viewer-toolbar .btn-active{
123
- color:var(--color-button-icon-activated-text);
124
- background-color:var(--color-button-icon-activated-bg);
125
- border:1px solid var(--color-button-icon-activated-outline);
128
+ color:var(--color-button-icon-active-text);
129
+ background-color:var(--color-button-icon-active-bg);
130
+ border:1px solid var(--color-button-icon-active-outline);
126
131
  }
127
132
 
128
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled){
129
- background-color:black;
130
- box-shadow:-1px 0px 0px 0px transparent;
131
- transition-property:color, background-color, border-color, box-shadow;
132
- }
133
-
134
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled).ant-radio-button-wrapper-checked,
135
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):hover{
136
- outline:none;
137
- color:white;
138
- border-color:#aeacae;
139
- }
140
-
141
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled).ant-radio-button-wrapper-checked:not(:first-child), .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):hover:not(:first-child){
142
- box-shadow:-1px 0px 0px 0px #aeacae;
143
- }
144
-
145
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled).ant-radio-button-wrapper-checked{
146
- background-color:#4b4b4b;
147
- }
148
-
149
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):hover{
150
- background-color:#aa88ed;
151
- color:white;
152
- }
133
+ .viewer-toolbar{
134
+ --color-button-radio-hover-outline:var(--color-button-tertiary-active-outline);
135
+ --color-button-radio-hover-text:var(--color-button-icon-active-text);
136
+ }
153
137
 
154
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):focus-within{
155
- outline:none;
156
- }
138
+ .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):hover,
139
+ .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):has(:focus-visible){
140
+ background-color:var(--color-button-tertiary-hover-text);
141
+ }
157
142
 
158
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled)::before{
159
- content:none;
143
+ .viewer-toolbar .ant-select.select-resolution > .ant-select-selector{
144
+ text-align:left;
160
145
  }
161
146
 
162
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting{
163
- min-width:120px;
164
- }
165
-
166
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting .ant-select-selection-item,
167
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting .ant-select-arrow{
147
+ .viewer-toolbar .ant-select.select-resolution .ant-select-selection-item{
168
148
  color:var(--color-button-tertiary-text);
169
- transition:all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
170
149
  }
171
150
 
172
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting.ant-select-disabled .ant-select-selection-item,
173
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting.ant-select-disabled .ant-select-selection-search{
174
- padding-inline-end:0;
175
- }
176
-
177
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting.ant-select-disabled .ant-select-selection-item{
178
- color:var(--color-button-icon-disabled-text);
179
- }
180
-
181
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting.ant-select-disabled .ant-select-selection-item:hover{
182
- color:var(--color-button-icon-disabled-text);
183
- }
184
-
185
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting.ant-select-disabled .ant-select-selector{
186
- border-color:var(--color-button-icon-disabled-text);
187
- }
188
-
189
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting.ant-select-disabled .ant-select-arrow{
151
+ .viewer-toolbar .ant-select.select-resolution.ant-select-disabled .ant-select-arrow{
190
152
  display:none;
191
153
  }
192
-
193
- .viewer-toolbar.viewer-toolbar .ant-select.select-render-setting .ant-select-selector{
194
- border-color:#aeacae;
195
- box-shadow:none;
196
- background-color:var(--color-toolbar-button-bg);
197
- }
198
-
199
- .viewer-toolbar .ant-select.select-render-setting:hover:not(:disabled) .ant-select-selector,
200
- .viewer-toolbar .ant-select.select-render-setting:hover:not(:disabled) .ant-select-arrow,
201
- .viewer-toolbar .ant-select.select-render-setting:hover:not(:disabled) .ant-select-selection-item,
202
- .viewer-toolbar .ant-select.select-render-setting:focus-visible:not(:disabled) .ant-select-selector,
203
- .viewer-toolbar .ant-select.select-render-setting:focus-visible:not(:disabled) .ant-select-arrow,
204
- .viewer-toolbar .ant-select.select-render-setting:focus-visible:not(:disabled) .ant-select-selection-item,
205
- .viewer-toolbar.viewer-toolbar.viewer-toolbar .ant-select-open .ant-select-selector,
206
- .viewer-toolbar.viewer-toolbar.viewer-toolbar .ant-select-open .ant-select-arrow,
207
- .viewer-toolbar.viewer-toolbar.viewer-toolbar .ant-select-open .ant-select-selection-item{
208
- color:var(--color-button-tertiary-hover-text);
209
- outline-color:var(--color-button-tertiary-hover-outline);
210
- }
211
-
212
- .viewer-toolbar-dropdown .ant-select-dropdown-menu-item-active{
213
- transition-property:background-color, color;
214
- }
215
-
216
- .viewer-toolbar-dropdown .ant-select-dropdown-menu-item-disabled,
217
- .viewer-toolbar-dropdown .ant-select-dropdown-menu-item-disabled:hover{
218
- color:#6e6e6e;
219
- }
220
-
221
- .viewer-toolbar-dropdown .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled){
222
- background-color:transparent;
223
- color:white;
224
- }
225
-
226
- .viewer-toolbar-dropdown .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled).ant-select-dropdown-menu-item-selected{
227
- background-color:#4b4b4b;
228
- }
229
-
230
- .viewer-toolbar-dropdown .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled){
231
- background-color:#f6f0ff;
232
- color:#4b4b4b;
233
- }
234
-
235
- @supports selector(:has(:focus-visible)){
236
- .viewer-toolbar .ant-select-selection:focus-visible,
237
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):has(:focus-visible),
238
- .viewer-toolbar .btn-borderless:focus-visible{
239
- background-color:#aa88ed !important;
240
- color:white !important;
241
- }
242
-
243
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):has(:focus-visible){
244
- outline:none;
245
- border-color:#aeacae;
246
- }
247
-
248
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):has(:focus-visible):not(:first-child){
249
- box-shadow:-1px 0px 0px 0px #aeacae;
250
- }
251
- }
252
-
253
- @supports not (selector(:has(:focus-visible))){
254
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):focus-within{
255
- outline:none;
256
- border-color:#aeacae;
257
- }
258
-
259
- .viewer-toolbar .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-disabled):focus-within:not(:first-child){
260
- box-shadow:-1px 0px 0px 0px #aeacae;
261
- }
262
- }
@@ -0,0 +1,148 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
3
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
4
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
+ import React, { useEffect } from "react";
6
+ import { activeAxisMap } from "../../shared/types";
7
+ import { DimensionSliderRow, IndexSliderRow, PlaySliderRow } from "./SliderRows";
8
+ var AXES = ["x", "y", "z"];
9
+ export var AxisClipSliders = function AxisClipSliders(props) {
10
+ var activeAxis = activeAxisMap[props.mode];
11
+ var pauseOnInput = function pauseOnInput(axis) {
12
+ // Pause on slider input unless user is scrubbing along the playing axis (playback is held while this is happening)
13
+ if (!props.playControls.playHolding || props.playingAxis !== axis) {
14
+ props.playControls.pause();
15
+ }
16
+ };
17
+ var updateRegion = function updateRegion(axis, minval, maxval) {
18
+ pauseOnInput(axis);
19
+ var changeViewerSetting = props.changeViewerSetting,
20
+ numSlices = props.numSlices;
21
+ // get a value from 0-1
22
+ var max = numSlices[axis];
23
+ var start = minval / max;
24
+ var end = maxval / max;
25
+ changeViewerSetting("region", _defineProperty({}, axis, [start, end]));
26
+ };
27
+ var updateSlice = function updateSlice(axis, slice) {
28
+ pauseOnInput(axis);
29
+ props.changeViewerSetting("slice", _defineProperty({}, axis, slice / props.numSlices[axis]));
30
+ };
31
+ var updateTime = function updateTime(time) {
32
+ pauseOnInput("t");
33
+ props.changeViewerSetting("time", time);
34
+ };
35
+
36
+ // Pause when view mode or volume size has changed
37
+ useEffect(function () {
38
+ return props.playControls.pause();
39
+ }, [props.mode, props.image, props.playControls]);
40
+ var handlePlayPause = function handlePlayPause(axis, willPlay) {
41
+ if (willPlay) {
42
+ props.playControls.play(axis);
43
+ } else {
44
+ props.playControls.pause();
45
+ }
46
+ };
47
+ var create2dAxisSlider = function create2dAxisSlider(axis) {
48
+ var numSlices = props.numSlices[axis];
49
+ var numSlicesLoaded = props.numSlicesLoaded[axis];
50
+ return /*#__PURE__*/React.createElement("div", {
51
+ key: axis + numSlices + numSlicesLoaded,
52
+ className: "slider-row slider-".concat(axis)
53
+ }, /*#__PURE__*/React.createElement(PlaySliderRow, {
54
+ label: axis.toUpperCase(),
55
+ val: Math.round(props.slices[axis] * numSlices),
56
+ max: numSlices,
57
+ onChange: function onChange(val) {
58
+ return updateSlice(axis, val);
59
+ },
60
+ onStart: function onStart() {
61
+ return props.playControls.startHold(axis);
62
+ },
63
+ onEnd: function onEnd() {
64
+ return props.playControls.endHold();
65
+ },
66
+ playing: props.playingAxis === axis,
67
+ onTogglePlayback: function onTogglePlayback(willPlay) {
68
+ return handlePlayPause(axis, willPlay);
69
+ },
70
+ updateWhileSliding: numSlices === numSlicesLoaded
71
+ }));
72
+ };
73
+ var create3dAxisSlider = function create3dAxisSlider(axis) {
74
+ var numSlices = props.numSlices[axis];
75
+ if (numSlices === 1) {
76
+ return null;
77
+ }
78
+ var region = props.region[axis];
79
+ return /*#__PURE__*/React.createElement("div", {
80
+ key: axis + numSlices + "3d",
81
+ className: "slider-row slider-".concat(axis)
82
+ }, /*#__PURE__*/React.createElement(DimensionSliderRow, {
83
+ label: axis.toUpperCase(),
84
+ val: [Math.round(region[0] * numSlices), Math.round(region[1] * numSlices)],
85
+ min: 0,
86
+ max: numSlices,
87
+ onSlide: function onSlide(values) {
88
+ return updateRegion(axis, values[0], values[1]);
89
+ },
90
+ onStart: function onStart() {
91
+ return props.playControls.startHold(axis);
92
+ },
93
+ onEnd: function onEnd() {
94
+ return props.playControls.endHold();
95
+ }
96
+ }));
97
+ };
98
+ return /*#__PURE__*/React.createElement("div", {
99
+ className: activeAxis ? "clip-sliders clip-sliders-2d" : "clip-sliders"
100
+ }, /*#__PURE__*/React.createElement("span", {
101
+ className: "slider-group"
102
+ }, /*#__PURE__*/React.createElement("span", {
103
+ className: "slider-group-title"
104
+ }, "ROI"), /*#__PURE__*/React.createElement("span", {
105
+ className: "slider-group-rows"
106
+ }, activeAxis ? create2dAxisSlider(activeAxis) : AXES.map(create3dAxisSlider))), props.numTimesteps > 1 && /*#__PURE__*/React.createElement("span", {
107
+ className: "slider-group"
108
+ }, /*#__PURE__*/React.createElement("span", {
109
+ className: "slider-group-title"
110
+ }, "Time"), /*#__PURE__*/React.createElement("span", {
111
+ className: "slider-group-rows"
112
+ }, /*#__PURE__*/React.createElement("div", {
113
+ className: "slider-row slider-t"
114
+ }, /*#__PURE__*/React.createElement(PlaySliderRow, {
115
+ label: "",
116
+ val: props.time,
117
+ max: props.numTimesteps,
118
+ playing: props.playingAxis === "t",
119
+ onTogglePlayback: function onTogglePlayback(willPlay) {
120
+ return handlePlayPause("t", willPlay);
121
+ },
122
+ onChange: function onChange(time) {
123
+ return updateTime(time);
124
+ },
125
+ onStart: function onStart() {
126
+ return props.playControls.startHold("t");
127
+ },
128
+ onEnd: function onEnd() {
129
+ return props.playControls.endHold();
130
+ }
131
+ })))), props.numScenes > 1 && /*#__PURE__*/React.createElement("span", {
132
+ className: "slider-group"
133
+ }, /*#__PURE__*/React.createElement("span", {
134
+ className: "slider-group-title"
135
+ }, "Scene"), /*#__PURE__*/React.createElement("span", {
136
+ className: "slider-group-rows"
137
+ }, /*#__PURE__*/React.createElement("div", {
138
+ className: "slider-row slider-scene"
139
+ }, /*#__PURE__*/React.createElement(IndexSliderRow, {
140
+ label: "",
141
+ val: props.scene,
142
+ max: props.numScenes,
143
+ onChange: function onChange(scene) {
144
+ props.changeViewerSetting("scene", scene);
145
+ props.changeViewerSetting("useExactScaleLevel", false);
146
+ }
147
+ })))));
148
+ };
@@ -0,0 +1,165 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
6
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
8
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
9
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
10
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
11
+ 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; } }
12
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
13
+ import { Button, Space } from "antd";
14
+ import React, { useCallback, useEffect, useRef, useState } from "react";
15
+ import { applyMatrix, defaultOrientedCamera, getRotationAngles, rotationMatrix, useCameraCallback } from "../../shared/utils/camera";
16
+ import { select, useViewerState } from "../../state/store";
17
+ import { DimensionSliderRow } from "./SliderRows";
18
+
19
+ /** Convert an angle from degrees to radians */
20
+ var toRadians = function toRadians(deg) {
21
+ return deg * (Math.PI / 180);
22
+ };
23
+ /** Convert an angle from radians to degrees */
24
+ var toDegrees = function toDegrees(rad) {
25
+ return rad * (180 / Math.PI);
26
+ };
27
+ export var RotationSliders = function RotationSliders(_ref) {
28
+ var view3d = _ref.view3d,
29
+ disable = _ref.disable;
30
+ var _useState = useState(function () {
31
+ return getRotationAngles(view3d.getCameraState());
32
+ }),
33
+ _useState2 = _slicedToArray(_useState, 2),
34
+ rotation = _useState2[0],
35
+ setRotation = _useState2[1];
36
+ var autorotate = useViewerState(select("autorotate"));
37
+ var changeViewerSetting = useViewerState(select("changeViewerSetting"));
38
+
39
+ // Set to `true` when user interacts with this component, `false` when they click on the canvas or start autorotate.
40
+ // While `hasControlRef.current === true`, this component's state propagates *down* to `view3d`
41
+ // While `hasControlRef.current === false`, `view3d`'s camera state is synced *up* to this component.
42
+ // TODO are there any other events besides the above that cause the volume to rotate? Ideally this would be an event
43
+ // that `View3d` would let us track directly.
44
+ var hasControlRef = useRef(false);
45
+ var handleRotate = useCallback(function (axis, deg) {
46
+ hasControlRef.current = true;
47
+ if (autorotate) {
48
+ changeViewerSetting("autorotate", false);
49
+ }
50
+ setRotation(function (current) {
51
+ return _objectSpread(_objectSpread({}, current), {}, _defineProperty({}, axis, toRadians(deg)));
52
+ });
53
+ }, [autorotate, changeViewerSetting]);
54
+ var handleJump = useCallback(function (x, y, z) {
55
+ hasControlRef.current = true;
56
+ setRotation({
57
+ x: x,
58
+ y: y,
59
+ z: z
60
+ });
61
+ }, []);
62
+ var jumpXMinus = useCallback(function () {
63
+ return handleJump(0, -Math.PI / 2, 0);
64
+ }, [handleJump]);
65
+ var jumpXPlus = useCallback(function () {
66
+ return handleJump(0, Math.PI / 2, 0);
67
+ }, [handleJump]);
68
+ var jumpYMinus = useCallback(function () {
69
+ return handleJump(Math.PI / 2, 0, -Math.PI / 2);
70
+ }, [handleJump]);
71
+ var jumpYPlus = useCallback(function () {
72
+ return handleJump(-Math.PI / 2, 0, -Math.PI / 2);
73
+ }, [handleJump]);
74
+ var jumpZMinus = useCallback(function () {
75
+ return handleJump(Math.PI, 0, -Math.PI);
76
+ }, [handleJump]);
77
+ var jumpZPlus = useCallback(function () {
78
+ return handleJump(0, 0, 0);
79
+ }, [handleJump]);
80
+
81
+ // Take away control when autorotate is enabled
82
+ useEffect(function () {
83
+ if (autorotate) {
84
+ hasControlRef.current = false;
85
+ }
86
+ }, [autorotate]);
87
+ var rotateCameraTo = useCameraCallback(function (state, rotation) {
88
+ var matrix = rotationMatrix(rotation.x, rotation.y, rotation.z);
89
+ return applyMatrix(defaultOrientedCamera(state), matrix);
90
+ }, view3d);
91
+
92
+ // Sync down rotation state while this component is "in control."
93
+ useEffect(function () {
94
+ if (hasControlRef.current) {
95
+ rotateCameraTo(rotation);
96
+ }
97
+ }, [rotateCameraTo, rotation]);
98
+
99
+ // Set up event listeners on mount.
100
+ useEffect(function () {
101
+ // TODO this is *extremely brittle*: setting this clears away any other listener for render events.
102
+ // At time of writing, `setOnRenderCallback` appears not to be used anywhere else in either this package or
103
+ // vole-core, but that could change at any time.
104
+ // Ideally `View3d` would have an `addEventListener`/`removeEventListener` model.
105
+ view3d.setOnRenderCallback(function () {
106
+ if (!hasControlRef.current) {
107
+ setRotation(getRotationAngles(view3d.getCameraState()));
108
+ }
109
+ });
110
+ var clickListener = function clickListener() {
111
+ return hasControlRef.current = false;
112
+ };
113
+ view3d.getDOMElement().addEventListener("mousedown", clickListener);
114
+ return function () {
115
+ return view3d.getDOMElement().removeEventListener("mousedown", clickListener);
116
+ };
117
+ }, [view3d]);
118
+ var createRotateSlider = function createRotateSlider(axis) {
119
+ return /*#__PURE__*/React.createElement("div", {
120
+ key: "".concat(axis, "-rotate"),
121
+ className: "slider-row slider-".concat(axis)
122
+ }, /*#__PURE__*/React.createElement(DimensionSliderRow, {
123
+ label: axis.toUpperCase(),
124
+ val: [toDegrees(rotation[axis])],
125
+ min: -180,
126
+ max: 180,
127
+ hideMax: true,
128
+ onSlide: function onSlide(_ref2) {
129
+ var _ref3 = _slicedToArray(_ref2, 1),
130
+ deg = _ref3[0];
131
+ return handleRotate(axis, deg);
132
+ },
133
+ unitSymbol: "\xB0"
134
+ }));
135
+ };
136
+ return /*#__PURE__*/React.createElement("div", {
137
+ className: "clip-sliders clip-sliders-2d"
138
+ }, /*#__PURE__*/React.createElement("span", {
139
+ className: "slider-group"
140
+ }, /*#__PURE__*/React.createElement("span", {
141
+ className: "slider-group-title"
142
+ }, "Rotate"), disable ? /*#__PURE__*/React.createElement("span", {
143
+ className: "axis-slider-container"
144
+ }, /*#__PURE__*/React.createElement("i", null, "Unavailable in 2d mode")) : /*#__PURE__*/React.createElement("span", {
145
+ className: "slider-group-rows"
146
+ }, createRotateSlider("x"), createRotateSlider("y"), createRotateSlider("z"))), !disable && /*#__PURE__*/React.createElement("span", {
147
+ className: "slider-group"
148
+ }, /*#__PURE__*/React.createElement("span", {
149
+ className: "slider-group-title group-title-extra"
150
+ }, "Jump to"), /*#__PURE__*/React.createElement("span", {
151
+ className: "slider-group-rows"
152
+ }, /*#__PURE__*/React.createElement(Space.Compact, null, /*#__PURE__*/React.createElement(Button, {
153
+ onClick: jumpXMinus
154
+ }, "-X"), /*#__PURE__*/React.createElement(Button, {
155
+ onClick: jumpXPlus
156
+ }, "+X"), /*#__PURE__*/React.createElement(Button, {
157
+ onClick: jumpYMinus
158
+ }, "-Y"), /*#__PURE__*/React.createElement(Button, {
159
+ onClick: jumpYPlus
160
+ }, "+Y"), /*#__PURE__*/React.createElement(Button, {
161
+ onClick: jumpZMinus
162
+ }, "-Z"), /*#__PURE__*/React.createElement(Button, {
163
+ onClick: jumpZPlus
164
+ }, "+Z")))));
165
+ };
@@ -0,0 +1,167 @@
1
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ 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; } }
4
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
5
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
6
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
7
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
8
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
9
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
10
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
11
+ import { CaretRightOutlined, PauseOutlined } from "@ant-design/icons";
12
+ import { Button, Tooltip } from "antd";
13
+ import React, { useCallback, useState } from "react";
14
+ import NumericInput from "../shared/NumericInput";
15
+ import SmarterSlider from "../shared/SmarterSlider";
16
+ import "./styles.css";
17
+ /** A single slider row, with a slider, one or two spinbox inputs, and a max value. */
18
+ export var DimensionSliderRow = function DimensionSliderRow(_ref) {
19
+ var label = _ref.label,
20
+ val = _ref.val,
21
+ _ref$valReadout = _ref.valReadout,
22
+ valReadout = _ref$valReadout === void 0 ? val : _ref$valReadout,
23
+ min = _ref.min,
24
+ max = _ref.max,
25
+ hideMax = _ref.hideMax,
26
+ unitSymbol = _ref.unitSymbol,
27
+ onSlide = _ref.onSlide,
28
+ _ref$onChange = _ref.onChange,
29
+ _onChange = _ref$onChange === void 0 ? onSlide : _ref$onChange,
30
+ onStart = _ref.onStart,
31
+ onEnd = _ref.onEnd;
32
+ return /*#__PURE__*/React.createElement("span", {
33
+ className: "axis-slider-container"
34
+ }, /*#__PURE__*/React.createElement("span", {
35
+ className: "slider-name"
36
+ }, label), max <= min ? /*#__PURE__*/React.createElement("i", null, "No values to adjust") : /*#__PURE__*/React.createElement("span", {
37
+ className: "axis-slider"
38
+ }, /*#__PURE__*/React.createElement(SmarterSlider, {
39
+ className: val.length <= 1 ? "slider-single-handle" : "",
40
+ connect: true,
41
+ range: {
42
+ min: min,
43
+ max: max
44
+ },
45
+ start: val,
46
+ step: 1,
47
+ margin: 1,
48
+ behaviour: "drag",
49
+ pips: {
50
+ mode: "positions",
51
+ values: [25, 50, 75],
52
+ density: 25,
53
+ format: {
54
+ // remove labels from pips
55
+ to: function to() {
56
+ return "";
57
+ }
58
+ }
59
+ }
60
+ // round slider output to nearest slice; assume any string inputs represent ints
61
+ ,
62
+ format: {
63
+ to: Math.round,
64
+ from: parseInt
65
+ },
66
+ onSlide: onSlide,
67
+ onChange: _onChange,
68
+ onStart: onStart,
69
+ onEnd: onEnd
70
+ })), max > min && /*#__PURE__*/React.createElement("span", {
71
+ className: "slider-values"
72
+ }, /*#__PURE__*/React.createElement(NumericInput, {
73
+ min: min,
74
+ max: max,
75
+ value: valReadout[0],
76
+ onChange: function onChange(value) {
77
+ return _onChange === null || _onChange === void 0 ? void 0 : _onChange([value].concat(_toConsumableArray(val.slice(1))));
78
+ },
79
+ unitSymbol: unitSymbol
80
+ }), val.length > 1 && /*#__PURE__*/React.createElement(React.Fragment, null, " , ", /*#__PURE__*/React.createElement(NumericInput, {
81
+ min: min,
82
+ max: max,
83
+ value: valReadout[1],
84
+ onChange: function onChange(value) {
85
+ return _onChange === null || _onChange === void 0 ? void 0 : _onChange([val[0], value].concat(_toConsumableArray(val.slice(2))));
86
+ },
87
+ unitSymbol: unitSymbol
88
+ })), !hideMax && /*#__PURE__*/React.createElement(React.Fragment, null, " / ", max)));
89
+ };
90
+
91
+ /** Extremely thin wrapper around `SliderRow` for adjusting 0-indexed values that the user should see as 1-indexed. */
92
+ export var IndexSliderRow = function IndexSliderRow(props) {
93
+ return /*#__PURE__*/React.createElement(DimensionSliderRow, {
94
+ label: props.label,
95
+ val: [props.val + 1],
96
+ valReadout: props.valReadout === undefined ? undefined : [props.valReadout + 1],
97
+ min: 1,
98
+ max: props.max,
99
+ onSlide: function onSlide(_ref2) {
100
+ var _props$onSlide;
101
+ var _ref3 = _slicedToArray(_ref2, 1),
102
+ value = _ref3[0];
103
+ return (_props$onSlide = props.onSlide) === null || _props$onSlide === void 0 ? void 0 : _props$onSlide.call(props, value - 1);
104
+ },
105
+ onChange: function onChange(_ref4) {
106
+ var _props$onChange;
107
+ var _ref5 = _slicedToArray(_ref4, 1),
108
+ value = _ref5[0];
109
+ return (_props$onChange = props.onChange) === null || _props$onChange === void 0 ? void 0 : _props$onChange.call(props, value - 1);
110
+ },
111
+ onStart: props.onStart,
112
+ onEnd: props.onEnd
113
+ });
114
+ };
115
+
116
+ /** Wrapper around `SliderRow` that adds a play button and accounts for the case where not all of an axis is loaded. */
117
+ export var PlaySliderRow = function PlaySliderRow(props) {
118
+ var onChange = props.onChange,
119
+ onStart = props.onStart,
120
+ onEnd = props.onEnd;
121
+ // In partially-loaded axes, stores the displayed value of the slider while the user is sliding it
122
+ var _useState = useState(props.val),
123
+ _useState2 = _slicedToArray(_useState, 2),
124
+ valReadout = _useState2[0],
125
+ setValReadout = _useState2[1];
126
+ // Tracks when the user is sliding the slider and `valReadout` may have to sub in for props
127
+ var _useState3 = useState(false),
128
+ _useState4 = _slicedToArray(_useState3, 2),
129
+ sliderHeld = _useState4[0],
130
+ setSliderHeld = _useState4[1];
131
+ var wrappedOnChange = useCallback(function (val) {
132
+ return onChange === null || onChange === void 0 ? void 0 : onChange(val);
133
+ }, [onChange]);
134
+ var wrappedSetValReadout = useCallback(function (val) {
135
+ return setValReadout(val);
136
+ }, []);
137
+ var wrappedOnStart = useCallback(function () {
138
+ setValReadout(props.val);
139
+ setSliderHeld(true);
140
+ onStart === null || onStart === void 0 || onStart();
141
+ }, [onStart, props.val]);
142
+ var wrappedOnEnd = useCallback(function () {
143
+ setSliderHeld(false);
144
+ onEnd === null || onEnd === void 0 || onEnd();
145
+ }, [onEnd]);
146
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(IndexSliderRow, {
147
+ label: props.label,
148
+ val: props.val,
149
+ valReadout: props.updateWhileSliding || !sliderHeld ? undefined : valReadout,
150
+ max: props.max,
151
+ onSlide: props.updateWhileSliding ? wrappedOnChange : wrappedSetValReadout,
152
+ onChange: props.updateWhileSliding ? undefined : wrappedOnChange,
153
+ onStart: wrappedOnStart,
154
+ onEnd: wrappedOnEnd
155
+ }), props.max > 1 && /*#__PURE__*/React.createElement(Tooltip, {
156
+ placement: "top",
157
+ title: "Play through sequence",
158
+ trigger: ["hover", "focus"]
159
+ }, /*#__PURE__*/React.createElement(Button, {
160
+ className: "slider-play-button",
161
+ onClick: function onClick() {
162
+ return props.onTogglePlayback(!props.playing);
163
+ },
164
+ icon: props.playing ? /*#__PURE__*/React.createElement(PauseOutlined, null) : /*#__PURE__*/React.createElement(CaretRightOutlined, null),
165
+ "aria-label": (props.playing ? "Pause " : "Play ") + props.label
166
+ })));
167
+ };