@aics/vole-app 3.3.1 → 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 (38) hide show
  1. package/es/aics-image-viewer/components/App/index.js +1 -0
  2. package/es/aics-image-viewer/components/BottomPanel/index.js +48 -19
  3. package/es/aics-image-viewer/components/BottomPanel/styles.css +16 -7
  4. package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +39 -19
  5. package/es/aics-image-viewer/components/ControlPanel/index.js +2 -0
  6. package/es/aics-image-viewer/components/dimension_sliders/AxisClipSliders.js +148 -0
  7. package/es/aics-image-viewer/components/dimension_sliders/RotationSliders.js +165 -0
  8. package/es/aics-image-viewer/components/dimension_sliders/SliderRows.js +167 -0
  9. package/es/aics-image-viewer/components/{AxisClipSliders → dimension_sliders}/styles.css +7 -1
  10. package/es/aics-image-viewer/components/shared/NumericInput/index.js +4 -2
  11. package/es/aics-image-viewer/components/shared/SliderRow/index.js +2 -0
  12. package/es/aics-image-viewer/components/shared/SliderRow/styles.css +2 -1
  13. package/es/aics-image-viewer/shared/constants.js +1 -1
  14. package/es/aics-image-viewer/shared/utils/camera.js +122 -0
  15. package/es/aics-image-viewer/shared/utils/test/camera.test.js +127 -0
  16. package/es/aics-image-viewer/shared/utils/test/urlParsing.test.js +23 -702
  17. package/es/aics-image-viewer/shared/utils/urlParsing.js +14 -828
  18. package/es/aics-image-viewer/state/deserialize.js +437 -0
  19. package/es/aics-image-viewer/state/serialize.js +145 -0
  20. package/es/aics-image-viewer/state/test/deserialize.test.js +432 -0
  21. package/es/aics-image-viewer/state/test/serialize.test.js +97 -0
  22. package/es/aics-image-viewer/state/test/test_data.js +168 -0
  23. package/es/aics-image-viewer/state/types.js +265 -1
  24. package/package.json +2 -1
  25. package/type-declarations/aics-image-viewer/components/App/types.d.ts +1 -1
  26. package/type-declarations/aics-image-viewer/components/BottomPanel/index.d.ts +6 -3
  27. package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +1 -0
  28. package/type-declarations/aics-image-viewer/components/{AxisClipSliders/index.d.ts → dimension_sliders/AxisClipSliders.d.ts} +2 -3
  29. package/type-declarations/aics-image-viewer/components/dimension_sliders/RotationSliders.d.ts +6 -0
  30. package/type-declarations/aics-image-viewer/components/dimension_sliders/SliderRows.d.ts +31 -0
  31. package/type-declarations/aics-image-viewer/components/shared/NumericInput/index.d.ts +1 -0
  32. package/type-declarations/aics-image-viewer/components/shared/SliderRow/index.d.ts +3 -1
  33. package/type-declarations/aics-image-viewer/shared/utils/camera.d.ts +19 -0
  34. package/type-declarations/aics-image-viewer/shared/utils/urlParsing.d.ts +1 -307
  35. package/type-declarations/aics-image-viewer/state/deserialize.d.ts +70 -0
  36. package/type-declarations/aics-image-viewer/state/serialize.d.ts +20 -0
  37. package/type-declarations/aics-image-viewer/state/types.d.ts +216 -0
  38. package/es/aics-image-viewer/components/AxisClipSliders/index.js +0 -295
@@ -41,6 +41,7 @@ var defaultVisibleControls = {
41
41
  alphaMaskSlider: true,
42
42
  autoRotateButton: true,
43
43
  axisClipSliders: true,
44
+ rotationSliders: true,
44
45
  brightnessSlider: true,
45
46
  backgroundColorPicker: true,
46
47
  boundingBoxColorPicker: true,
@@ -5,37 +5,66 @@ 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, { useCallback, useState } from "react";
8
+ import React, { useCallback, useEffect, useState } from "react";
9
9
  import ViewerIcon from "../shared/ViewerIcon";
10
10
  import "./styles.css";
11
11
  var BottomPanel = function BottomPanel(_ref) {
12
- var children = _ref.children,
12
+ var _contents$page;
13
+ var contents = _ref.contents,
13
14
  openProp = _ref.open,
14
- title = _ref.title,
15
+ pageProp = _ref.pageIndex,
15
16
  height = _ref.height,
16
- onOpenChange = _ref.onOpenChange;
17
+ onPageChange = _ref.onPageChange;
17
18
  var _useState = useState(true),
18
19
  _useState2 = _slicedToArray(_useState, 2),
19
20
  openState = _useState2[0],
20
21
  setOpenState = _useState2[1];
22
+ var _useState3 = useState(0),
23
+ _useState4 = _slicedToArray(_useState3, 2),
24
+ pageState = _useState4[0],
25
+ setPageState = _useState4[1];
21
26
  var open = openProp !== null && openProp !== void 0 ? openProp : openState;
22
- var toggleDrawer = useCallback(function () {
27
+ var page = pageProp !== null && pageProp !== void 0 ? pageProp : pageState;
28
+ var setPage = useCallback(function (index) {
29
+ var nextOpen = !open || index !== page;
23
30
  if (openProp === undefined) {
24
- setOpenState(!open);
31
+ setOpenState(nextOpen);
25
32
  }
26
- onOpenChange === null || onOpenChange === void 0 || onOpenChange(!open);
27
- }, [open, openProp, onOpenChange]);
28
- var optionsButton = /*#__PURE__*/React.createElement(Button, {
29
- className: "options-button",
30
- size: "small",
31
- onClick: toggleDrawer
32
- }, title || "Options", /*#__PURE__*/React.createElement(ViewerIcon, {
33
- type: "closePanel",
34
- className: "button-arrow",
35
- style: {
36
- fontSize: "15px"
33
+ if (pageProp === undefined) {
34
+ setPageState(index);
37
35
  }
38
- }));
36
+ onPageChange === null || onPageChange === void 0 || onPageChange(nextOpen ? index : null);
37
+ }, [open, openProp, page, pageProp, onPageChange]);
38
+
39
+ // If length of `contents` decreases, ensure we're still on a valid page
40
+ useEffect(function () {
41
+ if (page >= contents.length && contents.length > 0) {
42
+ var nextPage = contents.length - 1;
43
+ if (pageProp === undefined) {
44
+ setPageState(nextPage);
45
+ }
46
+ onPageChange === null || onPageChange === void 0 || onPageChange(open ? nextPage : null);
47
+ }
48
+ }, [contents.length, onPageChange, open, page, pageProp]);
49
+ var optionsButton = /*#__PURE__*/React.createElement("div", {
50
+ className: "options-button-container"
51
+ }, contents.map(function (_ref2, index) {
52
+ var title = _ref2.title;
53
+ return /*#__PURE__*/React.createElement(Button, {
54
+ key: index,
55
+ className: open && page === index ? "options-button button-open" : "options-button",
56
+ size: "small",
57
+ onClick: function onClick() {
58
+ return setPage(index);
59
+ }
60
+ }, title, /*#__PURE__*/React.createElement(ViewerIcon, {
61
+ type: "closePanel",
62
+ className: "button-arrow",
63
+ style: {
64
+ fontSize: "15px"
65
+ }
66
+ }));
67
+ }).reverse());
39
68
  return /*#__PURE__*/React.createElement("div", {
40
69
  className: "bottom-panel"
41
70
  }, /*#__PURE__*/React.createElement(Drawer, {
@@ -49,6 +78,6 @@ var BottomPanel = function BottomPanel(_ref) {
49
78
  height: height !== null && height !== void 0 ? height : 190
50
79
  }, /*#__PURE__*/React.createElement("div", {
51
80
  className: "drawer-body-wrapper"
52
- }, children)));
81
+ }, open !== null && ((_contents$page = contents[page]) === null || _contents$page === void 0 ? void 0 : _contents$page.children))));
53
82
  };
54
83
  export default BottomPanel;
@@ -46,18 +46,27 @@
46
46
  color:white;
47
47
  }
48
48
 
49
+ .bottom-panel .options-button-container{
50
+ position:absolute;
51
+ right:0;
52
+ }
53
+
49
54
  .bottom-panel .options-button{
55
+ bottom:0;
56
+ transition:bottom 0.1s linear;
50
57
  border:none;
51
58
  box-shadow:none;
52
59
  margin-right:0.8em;
53
60
  margin-bottom:0.2em;
54
- position:absolute;
55
- right:0;
56
61
  }
57
62
 
58
63
  .bottom-panel .button-arrow{
59
64
  transform:rotate(270deg);
60
- transition:transform 0.2s linear !important;
65
+ transition:transform 0.1s linear !important;
66
+ }
67
+
68
+ .bottom-panel .options-button.button-open .button-arrow{
69
+ transform:rotate(90deg);
61
70
  }
62
71
 
63
72
  .bottom-panel .drawer-body-wrapper{
@@ -65,6 +74,10 @@
65
74
  width:100%;
66
75
  }
67
76
 
77
+ .bottom-panel .ant-drawer.ant-drawer-open .options-button:not(.button-open){
78
+ bottom:0.8em;
79
+ }
80
+
68
81
  .bottom-panel .ant-drawer.ant-drawer-open .ant-drawer-content-wrapper{
69
82
  transform:none;
70
83
  box-shadow:none;
@@ -79,7 +92,3 @@
79
92
  .bottom-panel .ant-drawer.ant-drawer-open .ant-drawer-title .ant-btn.ant-btn-default{
80
93
  background-color:var(--color-controlpanel-drawer-bg);
81
94
  }
82
-
83
- .bottom-panel .ant-drawer.ant-drawer-open .button-arrow{
84
- transform:rotate(90deg);
85
- }
@@ -9,8 +9,9 @@ import React from "react";
9
9
  import { CLIPPING_PANEL_HEIGHT_DEFAULT, CLIPPING_PANEL_HEIGHT_TALL } from "../../shared/constants";
10
10
  import { ViewMode } from "../../shared/enums";
11
11
  import { select, useViewerState } from "../../state/store";
12
- import AxisClipSliders from "../AxisClipSliders";
13
12
  import BottomPanel from "../BottomPanel";
13
+ import { AxisClipSliders } from "../dimension_sliders/AxisClipSliders";
14
+ import { RotationSliders } from "../dimension_sliders/RotationSliders";
14
15
  import "./styles.css";
15
16
  var ViewerWrapper = function ViewerWrapper(props) {
16
17
  var view3dviewerRef = /*#__PURE__*/React.createRef();
@@ -47,6 +48,36 @@ var ViewerWrapper = function ViewerWrapper(props) {
47
48
  var time = useViewerState(select("time"));
48
49
  var scene = useViewerState(select("scene"));
49
50
  var clippingPanelTall = numTimesteps > 1 && numScenes > 1 && viewMode === ViewMode.threeD;
51
+ var bottomPanelContents = [];
52
+ if (visibleControls.axisClipSliders && !!props.image) {
53
+ bottomPanelContents.push({
54
+ title: "Clipping",
55
+ children: /*#__PURE__*/React.createElement(AxisClipSliders, {
56
+ mode: viewMode,
57
+ image: props.image,
58
+ changeViewerSetting: changeViewerSetting,
59
+ numSlices: props.numSlices,
60
+ numSlicesLoaded: props.numSlicesLoaded,
61
+ numScenes: numScenes,
62
+ region: region,
63
+ slices: slice,
64
+ numTimesteps: numTimesteps,
65
+ time: time,
66
+ scene: scene,
67
+ playControls: props.playControls,
68
+ playingAxis: props.playingAxis
69
+ })
70
+ });
71
+ }
72
+ if (visibleControls.rotationSliders) {
73
+ bottomPanelContents.push({
74
+ title: "Rotation",
75
+ children: /*#__PURE__*/React.createElement(RotationSliders, {
76
+ view3d: props.view3d,
77
+ disable: viewMode !== ViewMode.threeD
78
+ })
79
+ });
80
+ }
50
81
  return /*#__PURE__*/React.createElement("div", {
51
82
  className: "cell-canvas",
52
83
  style: _objectSpread(_objectSpread({}, STYLES.viewer), {}, {
@@ -56,25 +87,14 @@ var ViewerWrapper = function ViewerWrapper(props) {
56
87
  ref: view3dviewerRef,
57
88
  style: STYLES.view3d
58
89
  }), /*#__PURE__*/React.createElement(BottomPanel, {
59
- title: "Clipping",
60
90
  open: props.clippingPanelOpen,
61
- onOpenChange: props.onClippingPanelOpenChange,
62
- height: clippingPanelTall ? CLIPPING_PANEL_HEIGHT_TALL : CLIPPING_PANEL_HEIGHT_DEFAULT
63
- }, visibleControls.axisClipSliders && !!props.image && /*#__PURE__*/React.createElement(AxisClipSliders, {
64
- mode: viewMode,
65
- image: props.image,
66
- changeViewerSetting: changeViewerSetting,
67
- numSlices: props.numSlices,
68
- numSlicesLoaded: props.numSlicesLoaded,
69
- numScenes: numScenes,
70
- region: region,
71
- slices: slice,
72
- numTimesteps: numTimesteps,
73
- time: time,
74
- scene: scene,
75
- playControls: props.playControls,
76
- playingAxis: props.playingAxis
77
- })), renderOverlay());
91
+ onPageChange: function onPageChange(open) {
92
+ var _props$onClippingPane;
93
+ return (_props$onClippingPane = props.onClippingPanelOpenChange) === null || _props$onClippingPane === void 0 ? void 0 : _props$onClippingPane.call(props, open !== null);
94
+ },
95
+ height: clippingPanelTall ? CLIPPING_PANEL_HEIGHT_TALL : CLIPPING_PANEL_HEIGHT_DEFAULT,
96
+ contents: bottomPanelContents
97
+ }), renderOverlay());
78
98
  };
79
99
  export default ViewerWrapper;
80
100
  var STYLES = {
@@ -110,6 +110,8 @@ function ControlPanel(props) {
110
110
  icon: typeof icon === "string" ? icon : undefined
111
111
  }, _typeof(icon) === "object" && icon));
112
112
  };
113
+
114
+ // TODO this can just be a component...?
113
115
  var renderAdvancedSettings = function renderAdvancedSettings() {
114
116
  var items = [{
115
117
  key: 0,
@@ -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
+ };