@aics/vole-app 3.1.2 → 3.2.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.
@@ -13,8 +13,9 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
13
13
  import { Lut } from "@aics/vole-core";
14
14
  import { useEffect } from "react";
15
15
  import { useShallow } from "zustand/shallow";
16
+ import { SINGLE_CHANNEL_MODE_COLOR } from "../../shared/constants";
16
17
  import { binIndexedControlPointsToLut, rampToControlPoints } from "../../shared/utils/controlPointsToLut";
17
- import { useViewerState } from "../../state/store";
18
+ import { select, useViewerState } from "../../state/store";
18
19
  /**
19
20
  * A component that doesn't render anything, but reacts to the provided `ChannelState`
20
21
  * and keeps it in sync with the viewer.
@@ -28,6 +29,8 @@ var ChannelUpdater = function ChannelUpdater(_ref) {
28
29
  return state.channelSettings[index];
29
30
  });
30
31
  var channelState = useViewerState(channelStateSelector);
32
+ var singleChannelMode = useViewerState(select("singleChannelMode"));
33
+ var singleChannelIndex = useViewerState(select("singleChannelIndex"));
31
34
  var volumeEnabled = channelState.volumeEnabled,
32
35
  isosurfaceEnabled = channelState.isosurfaceEnabled,
33
36
  isovalue = channelState.isovalue,
@@ -50,17 +53,23 @@ var ChannelUpdater = function ChannelUpdater(_ref) {
50
53
  // enable/disable channel can't be dependent on channel load state because it may trigger the channel to load
51
54
  useEffect(function () {
52
55
  if (image) {
53
- view3d.setVolumeChannelEnabled(image, index, volumeEnabled);
56
+ var enabled = volumeEnabled;
57
+ if (singleChannelMode) {
58
+ // if this is the focused channel in single-channel mode, enable volume unless *only* isosurface is enabled
59
+ enabled = index === singleChannelIndex && !(!volumeEnabled && isosurfaceEnabled);
60
+ }
61
+ view3d.setVolumeChannelEnabled(image, index, enabled);
54
62
  view3d.updateLuts(image);
55
63
  }
56
- }, [image, volumeEnabled, index, view3d]);
64
+ }, [image, volumeEnabled, index, view3d, singleChannelMode, singleChannelIndex, isosurfaceEnabled]);
57
65
  useEffect(function () {
58
66
  if (image) {
67
+ var enabled = isosurfaceEnabled && (!singleChannelMode || singleChannelIndex === index);
59
68
  view3d.setVolumeChannelOptions(image, index, {
60
- isosurfaceEnabled: isosurfaceEnabled
69
+ isosurfaceEnabled: enabled
61
70
  });
62
71
  }
63
- }, [image, isosurfaceEnabled, index, view3d]);
72
+ }, [image, isosurfaceEnabled, index, view3d, singleChannelMode, singleChannelIndex]);
64
73
  useImageEffect(function (currentImage) {
65
74
  return view3d.setVolumeChannelOptions(currentImage, index, {
66
75
  isovalue: isovalue
@@ -72,11 +81,12 @@ var ChannelUpdater = function ChannelUpdater(_ref) {
72
81
  });
73
82
  }, [opacity, index, view3d]);
74
83
  useImageEffect(function (currentImage) {
84
+ var finalColor = singleChannelMode ? SINGLE_CHANNEL_MODE_COLOR : color;
75
85
  view3d.setVolumeChannelOptions(currentImage, index, {
76
- color: color
86
+ color: finalColor
77
87
  });
78
88
  view3d.updateLuts(currentImage);
79
- }, [color, index, view3d]);
89
+ }, [color, index, view3d, singleChannelMode]);
80
90
  var controlPoints = channelState.controlPoints,
81
91
  ramp = channelState.ramp,
82
92
  useControlPoints = channelState.useControlPoints;
@@ -1,13 +1,17 @@
1
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
+ 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 _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
8
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
2
9
  function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
3
10
  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."); }
4
11
  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; } }
5
12
  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; }
6
13
  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; } }
7
14
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
8
- 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; }
9
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
10
- 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); }
11
15
  import { Collapse, List } from "antd";
12
16
  import React from "react";
13
17
  import { useShallow } from "zustand/shallow";
@@ -37,6 +41,66 @@ var ChannelsWidget = function ChannelsWidget(props) {
37
41
  var volumeEnabled = useViewerState(selectVolumeEnabled);
38
42
  var isosurfaceEnabled = useViewerState(selectIsosurfaceEnabled);
39
43
  var channelNames = useViewerState(selectNames);
44
+ var singleChannelMode = useViewerState(select("singleChannelMode"));
45
+ var singleChannelIndex = useViewerState(select("singleChannelIndex"));
46
+ var changeViewerSetting = useViewerState(select("changeViewerSetting"));
47
+ var _React$useState = React.useState([Object.keys(channelGroupedByType)[0]]),
48
+ _React$useState2 = _slicedToArray(_React$useState, 2),
49
+ openGroups = _React$useState2[0],
50
+ setOpenGroups = _React$useState2[1];
51
+ var collapseClass = singleChannelMode ? "single-channel-mode" : "";
52
+
53
+ // Switch between channels in single-channel mode with arrow keys
54
+ React.useEffect(function () {
55
+ if (singleChannelMode) {
56
+ var handleKeyPress = function handleKeyPress(_ref2) {
57
+ var key = _ref2.key;
58
+ // We only care about arrow keys!
59
+ if (!(key === "ArrowUp" || key === "ArrowDown" || key === "ArrowLeft" || key === "ArrowRight")) {
60
+ return;
61
+ }
62
+
63
+ // Only navigate with arrow keys if no unrelated input element has focus
64
+ // (special case for checkboxes: they don't use arrow keys, and the user just clicked one to enter this mode)
65
+ var _document = document,
66
+ activeEl = _document.activeElement,
67
+ body = _document.body;
68
+ if (activeEl !== body && !(activeEl instanceof HTMLInputElement && activeEl.type === "checkbox")) {
69
+ return;
70
+ }
71
+
72
+ // Channels appear in the order determined by grouping props, not index order
73
+ var channelGroups = Object.values(channelGroupedByType);
74
+ var channelOrder = channelGroups.flat();
75
+ var currentIndex = channelOrder.indexOf(singleChannelIndex);
76
+ var delta = key === "ArrowUp" || key === "ArrowLeft" ? -1 : 1;
77
+ var nextIndex = (currentIndex + channelOrder.length + delta) % channelOrder.length;
78
+ changeViewerSetting("singleChannelIndex", channelOrder[nextIndex]);
79
+
80
+ // Which group is the new channel in?
81
+ var nextGroupIndex = 0;
82
+ var accumulator = 0;
83
+ while (accumulator + channelGroups[nextGroupIndex].length <= nextIndex) {
84
+ accumulator += channelGroups[nextGroupIndex].length;
85
+ nextGroupIndex += 1;
86
+ }
87
+
88
+ // If the new channel is in a closed group, open it
89
+ var nextGroupName = Object.keys(channelGroupedByType)[nextGroupIndex];
90
+ setOpenGroups(function (currentOpenGroups) {
91
+ if (!currentOpenGroups.includes(nextGroupName)) {
92
+ return [].concat(_toConsumableArray(currentOpenGroups), [nextGroupName]);
93
+ }
94
+ return currentOpenGroups;
95
+ });
96
+ };
97
+ window.addEventListener("keydown", handleKeyPress);
98
+ return function () {
99
+ return window.removeEventListener("keydown", handleKeyPress);
100
+ };
101
+ }
102
+ return undefined;
103
+ }, [singleChannelMode, singleChannelIndex, channelGroupedByType, changeViewerSetting]);
40
104
  var createCheckboxHandler = function createCheckboxHandler(key) {
41
105
  return function (value, channelArray) {
42
106
  changeChannelSetting(channelArray, _defineProperty({}, key, value));
@@ -45,6 +109,9 @@ var ChannelsWidget = function ChannelsWidget(props) {
45
109
  var showVolumes = createCheckboxHandler("volumeEnabled");
46
110
  var showSurfaces = createCheckboxHandler("isosurfaceEnabled");
47
111
  var renderVisibilityControls = function renderVisibilityControls(channelArray) {
112
+ if (singleChannelMode) {
113
+ return null;
114
+ }
48
115
  var volChecked = [];
49
116
  var isoChecked = [];
50
117
  channelArray.forEach(function (channelIndex) {
@@ -81,16 +148,15 @@ var ChannelsWidget = function ChannelsWidget(props) {
81
148
  saveIsosurface: props.saveIsosurface
82
149
  }) : null;
83
150
  };
84
- var firstKey = Object.keys(channelGroupedByType)[0];
85
- var rows = channelDataChannels && Object.entries(channelGroupedByType).filter(function (_ref2) {
86
- var _ref3 = _slicedToArray(_ref2, 2),
87
- key = _ref3[0],
88
- channelArray = _ref3[1];
151
+ var rows = channelDataChannels && Object.entries(channelGroupedByType).filter(function (_ref3) {
152
+ var _ref4 = _slicedToArray(_ref3, 2),
153
+ key = _ref4[0],
154
+ channelArray = _ref4[1];
89
155
  return channelArray.length > 0 && (!filterFunc || filterFunc(key));
90
- }).map(function (_ref4) {
91
- var _ref5 = _slicedToArray(_ref4, 2),
92
- key = _ref5[0],
93
- channelArray = _ref5[1];
156
+ }).map(function (_ref5) {
157
+ var _ref6 = _slicedToArray(_ref5, 2),
158
+ key = _ref6[0],
159
+ channelArray = _ref6[1];
94
160
  var children = /*#__PURE__*/React.createElement(List, {
95
161
  itemLayout: "horizontal",
96
162
  dataSource: channelArray,
@@ -104,9 +170,11 @@ var ChannelsWidget = function ChannelsWidget(props) {
104
170
  };
105
171
  });
106
172
  return /*#__PURE__*/React.createElement(Collapse, {
173
+ className: collapseClass,
107
174
  bordered: false,
108
- defaultActiveKey: firstKey,
109
175
  items: rows,
176
+ activeKey: openGroups,
177
+ onChange: setOpenGroups,
110
178
  collapsible: "icon"
111
179
  });
112
180
  };
@@ -15,15 +15,25 @@ import "./styles.css";
15
15
  var ChannelsWidgetRow = function ChannelsWidgetRow(props) {
16
16
  var index = props.index,
17
17
  saveIsosurface = props.saveIsosurface;
18
- var _useState = useState(false),
19
- _useState2 = _slicedToArray(_useState, 2),
20
- controlsOpen = _useState2[0],
21
- setControlsOpen = _useState2[1];
22
18
  var changeChannelSetting = useViewerState(select("changeChannelSetting"));
19
+ var changeViewerSetting = useViewerState(select("changeViewerSetting"));
23
20
  var channelState = useViewerState(function (_ref) {
24
21
  var channelSettings = _ref.channelSettings;
25
22
  return channelSettings[props.index];
26
23
  });
24
+ var singleChannelMode = useViewerState(select("singleChannelMode"));
25
+ var singleChannelIndex = useViewerState(select("singleChannelIndex"));
26
+ var _useState = useState(false),
27
+ _useState2 = _slicedToArray(_useState, 2),
28
+ _controlsOpen = _useState2[0],
29
+ setControlsOpen = _useState2[1];
30
+ // Don't show controls in single-channel mode
31
+ var controlsOpen = _controlsOpen && !singleChannelMode;
32
+ var onClickChannel = useCallback(function () {
33
+ if (singleChannelMode) {
34
+ changeViewerSetting("singleChannelIndex", index);
35
+ }
36
+ }, [singleChannelMode, changeViewerSetting, index]);
27
37
  var changeSettingForThisChannel = useCallback(function (value) {
28
38
  return changeChannelSetting(index, value);
29
39
  }, [changeChannelSetting, index]);
@@ -58,7 +68,12 @@ var ChannelsWidgetRow = function ChannelsWidgetRow(props) {
58
68
  width: 18
59
69
  });
60
70
  };
61
- var visibilityControls = /*#__PURE__*/React.createElement("div", {
71
+ var thisChannelOnly = singleChannelMode && singleChannelIndex === index;
72
+ var visibilityControls = singleChannelMode ? /*#__PURE__*/React.createElement("div", {
73
+ className: "channel-visibility-controls".concat(thisChannelOnly ? " single-channel" : "")
74
+ }, /*#__PURE__*/React.createElement("span", {
75
+ className: "single-channel-text"
76
+ }, thisChannelOnly ? "Showing this volume only" : "")) : /*#__PURE__*/React.createElement("div", {
62
77
  className: "channel-visibility-controls"
63
78
  }, /*#__PURE__*/React.createElement(Checkbox, {
64
79
  checked: channelState.volumeEnabled,
@@ -79,7 +94,16 @@ var ChannelsWidgetRow = function ChannelsWidgetRow(props) {
79
94
  title: "Open channel settings",
80
95
  type: "text"
81
96
  }));
82
- var createTFEditor = function createTFEditor() {
97
+ var renderControls = function renderControls() {
98
+ var showEditor = singleChannelMode ? singleChannelIndex === index : channelState.volumeEnabled || channelState.isosurfaceEnabled;
99
+ if (!showEditor) {
100
+ return /*#__PURE__*/React.createElement("h4", {
101
+ style: {
102
+ fontStyle: "italic"
103
+ }
104
+ }, "Not currently visible");
105
+ }
106
+
83
107
  // TODO this is most of `channelState`... should `TfEditor` just get `channelState`?
84
108
  var controlPoints = channelState.controlPoints,
85
109
  colorizeEnabled = channelState.colorizeEnabled,
@@ -105,25 +129,16 @@ var ChannelsWidgetRow = function ChannelsWidgetRow(props) {
105
129
  keepIntensityRange: channelState.keepIntensityRange,
106
130
  isovalue: isovalue,
107
131
  opacity: channelState.opacity,
108
- volumeEnabled: channelState.volumeEnabled,
109
- isosurfaceEnabled: channelState.isosurfaceEnabled,
132
+ volumeEnabled: singleChannelMode ? singleChannelIndex === index : channelState.volumeEnabled,
133
+ isosurfaceEnabled: channelState.isosurfaceEnabled && !singleChannelMode,
110
134
  saveIsosurface: saveThisIsosurface
111
135
  });
112
136
  };
113
- var renderControls = function renderControls() {
114
- if (!channelState.volumeEnabled && !channelState.isosurfaceEnabled) {
115
- return /*#__PURE__*/React.createElement("h4", {
116
- style: {
117
- fontStyle: "italic"
118
- }
119
- }, "Not currently visible");
120
- }
121
- return /*#__PURE__*/React.createElement(React.Fragment, null, (channelState.volumeEnabled || channelState.isosurfaceEnabled) && createTFEditor());
122
- };
123
- var rowClass = controlsOpen ? "channel-row" : "channel-row controls-closed";
137
+ var rowClass = "channel-row".concat(controlsOpen ? "" : " controls-closed").concat(thisChannelOnly ? " single-channel" : "");
124
138
  return /*#__PURE__*/React.createElement(List.Item, {
125
139
  key: index,
126
- className: rowClass
140
+ className: rowClass,
141
+ onClick: onClickChannel
127
142
  }, /*#__PURE__*/React.createElement(List.Item.Meta, {
128
143
  title: props.name,
129
144
  avatar: createColorPicker()
@@ -1,25 +1,23 @@
1
- .channel-rows-list .ant-list-item.channel-row{
2
- padding:22px 0;
3
- border-bottom:1px solid var(--color-controlpanel-border);
4
- flex-flow:row wrap;
5
- }
6
-
7
- .channel-rows-list .ant-list-item.channel-row .ant-list-item-meta-title,
8
- .channel-rows-list .ant-list-item.channel-row .ant-checkbox-wrapper{
1
+ .control-panel-content .ant-list-item.channel-row .ant-list-item-meta-title,
2
+ .control-panel-content .ant-list-item.channel-row .ant-checkbox-wrapper{
9
3
  color:var(--color-controlpanel-text);
10
4
  }
11
5
 
12
- .channel-rows-list .ant-list-item.channel-row .ant-btn-text{
6
+ .control-panel-content .ant-list-item.channel-row .ant-list-item-meta{
7
+ align-items:center;
8
+ }
9
+
10
+ .control-panel-content .ant-list-item.channel-row .ant-btn-text{
13
11
  color:var(--color-button-icon-activated-text);
14
12
  transition:color 0.3s;
15
13
  }
16
14
 
17
- .channel-rows-list .ant-list-item.channel-row .ant-btn-text:hover,
18
- .channel-rows-list .ant-list-item.channel-row .ant-btn-text:focus-visible{
15
+ .control-panel-content .ant-list-item.channel-row .ant-btn-text:hover,
16
+ .control-panel-content .ant-list-item.channel-row .ant-btn-text:focus-visible{
19
17
  color:var(--color-button-tertiary-hover-text) !important;
20
18
  }
21
19
 
22
- .channel-rows-list .ant-list-item.channel-row .button-row{
20
+ .control-panel-content .ant-list-item.channel-row .button-row{
23
21
  margin-top:16px;
24
22
  display:flex;
25
23
  justify-content:start;
@@ -27,10 +25,24 @@
27
25
  gap:5px;
28
26
  }
29
27
 
30
- .channel-rows-list .ant-list-item.channel-row .button-row .ant-btn.ant-btn-sm{
28
+ .control-panel-content .ant-list-item.channel-row .button-row .ant-btn.ant-btn-sm{
31
29
  padding:12px 8px;
32
30
  }
33
31
 
34
- .channel-rows-list .ant-list-item.channel-row.controls-closed .ant-btn-text:not(:focus-visible){
32
+ .control-panel-content .ant-list-item.channel-row.controls-closed .ant-btn-text:not(:focus-visible){
35
33
  color:var(--color-controlpanel-text);
36
34
  }
35
+
36
+ .control-panel-content .ant-list-item.channel-row.single-channel{
37
+ background-color:var(--color-button-primary-bg);
38
+ }
39
+
40
+ .control-panel-content .ant-list-item.channel-row.single-channel .channel-visibility-controls,
41
+ .control-panel-content .ant-list-item.channel-row.single-channel .ant-list-item-meta-title{
42
+ color:var(--color-button-primary-text);
43
+ font-weight:600;
44
+ }
45
+
46
+ .control-panel-content .ant-list-item.channel-row.single-channel .color-picker .color-picker-swatch{
47
+ border-color:var(--color-button-primary-text);
48
+ }
@@ -1,9 +1,3 @@
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
1
  function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
8
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."); }
9
3
  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; } }
@@ -13,6 +7,8 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
13
7
  import { map } from "lodash";
14
8
  import React from "react";
15
9
  import { SketchPicker } from "react-color";
10
+ import "./styles.css";
11
+
16
12
  // if there are fewer than this many screen pixels below the swatch but more above, open above the swatch
17
13
  var OPEN_ABOVE_MARGIN = 310;
18
14
  var DEFAULT_COLOR = {
@@ -61,29 +57,31 @@ var ColorPicker = function ColorPicker(props) {
61
57
  }, [props.color]);
62
58
  var width = props.width || 36;
63
59
  var popoverDirectionStyle = openAboveSwatch ? {
64
- bottom: "21px"
60
+ bottom: "18px"
65
61
  } : {
66
- top: "0px"
62
+ top: "3px"
67
63
  };
68
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
69
- style: STYLES.swatch,
70
- ref: swatchRef,
71
- onClick: handleClick
64
+ return /*#__PURE__*/React.createElement("div", {
65
+ className: "color-picker"
72
66
  }, /*#__PURE__*/React.createElement("div", {
73
- style: _objectSpread(_objectSpread({}, STYLES.color), {}, {
67
+ ref: swatchRef,
68
+ onClick: handleClick,
69
+ className: "color-picker-swatch",
70
+ style: {
74
71
  width: "".concat(width, "px"),
75
72
  background: "rgba(".concat(map(currentColor, function (ele) {
76
73
  return ele;
77
74
  }), ")")
78
- })
79
- })), /*#__PURE__*/React.createElement("div", {
75
+ }
76
+ }), /*#__PURE__*/React.createElement("div", {
80
77
  style: {
81
78
  position: "absolute"
82
79
  }
83
80
  }, isOpen ? /*#__PURE__*/React.createElement("div", {
84
- style: _objectSpread(_objectSpread({}, STYLES.popover), popoverDirectionStyle)
81
+ className: "color-picker-popover",
82
+ style: popoverDirectionStyle
85
83
  }, /*#__PURE__*/React.createElement("div", {
86
- style: STYLES.cover,
84
+ className: "color-picker-cover",
87
85
  onClick: handleClose
88
86
  }), /*#__PURE__*/React.createElement(SketchPicker, {
89
87
  color: currentColor,
@@ -92,29 +90,4 @@ var ColorPicker = function ColorPicker(props) {
92
90
  disableAlpha: props.disableAlpha
93
91
  })) : null));
94
92
  };
95
- export default ColorPicker;
96
- var STYLES = {
97
- color: {
98
- height: "14px",
99
- margin: "3px",
100
- borderRadius: "2px"
101
- },
102
- swatch: {
103
- borderRadius: "3px",
104
- border: "1px solid var(--color-controlpanel-border)",
105
- display: "inline-block",
106
- cursor: "pointer",
107
- verticalAlign: "middle"
108
- },
109
- popover: {
110
- position: "absolute",
111
- zIndex: "9999"
112
- },
113
- cover: {
114
- position: "fixed",
115
- top: "0px",
116
- right: "0px",
117
- bottom: "0px",
118
- left: "0px"
119
- }
120
- };
93
+ export default ColorPicker;
@@ -0,0 +1,17 @@
1
+ .color-picker .color-picker-swatch{
2
+ height:15px;
3
+ border-radius:3px;
4
+ border:1px solid var(--color-controlpanel-border);
5
+ cursor:pointer;
6
+ }
7
+ .color-picker .color-picker-popover{
8
+ position:absolute;
9
+ z-index:9999;
10
+ }
11
+ .color-picker .color-picker-cover{
12
+ position:fixed;
13
+ top:0;
14
+ right:0;
15
+ bottom:0;
16
+ left:0;
17
+ }
@@ -9,7 +9,7 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
9
9
  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; }
10
10
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
11
11
  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); }
12
- import { Button, Collapse, Dropdown, Flex, Tooltip } from "antd";
12
+ import { Button, Checkbox, Collapse, Dropdown, Flex, Tooltip } from "antd";
13
13
  import React from "react";
14
14
  import { PRESET_COLOR_MAP } from "../../shared/constants";
15
15
  import { select, useViewerState } from "../../state/store";
@@ -25,7 +25,7 @@ var ControlTab = /*#__PURE__*/function (ControlTab) {
25
25
  ControlTab[ControlTab["Metadata"] = 2] = "Metadata";
26
26
  return ControlTab;
27
27
  }(ControlTab || {});
28
- var ControlTabNames = _defineProperty(_defineProperty(_defineProperty({}, ControlTab.Channels, "Channel Settings"), ControlTab.Advanced, "Advanced Settings"), ControlTab.Metadata, "Metadata");
28
+ var ControlTabNames = _defineProperty(_defineProperty(_defineProperty({}, ControlTab.Channels, "Channel settings"), ControlTab.Advanced, "Advanced settings"), ControlTab.Metadata, "Metadata");
29
29
  function ControlPanel(props) {
30
30
  var _React$useState = React.useState(ControlTab.Channels),
31
31
  _React$useState2 = _slicedToArray(_React$useState, 2),
@@ -36,6 +36,8 @@ function ControlPanel(props) {
36
36
  props.setCollapsed(false);
37
37
  };
38
38
  var resetToDefaultViewerState = useViewerState(select("resetToDefaultViewerState"));
39
+ var singleChannelMode = useViewerState(select("singleChannelMode"));
40
+ var changeViewerSetting = useViewerState(select("changeViewerSetting"));
39
41
  var controlPanelContainerRef = React.useRef(null);
40
42
  var getDropdownContainer = controlPanelContainerRef.current ? function () {
41
43
  return controlPanelContainerRef.current;
@@ -50,7 +52,7 @@ function ControlPanel(props) {
50
52
  var key = _ref.key;
51
53
  return props.onApplyColorPresets(PRESET_COLOR_MAP[key].colors);
52
54
  };
53
- var renderColorPresetsDropdown = function renderColorPresetsDropdown() {
55
+ var renderChannelSettingsHeader = function renderChannelSettingsHeader() {
54
56
  var dropDownMenuProps = {
55
57
  items: PRESET_COLOR_MAP.map(function (preset, index) {
56
58
  return {
@@ -60,8 +62,9 @@ function ControlPanel(props) {
60
62
  }),
61
63
  onClick: makeTurnOnPresetFn
62
64
  };
65
+ var singleChannelTitle = singleChannelMode ? "Turn off single channel mode" : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", null, "Turn on single channel mode"), /*#__PURE__*/React.createElement("div", null, "Use arrow keys to navigate"));
63
66
  return /*#__PURE__*/React.createElement("div", {
64
- className: "color-presets-dropdown"
67
+ className: "channel-settings-header"
65
68
  }, /*#__PURE__*/React.createElement(Dropdown, {
66
69
  trigger: ["click"],
67
70
  menu: dropDownMenuProps,
@@ -78,7 +81,21 @@ function ControlPanel(props) {
78
81
  style: {
79
82
  fontSize: "14px"
80
83
  }
81
- })))));
84
+ })))), /*#__PURE__*/React.createElement("div", {
85
+ style: {
86
+ alignSelf: "end",
87
+ width: "40%"
88
+ }
89
+ }, /*#__PURE__*/React.createElement(Tooltip, {
90
+ title: singleChannelTitle
91
+ }, /*#__PURE__*/React.createElement(Checkbox, {
92
+ name: "Single channel mode",
93
+ checked: singleChannelMode,
94
+ onChange: function onChange(_ref2) {
95
+ var target = _ref2.target;
96
+ return changeViewerSetting("singleChannelMode", target.checked);
97
+ }
98
+ }, "Single channel mode"))));
82
99
  };
83
100
  var renderTab = function renderTab(thisTab, icon) {
84
101
  return /*#__PURE__*/React.createElement(Tooltip, _extends({
@@ -164,8 +181,8 @@ function ControlPanel(props) {
164
181
  }
165
182
  }, /*#__PURE__*/React.createElement("h2", {
166
183
  className: "control-panel-title"
167
- }, ControlTabNames[tab]), visibleControls.colorPresetsDropdown && tab === ControlTab.Channels && renderColorPresetsDropdown(), hasImage && /*#__PURE__*/React.createElement("div", {
168
- className: "channel-rows-list"
184
+ }, ControlTabNames[tab]), visibleControls.colorPresetsDropdown && tab === ControlTab.Channels && renderChannelSettingsHeader(), hasImage && /*#__PURE__*/React.createElement("div", {
185
+ className: "control-panel-content"
169
186
  }, tab === ControlTab.Channels && /*#__PURE__*/React.createElement(ChannelsWidget, {
170
187
  channelDataChannels: props.channelDataChannels,
171
188
  channelGroupedByType: props.channelGroupedByType,
@@ -8,6 +8,10 @@
8
8
  border-right:1px solid var(--color-controlpanel-border);
9
9
  }
10
10
 
11
+ .control-panel-col-container .ant-checkbox-wrapper{
12
+ align-items:center;
13
+ }
14
+
11
15
  .control-panel-col-container .control-panel-tab-col{
12
16
  text-align:center;
13
17
  }
@@ -64,38 +68,47 @@
64
68
  font-size:1.4em;
65
69
  }
66
70
 
67
- .control-panel-col-container .control-panel-col .color-presets-dropdown{
71
+ .control-panel-col-container .control-panel-col .channel-settings-header{
68
72
  margin:0 16px 16px;
73
+ display:flex;
74
+ justify-content:space-between;
69
75
  }
70
76
 
71
- .control-panel-col-container .control-panel-col .channel-rows-list{
72
- border-top:1px solid var(--color-controlpanel-border);
73
- }
74
-
75
- .control-panel-col-container .control-panel-col .channel-rows-list .ant-list-item-meta{
76
- align-items:center;
77
+ .control-panel-col-container .control-panel-col .channel-settings-header .ant-checkbox-wrapper{
78
+ color:var(--color-controlpanel-text);
77
79
  }
78
80
 
79
- .control-panel-col-container .control-panel-col .channel-rows-list .ant-list-item-meta .ant-list-item-meta-title{
80
- margin:0;
81
- }
81
+ .control-panel-col-container .control-panel-col .ant-checkbox-wrapper:hover .ant-checkbox-inner{
82
+ border-color:white;
83
+ }
82
84
 
83
- .control-panel-col-container .control-panel-col .channel-rows-list .ant-checkbox-wrapper:hover .ant-checkbox-inner{
84
- border-color:white;
85
+ .control-panel-col-container .control-panel-col .control-panel-content{
86
+ border-top:1px solid var(--color-controlpanel-border);
87
+ }
88
+
89
+ .control-panel-col-container .control-panel-col .control-panel-content .ant-list-item-meta .ant-list-item-meta-title{
90
+ margin:0;
85
91
  }
86
92
 
87
- .control-panel-col-container .control-panel-col .channel-rows-list .channel-visibility-controls,
88
- .control-panel-col-container .control-panel-col .channel-rows-list .ant-collapse-extra{
93
+ .control-panel-col-container .control-panel-col .control-panel-content .channel-visibility-controls,
94
+ .control-panel-col-container .control-panel-col .control-panel-content .ant-collapse-extra{
89
95
  width:40%;
90
96
  display:flex;
91
97
  }
92
98
 
93
- .control-panel-col-container .control-panel-col .channel-rows-list .channel-visibility-controls .ant-checkbox-wrapper, .control-panel-col-container .control-panel-col .channel-rows-list .ant-collapse-extra .ant-checkbox-wrapper{
99
+ .control-panel-col-container .control-panel-col .control-panel-content .channel-visibility-controls .ant-checkbox-wrapper,
100
+ .control-panel-col-container .control-panel-col .control-panel-content .channel-visibility-controls .single-channel-text,
101
+ .control-panel-col-container .control-panel-col .control-panel-content .ant-collapse-extra .ant-checkbox-wrapper,
102
+ .control-panel-col-container .control-panel-col .control-panel-content .ant-collapse-extra .single-channel-text{
94
103
  flex:4;
95
104
  }
96
105
 
97
- .control-panel-col-container .control-panel-col .channel-rows-list .ant-collapse-content-box{
98
- padding:0 16px;
106
+ .control-panel-col-container .control-panel-col .control-panel-content .channel-visibility-controls .single-channel-text{
107
+ font-size:11px;
108
+ }
109
+
110
+ .control-panel-col-container .control-panel-col .control-panel-content .ant-collapse-content-box{
111
+ padding:0;
99
112
  }
100
113
 
101
114
  .control-panel-col-container .control-panel-col .ant-collapse{
@@ -107,6 +120,46 @@
107
120
  background-color:var(--color-controlpanel-section-bg);
108
121
  }
109
122
 
123
+ .control-panel-col-container .control-panel-col .ant-collapse.single-channel-mode .ant-list{
124
+ cursor:pointer;
125
+ }
126
+
127
+ .control-panel-col-container .control-panel-col .ant-collapse .ant-collapse-item:not(.ant-collapse-item-active):last-child{
128
+ border-bottom:1px solid var(--color-controlpanel-border);
129
+ }
130
+
131
+ .control-panel-col-container .control-panel-col .ant-list-item,
132
+ .control-panel-col-container .control-panel-col .color-picker-row{
133
+ padding:0 16px;
134
+ border-bottom:none;
135
+ display:flex;
136
+ flex-flow:row wrap;
137
+ color:var(--color-controlpanel-text);
138
+ }
139
+
140
+ .control-panel-col-container .control-panel-col .ant-list-item::after, .control-panel-col-container .control-panel-col .color-picker-row::after{
141
+ content:"";
142
+ margin-top:22px;
143
+ width:100%;
144
+ border-bottom:1px solid var(--color-controlpanel-border);
145
+ }
146
+
147
+ .control-panel-col-container .control-panel-col .ant-list-item{
148
+ padding-top:22px;
149
+ }
150
+
151
+ .control-panel-col-container .control-panel-col .ant-list-item::after{
152
+ margin-top:22px;
153
+ }
154
+
155
+ .control-panel-col-container .control-panel-col .color-picker-row{
156
+ padding-top:16px;
157
+ }
158
+
159
+ .control-panel-col-container .control-panel-col .color-picker-row::after{
160
+ margin-top:16px;
161
+ }
162
+
110
163
  .control-panel-col-container .control-panel-col .noUi-horizontal .noUi-handle{
111
164
  box-shadow:none;
112
165
  cursor:pointer;
@@ -7,9 +7,13 @@ var ColorPickerRow = function ColorPickerRow(_ref) {
7
7
  _onColorChange = _ref.onColorChange,
8
8
  children = _ref.children;
9
9
  return /*#__PURE__*/React.createElement("div", {
10
- style: STYLES.colorPickerRow
10
+ className: "color-picker-row"
11
11
  }, /*#__PURE__*/React.createElement("span", {
12
- style: STYLES.colorPicker
12
+ style: {
13
+ marginRight: "16px",
14
+ display: "flex",
15
+ alignItems: "center"
16
+ }
13
17
  }, /*#__PURE__*/React.createElement(ColorPicker, {
14
18
  color: colorArrayToObject(color),
15
19
  onColorChange: function onColorChange(color) {
@@ -36,15 +40,4 @@ var CustomizeWidget = function CustomizeWidget(props) {
36
40
  }
37
41
  }, "Bounding box color", !showBoundingBox && /*#__PURE__*/React.createElement("i", null, " - bounding box turned off")));
38
42
  };
39
- var STYLES = {
40
- colorPickerRow: {
41
- padding: "14px 0",
42
- display: "flex",
43
- borderBottom: "1px solid #6e6e6e",
44
- color: "var(--color-controlpanel-text)"
45
- },
46
- colorPicker: {
47
- marginRight: "16px"
48
- }
49
- };
50
43
  export default CustomizeWidget;
@@ -24,8 +24,7 @@ var GlobalVolumeControls = function GlobalVolumeControls(props) {
24
24
  var showControls = props.visibleControls;
25
25
  return /*#__PURE__*/React.createElement("div", {
26
26
  style: {
27
- paddingTop: 18,
28
- paddingBottom: 22
27
+ padding: "18px 16px 22px"
29
28
  }
30
29
  }, showControls.alphaMaskSlider && createSliderRow("mask cell", maskAlpha, 100, "maskAlpha"), showControls.brightnessSlider && createSliderRow("brightness", brightness, 100, "brightness"), showControls.densitySlider && createSliderRow("density", density, 100, "density"), showControls.levelsSliders && createSliderRow("levels", levels, 255, "levels"), showControls.interpolationControl && /*#__PURE__*/React.createElement(SliderRow, {
31
30
  label: "interpolate",
@@ -25,7 +25,8 @@ export var
25
25
  LEVELS_SLIDER_DEFAULT = [35.0, 140.0, 255.0],
26
26
  INTERPOLATION_ENABLED_DEFAULT = true,
27
27
  OTHER_CHANNEL_KEY = "Other",
28
- SINGLE_GROUP_CHANNEL_KEY = "Channels";
28
+ SINGLE_GROUP_CHANNEL_KEY = "Channels",
29
+ SINGLE_CHANNEL_MODE_COLOR = [255, 255, 255];
29
30
  export var TFEDITOR_DEFAULT_COLOR = [255, 255, 255];
30
31
  export var TFEDITOR_MAX_BIN = 255;
31
32
  export var CACHE_MAX_SIZE = 1000000000;
@@ -163,6 +164,8 @@ export var getDefaultViewerState = function getDefaultViewerState() {
163
164
  },
164
165
  time: 0,
165
166
  scene: 0,
167
+ singleChannelMode: false,
168
+ singleChannelIndex: 0,
166
169
  // Do not override camera position, target, etc. by default;
167
170
  // instead, let the viewer apply default camera settings based on the view mode.
168
171
  // This prevents a bug where the camera's position and view mode are set to
@@ -436,7 +436,9 @@ describe("Viewer state", function () {
436
436
  },
437
437
  time: 0,
438
438
  scene: 0,
439
- cameraState: undefined
439
+ cameraState: undefined,
440
+ singleChannelMode: false,
441
+ singleChannelIndex: 0
440
442
  };
441
443
  var SERIALIZED_DEFAULT_VIEWER_STATE = {
442
444
  mode: "volumetric",
@@ -455,7 +457,9 @@ describe("Viewer state", function () {
455
457
  reg: "0:1,0:1,0:1",
456
458
  slice: "0.5,0.5,0.5",
457
459
  t: "0",
458
- scene: "0"
460
+ scene: "0",
461
+ scm: "0",
462
+ sci: "0"
459
463
  };
460
464
  var CUSTOM_VIEWER_STATE = {
461
465
  renderMode: RenderMode.pathTrace,
@@ -483,6 +487,8 @@ describe("Viewer state", function () {
483
487
  },
484
488
  time: 100,
485
489
  scene: 3,
490
+ singleChannelMode: true,
491
+ singleChannelIndex: 3,
486
492
  cameraState: {
487
493
  position: [-1.05, -4, 45],
488
494
  target: [0, 0, 0],
@@ -509,6 +515,8 @@ describe("Viewer state", function () {
509
515
  slice: "0.25,0.75,0.5",
510
516
  t: "100",
511
517
  scene: "3",
518
+ scm: "1",
519
+ sci: "3",
512
520
  cam: "pos:-1.05:-4:45,tar:0:0:0,up:0:1:0,ort:3.534,fov:43.5"
513
521
  };
514
522
  describe("serializeViewerState", function () {
@@ -1,5 +1,5 @@
1
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
- var _ViewerChannelSetting, _ViewerChannelSetting2, _ViewerChannelSetting3, _ViewerChannelSetting4, _ViewerChannelSetting5, _ViewerChannelSetting6, _ViewerChannelSetting7, _ViewerChannelSetting8, _ViewerChannelSetting9, _ViewerChannelSetting10, _ViewerChannelSetting11, _ViewerChannelSetting12, _ViewerChannelSetting13, _ViewerChannelSetting14, _ViewerStateKeys$View, _ViewerStateKeys$Mode, _ViewerStateKeys$Mask, _ViewerStateKeys$Imag, _ViewerStateKeys$Axes, _ViewerStateKeys$Boun, _ViewerStateKeys$Boun2, _ViewerStateKeys$Back, _ViewerStateKeys$Auto, _ViewerStateKeys$Brig, _ViewerStateKeys$Dens, _ViewerStateKeys$Leve, _ViewerStateKeys$Inte, _ViewerStateKeys$Regi, _ViewerStateKeys$Slic, _ViewerStateKeys$Time, _ViewerStateKeys$Scen, _ViewerStateKeys$Came;
2
+ var _ViewerChannelSetting, _ViewerChannelSetting2, _ViewerChannelSetting3, _ViewerChannelSetting4, _ViewerChannelSetting5, _ViewerChannelSetting6, _ViewerChannelSetting7, _ViewerChannelSetting8, _ViewerChannelSetting9, _ViewerChannelSetting10, _ViewerChannelSetting11, _ViewerChannelSetting12, _ViewerChannelSetting13, _ViewerChannelSetting14, _ViewerStateKeys$View, _ViewerStateKeys$Mode, _ViewerStateKeys$Mask, _ViewerStateKeys$Imag, _ViewerStateKeys$Axes, _ViewerStateKeys$Boun, _ViewerStateKeys$Sing, _ViewerStateKeys$Sing2, _ViewerStateKeys$Boun2, _ViewerStateKeys$Back, _ViewerStateKeys$Auto, _ViewerStateKeys$Brig, _ViewerStateKeys$Dens, _ViewerStateKeys$Leve, _ViewerStateKeys$Inte, _ViewerStateKeys$Regi, _ViewerStateKeys$Slic, _ViewerStateKeys$Time, _ViewerStateKeys$Scen, _ViewerStateKeys$Came;
3
3
  function _regeneratorRuntime() { "use strict"; var r = _regenerator(), e = r.m(_regeneratorRuntime), t = (Object.getPrototypeOf ? Object.getPrototypeOf(e) : e.__proto__).constructor; function n(r) { var e = "function" == typeof r && r.constructor; return !!e && (e === t || "GeneratorFunction" === (e.displayName || e.name)); } var o = { "throw": 1, "return": 2, "break": 3, "continue": 3 }; function a(r) { var e, t; return function (n) { e || (e = { stop: function stop() { return t(n.a, 2); }, "catch": function _catch() { return n.v; }, abrupt: function abrupt(r, e) { return t(n.a, o[r], e); }, delegateYield: function delegateYield(r, o, a) { return e.resultName = o, t(n.d, _regeneratorValues(r), a); }, finish: function finish(r) { return t(n.f, r); } }, t = function t(r, _t, o) { n.p = e.prev, n.n = e.next; try { return r(_t, o); } finally { e.next = n.n; } }), e.resultName && (e[e.resultName] = n.v, e.resultName = void 0), e.sent = n.v, e.next = n.n; try { return r.call(this, e); } finally { n.p = e.prev, n.n = e.next; } }; } return (_regeneratorRuntime = function _regeneratorRuntime() { return { wrap: function wrap(e, t, n, o) { return r.w(a(e), t, n, o && o.reverse()); }, isGeneratorFunction: n, mark: r.m, awrap: function awrap(r, e) { return new _OverloadYield(r, e); }, AsyncIterator: _regeneratorAsyncIterator, async: function async(r, e, t, o, u) { return (n(e) ? _regeneratorAsyncGen : _regeneratorAsync)(a(r), e, t, o, u); }, keys: _regeneratorKeys, values: _regeneratorValues }; })(); }
4
4
  function _regeneratorValues(e) { if (null != e) { var t = e["function" == typeof Symbol && Symbol.iterator || "@@iterator"], r = 0; if (t) return t.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) return { next: function next() { return e && r >= e.length && (e = void 0), { value: e && e[r++], done: !e }; } }; } throw new TypeError(_typeof(e) + " is not iterable"); }
5
5
  function _regeneratorKeys(e) { var n = Object(e), r = []; for (var t in n) r.unshift(t); return function e() { for (; r.length;) if ((t = r.pop()) in n) return e.value = t, e.done = !1, e; return e.done = !0, e; }; }
@@ -111,6 +111,8 @@ export var ViewerStateKeys = /*#__PURE__*/function (ViewerStateKeys) {
111
111
  ViewerStateKeys["Time"] = "t";
112
112
  ViewerStateKeys["Scene"] = "scene";
113
113
  ViewerStateKeys["CameraState"] = "cam";
114
+ ViewerStateKeys["SingleChannelMode"] = "scm";
115
+ ViewerStateKeys["SingleChannelIndex"] = "sci";
114
116
  return ViewerStateKeys;
115
117
  }({});
116
118
  export var CameraTransformKeys = /*#__PURE__*/function (CameraTransformKeys) {
@@ -257,6 +259,8 @@ _ViewerStateKeys$Mask = ViewerStateKeys.Mask;
257
259
  _ViewerStateKeys$Imag = ViewerStateKeys.Image;
258
260
  _ViewerStateKeys$Axes = ViewerStateKeys.Axes;
259
261
  _ViewerStateKeys$Boun = ViewerStateKeys.BoundingBox;
262
+ _ViewerStateKeys$Sing = ViewerStateKeys.SingleChannelMode;
263
+ _ViewerStateKeys$Sing2 = ViewerStateKeys.SingleChannelIndex;
260
264
  _ViewerStateKeys$Boun2 = ViewerStateKeys.BoundingBoxColor;
261
265
  _ViewerStateKeys$Back = ViewerStateKeys.BackgroundColor;
262
266
  _ViewerStateKeys$Auto = ViewerStateKeys.Autorotate;
@@ -287,6 +291,10 @@ export var ViewerStateParams = /*#__PURE__*/_createClass(function ViewerStatePar
287
291
  _defineProperty(this, _ViewerStateKeys$Axes, undefined);
288
292
  /** Whether to show the bounding box. "1" is enabled. Disabled by default. */
289
293
  _defineProperty(this, _ViewerStateKeys$Boun, undefined);
294
+ /** Whether single-channel mode is active. "1" is active. Inactive by default. */
295
+ _defineProperty(this, _ViewerStateKeys$Sing, undefined);
296
+ /** If single-channel mode is active, which channel index is shown. Defaults to 0. */
297
+ _defineProperty(this, _ViewerStateKeys$Sing2, undefined);
290
298
  /** The color of the bounding box, as a 6-digit hex color. */
291
299
  _defineProperty(this, _ViewerStateKeys$Boun2, undefined);
292
300
  /** The background color, as a 6-digit hex color. */
@@ -942,6 +950,8 @@ export function deserializeViewerState(params) {
942
950
  time: parseStringInt(params[ViewerStateKeys.Time], 0, Number.POSITIVE_INFINITY),
943
951
  scene: parseStringInt(params[ViewerStateKeys.Scene], 0, Number.POSITIVE_INFINITY),
944
952
  renderMode: parseStringEnum(params[ViewerStateKeys.Mode], RenderMode),
953
+ singleChannelMode: parseStringBoolean(params[ViewerStateKeys.SingleChannelMode]),
954
+ singleChannelIndex: parseStringInt(params[ViewerStateKeys.SingleChannelIndex], 0, Number.POSITIVE_INFINITY),
945
955
  cameraState: parseCameraState(params[ViewerStateKeys.CameraState])
946
956
  };
947
957
 
@@ -973,11 +983,11 @@ export function deserializeViewerState(params) {
973
983
  * @returns A `ViewerStateParams` object with the serialized parameters. Undefined values are removed.
974
984
  */
975
985
  export function serializeViewerState(state, removeDefaults) {
976
- var _state$maskAlpha, _state$brightness, _state$density, _state$levels, _state$time, _state$scene, _result;
986
+ var _state$maskAlpha, _state$brightness, _state$density, _state$levels, _state$time, _state$scene, _state$singleChannelI, _result;
977
987
  if (removeDefaults) {
978
988
  state = removeMatchingProperties(state, getDefaultViewerState());
979
989
  }
980
- var result = (_result = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_result, ViewerStateKeys.Mode, state.renderMode), ViewerStateKeys.Mask, (_state$maskAlpha = state.maskAlpha) === null || _state$maskAlpha === void 0 ? void 0 : _state$maskAlpha.toString()), ViewerStateKeys.Image, state.imageType), ViewerStateKeys.Axes, serializeBoolean(state.showAxes)), ViewerStateKeys.BoundingBox, serializeBoolean(state.showBoundingBox)), ViewerStateKeys.BoundingBoxColor, state.boundingBoxColor && colorArrayToHex(state.boundingBoxColor)), ViewerStateKeys.BackgroundColor, state.backgroundColor && colorArrayToHex(state.backgroundColor)), ViewerStateKeys.Autorotate, serializeBoolean(state.autorotate)), ViewerStateKeys.Brightness, (_state$brightness = state.brightness) === null || _state$brightness === void 0 ? void 0 : _state$brightness.toString()), ViewerStateKeys.Density, (_state$density = state.density) === null || _state$density === void 0 ? void 0 : _state$density.toString()), _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_result, ViewerStateKeys.Interpolation, serializeBoolean(state.interpolationEnabled)), ViewerStateKeys.Region, state.region && serializeRegion(state.region)), ViewerStateKeys.Slice, state.slice && serializeSlice(state.slice)), ViewerStateKeys.Levels, (_state$levels = state.levels) === null || _state$levels === void 0 ? void 0 : _state$levels.join(",")), ViewerStateKeys.Time, (_state$time = state.time) === null || _state$time === void 0 ? void 0 : _state$time.toString()), ViewerStateKeys.Scene, (_state$scene = state.scene) === null || _state$scene === void 0 ? void 0 : _state$scene.toString()), ViewerStateKeys.CameraState, state.cameraState && serializeCameraState(state.cameraState, removeDefaults, state.viewMode)));
990
+ var result = (_result = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_result, ViewerStateKeys.Mode, state.renderMode), ViewerStateKeys.Mask, (_state$maskAlpha = state.maskAlpha) === null || _state$maskAlpha === void 0 ? void 0 : _state$maskAlpha.toString()), ViewerStateKeys.Image, state.imageType), ViewerStateKeys.Axes, serializeBoolean(state.showAxes)), ViewerStateKeys.BoundingBox, serializeBoolean(state.showBoundingBox)), ViewerStateKeys.BoundingBoxColor, state.boundingBoxColor && colorArrayToHex(state.boundingBoxColor)), ViewerStateKeys.BackgroundColor, state.backgroundColor && colorArrayToHex(state.backgroundColor)), ViewerStateKeys.Autorotate, serializeBoolean(state.autorotate)), ViewerStateKeys.Brightness, (_state$brightness = state.brightness) === null || _state$brightness === void 0 ? void 0 : _state$brightness.toString()), ViewerStateKeys.Density, (_state$density = state.density) === null || _state$density === void 0 ? void 0 : _state$density.toString()), _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_result, ViewerStateKeys.Interpolation, serializeBoolean(state.interpolationEnabled)), ViewerStateKeys.Region, state.region && serializeRegion(state.region)), ViewerStateKeys.Slice, state.slice && serializeSlice(state.slice)), ViewerStateKeys.Levels, (_state$levels = state.levels) === null || _state$levels === void 0 ? void 0 : _state$levels.join(",")), ViewerStateKeys.Time, (_state$time = state.time) === null || _state$time === void 0 ? void 0 : _state$time.toString()), ViewerStateKeys.Scene, (_state$scene = state.scene) === null || _state$scene === void 0 ? void 0 : _state$scene.toString()), ViewerStateKeys.SingleChannelMode, serializeBoolean(state.singleChannelMode)), ViewerStateKeys.SingleChannelIndex, (_state$singleChannelI = state.singleChannelIndex) === null || _state$singleChannelI === void 0 ? void 0 : _state$singleChannelI.toString()), ViewerStateKeys.CameraState, state.cameraState && serializeCameraState(state.cameraState, removeDefaults, state.viewMode)));
981
991
  var viewModeToViewParam = _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, ViewMode.threeD, "3D"), ViewMode.xy, "Z"), ViewMode.xz, "Y"), ViewMode.yz, "X");
982
992
  result[ViewerStateKeys.View] = state.viewMode && viewModeToViewParam[state.viewMode];
983
993
  return removeUndefinedProperties(result);
@@ -75,7 +75,9 @@ export var selectViewerSettings = function selectViewerSettings(store) {
75
75
  slice: store.slice,
76
76
  time: store.time,
77
77
  scene: store.scene,
78
- cameraState: store.cameraState
78
+ cameraState: store.cameraState,
79
+ singleChannelMode: store.singleChannelMode,
80
+ singleChannelIndex: store.singleChannelIndex
79
81
  };
80
82
  };
81
83
 
@@ -38,6 +38,8 @@ var arbitraryViewerState = function arbitraryViewerState() {
38
38
  },
39
39
  time: 12,
40
40
  scene: 3,
41
+ singleChannelMode: true,
42
+ singleChannelIndex: 3,
41
43
  cameraState: undefined
42
44
  };
43
45
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aics/vole-app",
3
- "version": "3.1.2",
3
+ "version": "3.2.0",
4
4
  "description": "web view of cell volume images",
5
5
  "main": "es/index.js",
6
6
  "module": "es/index.js",
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
- import type { ColorObject } from "../shared/utils/colorRepresentations";
2
+ import type { ColorObject } from "../../shared/utils/colorRepresentations";
3
+ import "./styles.css";
3
4
  type ColorChangeHandler = (currentColor: ColorObject, prevColor?: ColorObject, idx?: number) => void;
4
5
  interface ColorPickerProps {
5
6
  color: ColorObject;
@@ -5,7 +5,7 @@ import type { AxisName } from "./types";
5
5
  import type { ColorArray } from "./utils/colorRepresentations";
6
6
  import type { ViewerChannelSettings } from "./utils/viewerChannelSettings";
7
7
  export declare const // Control panel will automatically close if viewport is less than this width
8
- CONTROL_PANEL_CLOSE_WIDTH = 970, CLIPPING_PANEL_HEIGHT_DEFAULT = 200, CLIPPING_PANEL_HEIGHT_TALL = 235, BACKGROUND_COLOR_DEFAULT: ColorArray, BOUNDING_BOX_COLOR_DEFAULT: ColorArray, AXIS_MARGIN_DEFAULT: [number, number], SCALE_BAR_MARGIN_DEFAULT: [number, number], LUT_MIN_PERCENTILE = 0.5, LUT_MAX_PERCENTILE = 0.983, ALPHA_MASK_SLIDER_DEFAULT = 0, BRIGHTNESS_SLIDER_LEVEL_DEFAULT = 70, DENSITY_SLIDER_LEVEL_DEFAULT = 50, LEVELS_SLIDER_DEFAULT: ColorArray, INTERPOLATION_ENABLED_DEFAULT = true, OTHER_CHANNEL_KEY = "Other", SINGLE_GROUP_CHANNEL_KEY = "Channels";
8
+ CONTROL_PANEL_CLOSE_WIDTH = 970, CLIPPING_PANEL_HEIGHT_DEFAULT = 200, CLIPPING_PANEL_HEIGHT_TALL = 235, BACKGROUND_COLOR_DEFAULT: ColorArray, BOUNDING_BOX_COLOR_DEFAULT: ColorArray, AXIS_MARGIN_DEFAULT: [number, number], SCALE_BAR_MARGIN_DEFAULT: [number, number], LUT_MIN_PERCENTILE = 0.5, LUT_MAX_PERCENTILE = 0.983, ALPHA_MASK_SLIDER_DEFAULT = 0, BRIGHTNESS_SLIDER_LEVEL_DEFAULT = 70, DENSITY_SLIDER_LEVEL_DEFAULT = 50, LEVELS_SLIDER_DEFAULT: ColorArray, INTERPOLATION_ENABLED_DEFAULT = true, OTHER_CHANNEL_KEY = "Other", SINGLE_GROUP_CHANNEL_KEY = "Channels", SINGLE_CHANNEL_MODE_COLOR: ColorArray;
9
9
  export declare const TFEDITOR_DEFAULT_COLOR: ColorArray;
10
10
  export declare const TFEDITOR_MAX_BIN = 255;
11
11
  export declare const CACHE_MAX_SIZE = 1000000000;
@@ -48,7 +48,9 @@ export declare enum ViewerStateKeys {
48
48
  Slice = "slice",
49
49
  Time = "t",
50
50
  Scene = "scene",
51
- CameraState = "cam"
51
+ CameraState = "cam",
52
+ SingleChannelMode = "scm",
53
+ SingleChannelIndex = "sci"
52
54
  }
53
55
  export declare enum CameraTransformKeys {
54
56
  /** Camera position in 3D coordinates. */
@@ -194,6 +196,10 @@ export declare class ViewerStateParams {
194
196
  [ViewerStateKeys.Axes]?: string;
195
197
  /** Whether to show the bounding box. "1" is enabled. Disabled by default. */
196
198
  [ViewerStateKeys.BoundingBox]?: string;
199
+ /** Whether single-channel mode is active. "1" is active. Inactive by default. */
200
+ [ViewerStateKeys.SingleChannelMode]?: string;
201
+ /** If single-channel mode is active, which channel index is shown. Defaults to 0. */
202
+ [ViewerStateKeys.SingleChannelIndex]?: string;
197
203
  /** The color of the bounding box, as a 6-digit hex color. */
198
204
  [ViewerStateKeys.BoundingBoxColor]?: string;
199
205
  /** The background color, as a 6-digit hex color. */
@@ -22,6 +22,8 @@ export type ViewerState = {
22
22
  time: number;
23
23
  scene: number;
24
24
  cameraState: Partial<CameraState> | undefined;
25
+ singleChannelMode: boolean;
26
+ singleChannelIndex: number;
25
27
  };
26
28
  export type ChannelState = {
27
29
  name: string;