@aics/vole-app 3.3.0 → 3.3.1
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.
- package/LICENSE +21 -25
- package/es/aics-image-viewer/components/App/index.js +10 -9
- package/es/aics-image-viewer/components/ChannelsWidget.js +2 -2
- package/es/aics-image-viewer/components/ControlPanel/index.js +15 -11
- package/es/aics-image-viewer/components/ControlPanel/styles.css +5 -5
- package/es/aics-image-viewer/components/ErrorAlert/index.js +91 -64
- package/es/aics-image-viewer/components/ErrorAlert/styles.css +33 -4
- package/es/aics-image-viewer/components/StyleProvider/index.js +42 -22
- package/es/aics-image-viewer/components/TfEditor/index.js +8 -1
- package/es/aics-image-viewer/components/Toolbar/index.js +33 -12
- package/es/aics-image-viewer/components/Toolbar/styles.css +21 -130
- package/es/aics-image-viewer/components/shared/ControlPanelRow/styles.css +1 -1
- package/es/aics-image-viewer/components/useVolume.js +3 -0
- package/es/aics-image-viewer/shared/constants.js +1 -1
- package/es/aics-image-viewer/shared/utils/playControls.js +12 -1
- package/es/aics-image-viewer/shared/utils/sceneStore.js +8 -0
- package/es/aics-image-viewer/shared/utils/viewerChannelSettings.js +3 -4
- package/package.json +5 -5
- package/type-declarations/aics-image-viewer/components/App/types.d.ts +2 -2
- package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +4 -5
- package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +8 -5
- package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +2 -1
- package/type-declarations/aics-image-viewer/components/useVolume.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/constants.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +1 -0
- package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +2 -1
- package/LICENSE.txt +0 -26
|
@@ -317,6 +317,7 @@ var TfEditor = function TfEditor(props) {
|
|
|
317
317
|
colorPickerPosition = _useState8[0],
|
|
318
318
|
setColorPickerPosition = _useState8[1];
|
|
319
319
|
var lastColorRef = useRef(TFEDITOR_DEFAULT_COLOR);
|
|
320
|
+
var dropdownContainerRef = useRef(null);
|
|
320
321
|
var svgRef = useRef(null); // need access to SVG element to measure mouse position
|
|
321
322
|
|
|
322
323
|
var histogram = props.channelData.histogram;
|
|
@@ -765,7 +766,9 @@ var TfEditor = function TfEditor(props) {
|
|
|
765
766
|
}
|
|
766
767
|
})))), props.volumeEnabled && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h4", null, "Volume settings"), /*#__PURE__*/React.createElement("div", {
|
|
767
768
|
className: "tf-editor-control-row"
|
|
768
|
-
}, /*#__PURE__*/React.createElement("div",
|
|
769
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
770
|
+
ref: dropdownContainerRef
|
|
771
|
+
}, /*#__PURE__*/React.createElement(Dropdown, {
|
|
769
772
|
trigger: ["click"],
|
|
770
773
|
menu: {
|
|
771
774
|
items: [{
|
|
@@ -785,6 +788,10 @@ var TfEditor = function TfEditor(props) {
|
|
|
785
788
|
var key = _ref5.key;
|
|
786
789
|
return applyTFGenerator(key);
|
|
787
790
|
}
|
|
791
|
+
},
|
|
792
|
+
getPopupContainer: function getPopupContainer() {
|
|
793
|
+
var _dropdownContainerRef;
|
|
794
|
+
return (_dropdownContainerRef = dropdownContainerRef.current) !== null && _dropdownContainerRef !== void 0 ? _dropdownContainerRef : document.body;
|
|
788
795
|
}
|
|
789
796
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
790
797
|
size: "small"
|
|
@@ -4,8 +4,6 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
|
|
|
4
4
|
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; }
|
|
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
|
-
// TODO this really ought to be exported at the top level...
|
|
8
|
-
|
|
9
7
|
import { ReloadOutlined } from "@ant-design/icons";
|
|
10
8
|
import { Button, Radio, Select, Tooltip } from "antd";
|
|
11
9
|
import { debounce } from "lodash";
|
|
@@ -35,6 +33,7 @@ var Toolbar = function Toolbar(props) {
|
|
|
35
33
|
var leftRef = React.useRef(null);
|
|
36
34
|
var rightRef = React.useRef(null);
|
|
37
35
|
var centerRef = React.useRef(null);
|
|
36
|
+
var resizeObserver = React.useRef();
|
|
38
37
|
var _React$useState = React.useState(false),
|
|
39
38
|
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
40
39
|
scrollMode = _React$useState2[0],
|
|
@@ -65,7 +64,7 @@ var Toolbar = function Toolbar(props) {
|
|
|
65
64
|
return;
|
|
66
65
|
}
|
|
67
66
|
setScrollBtnLeft(barEl.scrollLeft > 0);
|
|
68
|
-
setScrollBtnRight(barEl.scrollLeft < barEl.scrollWidth - barEl.clientWidth);
|
|
67
|
+
setScrollBtnRight(Math.ceil(barEl.scrollLeft) < barEl.scrollWidth - barEl.clientWidth);
|
|
69
68
|
}, []);
|
|
70
69
|
|
|
71
70
|
// This is effectively a `useCallback` - it memoizes a function - but since we're feeding the whole function into
|
|
@@ -93,15 +92,30 @@ var Toolbar = function Toolbar(props) {
|
|
|
93
92
|
return leftRect.right > centerRect.left || centerRect.right > rightRect.left;
|
|
94
93
|
}
|
|
95
94
|
});
|
|
96
|
-
checkScrollBtnVisible
|
|
95
|
+
window.setTimeout(checkScrollBtnVisible, 0);
|
|
97
96
|
}, RESIZE_DEBOUNCE_DELAY);
|
|
98
97
|
}, [checkScrollBtnVisible]);
|
|
99
98
|
React.useEffect(function () {
|
|
100
99
|
// Make sure `checkSize` is run once on mount
|
|
101
100
|
checkSize();
|
|
101
|
+
if (resizeObserver.current !== undefined) {
|
|
102
|
+
resizeObserver.current.disconnect();
|
|
103
|
+
}
|
|
104
|
+
resizeObserver.current = new ResizeObserver(checkSize);
|
|
105
|
+
if (leftRef.current !== null) {
|
|
106
|
+
resizeObserver.current.observe(leftRef.current);
|
|
107
|
+
}
|
|
108
|
+
if (centerRef.current !== null) {
|
|
109
|
+
resizeObserver.current.observe(centerRef.current);
|
|
110
|
+
}
|
|
111
|
+
if (rightRef.current !== null) {
|
|
112
|
+
resizeObserver.current.observe(rightRef.current);
|
|
113
|
+
}
|
|
102
114
|
window.addEventListener("resize", checkSize);
|
|
103
115
|
return function () {
|
|
104
|
-
|
|
116
|
+
var _resizeObserver$curre;
|
|
117
|
+
(_resizeObserver$curre = resizeObserver.current) === null || _resizeObserver$curre === void 0 || _resizeObserver$curre.disconnect();
|
|
118
|
+
window.removeEventListener("resize", checkSize);
|
|
105
119
|
};
|
|
106
120
|
}, [checkSize]);
|
|
107
121
|
var scrollX = function scrollX(amount) {
|
|
@@ -126,7 +140,8 @@ var Toolbar = function Toolbar(props) {
|
|
|
126
140
|
var classForToggleBtn = function classForToggleBtn(active) {
|
|
127
141
|
return "ant-btn-icon-only btn-borderless" + (active ? " btn-active" : "");
|
|
128
142
|
};
|
|
129
|
-
var visibleControls = props.visibleControls
|
|
143
|
+
var visibleControls = props.visibleControls,
|
|
144
|
+
multiscaleDims = props.multiscaleDims;
|
|
130
145
|
var twoDMode = viewMode !== ViewMode.threeD;
|
|
131
146
|
var renderGroup1 = visibleControls.viewModeRadioButtons || visibleControls.resetCameraButton || visibleControls.autoRotateButton;
|
|
132
147
|
var renderGroup4 = visibleControls.showAxesButton || visibleControls.showBoundingBoxButton;
|
|
@@ -214,8 +229,9 @@ var Toolbar = function Toolbar(props) {
|
|
|
214
229
|
}, "Full field"))), /*#__PURE__*/React.createElement("div", {
|
|
215
230
|
className: "viewer-toolbar-group"
|
|
216
231
|
}, /*#__PURE__*/React.createElement(Select, {
|
|
217
|
-
|
|
218
|
-
|
|
232
|
+
style: {
|
|
233
|
+
minWidth: 120
|
|
234
|
+
},
|
|
219
235
|
value: renderMode,
|
|
220
236
|
onChange: function onChange(value) {
|
|
221
237
|
return changeViewerSetting("renderMode", value);
|
|
@@ -249,9 +265,13 @@ var Toolbar = function Toolbar(props) {
|
|
|
249
265
|
onClick: toggleBoundingBox
|
|
250
266
|
}, /*#__PURE__*/React.createElement(ViewerIcon, {
|
|
251
267
|
type: "boundingBox"
|
|
252
|
-
})))),
|
|
268
|
+
})))), multiscaleDims !== undefined && multiscaleDims.length > 1 && visibleControls.scaleLevelControls && /*#__PURE__*/React.createElement("div", {
|
|
253
269
|
className: "viewer-toolbar-group"
|
|
254
|
-
}, /*#__PURE__*/React.createElement("span",
|
|
270
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
271
|
+
style: {
|
|
272
|
+
color: "var(--color-button-tertiary-text)"
|
|
273
|
+
}
|
|
274
|
+
}, "Resolution"), /*#__PURE__*/React.createElement(Radio.Group, {
|
|
255
275
|
value: useExactScaleLevel,
|
|
256
276
|
onChange: function onChange(e) {
|
|
257
277
|
return changeViewerSetting("useExactScaleLevel", e.target.value);
|
|
@@ -261,7 +281,8 @@ var Toolbar = function Toolbar(props) {
|
|
|
261
281
|
}, "Auto"), /*#__PURE__*/React.createElement(Radio.Button, {
|
|
262
282
|
value: true
|
|
263
283
|
}, "Manual")), /*#__PURE__*/React.createElement(Select, {
|
|
264
|
-
className: "select-
|
|
284
|
+
className: "select-resolution",
|
|
285
|
+
getPopupContainer: getPopupContainer,
|
|
265
286
|
style: {
|
|
266
287
|
minWidth: 150
|
|
267
288
|
},
|
|
@@ -270,7 +291,7 @@ var Toolbar = function Toolbar(props) {
|
|
|
270
291
|
return changeViewerSetting("scaleLevelIndex", value);
|
|
271
292
|
},
|
|
272
293
|
disabled: !useExactScaleLevel
|
|
273
|
-
},
|
|
294
|
+
}, multiscaleDims.map(function (dims, idx) {
|
|
274
295
|
var _dims$shape = _slicedToArray(dims.shape, 5),
|
|
275
296
|
_t = _dims$shape[0],
|
|
276
297
|
_c = _dims$shape[1],
|
|
@@ -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-
|
|
124
|
-
background-color:var(--color-button-icon-
|
|
125
|
-
border:1px solid var(--color-button-icon-
|
|
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
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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):
|
|
155
|
-
|
|
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-
|
|
159
|
-
|
|
143
|
+
.viewer-toolbar .ant-select.select-resolution > .ant-select-selector{
|
|
144
|
+
text-align:left;
|
|
160
145
|
}
|
|
161
146
|
|
|
162
|
-
.viewer-toolbar
|
|
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
|
|
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
|
-
}
|
|
@@ -110,6 +110,9 @@ var useVolume = function useVolume(scenePaths, options) {
|
|
|
110
110
|
setPlayingAxis(axis);
|
|
111
111
|
// prioritize prefetching along the playing axis
|
|
112
112
|
sceneLoader.setPrefetchPriority(axis ? [AXIS_TO_LOADER_PRIORITY[axis]] : []);
|
|
113
|
+
sceneLoader.updateFetchOptions({
|
|
114
|
+
onlyPriorityDirections: isPlaying
|
|
115
|
+
});
|
|
113
116
|
// sync multichannel loading so we don't show loaded channels one at a time
|
|
114
117
|
sceneLoader.syncMultichannelLoading(isPlaying);
|
|
115
118
|
if (image) {
|
|
@@ -31,7 +31,7 @@ export var TFEDITOR_DEFAULT_COLOR = [255, 255, 255];
|
|
|
31
31
|
export var TFEDITOR_MAX_BIN = 255;
|
|
32
32
|
export var CACHE_MAX_SIZE = 1000000000;
|
|
33
33
|
export var QUEUE_MAX_SIZE = 10;
|
|
34
|
-
export var QUEUE_MAX_LOW_PRIORITY_SIZE =
|
|
34
|
+
export var QUEUE_MAX_LOW_PRIORITY_SIZE = 6;
|
|
35
35
|
|
|
36
36
|
/** Maps an axis the user can "play" through to the direction to prefetch while playing that axis */
|
|
37
37
|
export var AXIS_TO_LOADER_PRIORITY = {
|
|
@@ -13,6 +13,7 @@ var PlayControls = /*#__PURE__*/function () {
|
|
|
13
13
|
_defineProperty(this, "playWaitingForLoad", false);
|
|
14
14
|
_defineProperty(this, "playHolding", false);
|
|
15
15
|
_defineProperty(this, "playTimeoutId", 0);
|
|
16
|
+
_defineProperty(this, "lastStepTime", 0);
|
|
16
17
|
}
|
|
17
18
|
return _createClass(PlayControls, [{
|
|
18
19
|
key: "setPlayingAxis",
|
|
@@ -28,11 +29,18 @@ var PlayControls = /*#__PURE__*/function () {
|
|
|
28
29
|
if (!this.playingAxis || this.playHolding || !this.stepAxis) {
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
|
-
// If the volume is not loaded, wait for it to load before continuing
|
|
32
32
|
if (!((_this$getVolumeIsLoad = this.getVolumeIsLoaded) !== null && _this$getVolumeIsLoad !== void 0 && _this$getVolumeIsLoad.call(this))) {
|
|
33
33
|
this.playWaitingForLoad = true;
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
// Enforce minimum interval between frame *presentations* (not requests).
|
|
38
|
+
// lastStepTime is set in onImageLoaded when a frame's data arrives.
|
|
39
|
+
var delay = PLAY_STEP_INTERVAL_MS - (performance.now() - this.lastStepTime);
|
|
40
|
+
if (delay > 0) {
|
|
41
|
+
this.playTimeoutId = window.setTimeout(this.playStep.bind(this), delay);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
36
44
|
this.stepAxis(this.playingAxis);
|
|
37
45
|
this.playTimeoutId = window.setTimeout(this.playStep.bind(this), PLAY_STEP_INTERVAL_MS);
|
|
38
46
|
}
|
|
@@ -41,6 +49,9 @@ var PlayControls = /*#__PURE__*/function () {
|
|
|
41
49
|
}, {
|
|
42
50
|
key: "onImageLoaded",
|
|
43
51
|
value: function onImageLoaded() {
|
|
52
|
+
// Record when the frame was presented, so scheduleNextStep enforces
|
|
53
|
+
// PLAY_STEP_INTERVAL_MS between presentations (not between requests).
|
|
54
|
+
this.lastStepTime = performance.now();
|
|
44
55
|
if (this.playWaitingForLoad) {
|
|
45
56
|
this.playWaitingForLoad = false;
|
|
46
57
|
this.playStep();
|
|
@@ -158,6 +158,14 @@ var SceneStore = /*#__PURE__*/function () {
|
|
|
158
158
|
currentLoader.setPrefetchPriority(priority);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
+
}, {
|
|
162
|
+
key: "updateFetchOptions",
|
|
163
|
+
value: function updateFetchOptions(fetchOptions) {
|
|
164
|
+
var currentLoader = this.loaders[this.currentScene];
|
|
165
|
+
if (currentLoader) {
|
|
166
|
+
currentLoader.updateFetchOptions(fetchOptions);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
161
169
|
}]);
|
|
162
170
|
}();
|
|
163
171
|
export { SceneStore as default };
|
|
@@ -87,12 +87,11 @@ export function findFirstChannelMatch(channel, channelIndex, settings) {
|
|
|
87
87
|
}
|
|
88
88
|
export function getDisplayName(name, index, settings) {
|
|
89
89
|
if (settings) {
|
|
90
|
+
var _c$name;
|
|
90
91
|
var c = findFirstChannelMatch(name, index, settings);
|
|
91
|
-
|
|
92
|
-
return c.name || name;
|
|
93
|
-
}
|
|
92
|
+
return (_c$name = c === null || c === void 0 ? void 0 : c.name) !== null && _c$name !== void 0 ? _c$name : name;
|
|
94
93
|
}
|
|
95
|
-
return name;
|
|
94
|
+
return name !== null && name !== void 0 ? name : index.toString();
|
|
96
95
|
}
|
|
97
96
|
export function makeChannelIndexGrouping(channels, settings) {
|
|
98
97
|
if (!channels) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aics/vole-app",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "web view of cell volume images",
|
|
5
5
|
"main": "es/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"gh-build-nightly": "webpack --config webpack.dev.js --env env=production basename=/vole-app/",
|
|
26
26
|
"gh-build-release": "webpack --config webpack.dev.js --env env=production basename=/website-3d-cell-viewer-release/",
|
|
27
27
|
"s3-build": "webpack --config webpack.dev.js --env env=production",
|
|
28
|
+
"release-build": "webpack --config webpack.dev.js --env env=production",
|
|
28
29
|
"docker-build": "webpack --config webpack.common.js --env env=production",
|
|
29
30
|
"dev": "webpack --config webpack.dev.js --env env=dev",
|
|
30
31
|
"lint": "eslint --config ./.eslintrc --ignore-path ./.eslintignore --ext .jsx --ext .js --ext .ts --ext .tsx ./",
|
|
@@ -43,9 +44,9 @@
|
|
|
43
44
|
"checks": "npm run lint && npm run typeCheck && npm run test"
|
|
44
45
|
},
|
|
45
46
|
"author": "Megan Riel-Mehan",
|
|
46
|
-
"license": "
|
|
47
|
+
"license": "BSD-3-Clause",
|
|
47
48
|
"dependencies": {
|
|
48
|
-
"@aics/vole-core": "^4.
|
|
49
|
+
"@aics/vole-core": "^4.9.1",
|
|
49
50
|
"@ant-design/icons": "^5.2.5",
|
|
50
51
|
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
|
51
52
|
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
|
@@ -65,8 +66,7 @@
|
|
|
65
66
|
"peerDependencies": {
|
|
66
67
|
"antd": "^5.16.2",
|
|
67
68
|
"react": "18.x",
|
|
68
|
-
"react-dom": "18.x"
|
|
69
|
-
"three": "^0.171.0"
|
|
69
|
+
"react-dom": "18.x"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@babel/cli": "^7.14.5",
|
|
@@ -5,7 +5,7 @@ import type { ViewerChannelSettings } from "../../shared/utils/viewerChannelSett
|
|
|
5
5
|
import type { ViewerState } from "../../state/types";
|
|
6
6
|
/** `typeof useEffect`, but the effect handler takes a `Volume` as an argument */
|
|
7
7
|
export type UseImageEffectType = (effect: (image: Volume) => void | (() => void), deps: React.DependencyList) => void;
|
|
8
|
-
type ControlNames = "alphaMaskSlider" | "autoRotateButton" | "axisClipSliders" | "brightnessSlider" | "backgroundColorPicker" | "boundingBoxColorPicker" | "colorPresetsDropdown" | "densitySlider" | "levelsSliders" | "interpolationControl" | "saveSurfaceButtons" | "fovCellSwitchControls" | "viewModeRadioButtons" | "resetCameraButton" | "showAxesButton" | "showBoundingBoxButton" | "metadataViewer";
|
|
8
|
+
type ControlNames = "alphaMaskSlider" | "autoRotateButton" | "axisClipSliders" | "brightnessSlider" | "backgroundColorPicker" | "boundingBoxColorPicker" | "colorPresetsDropdown" | "densitySlider" | "levelsSliders" | "interpolationControl" | "saveSurfaceButtons" | "fovCellSwitchControls" | "viewModeRadioButtons" | "resetCameraButton" | "showAxesButton" | "showBoundingBoxButton" | "metadataViewer" | "scaleLevelControls";
|
|
9
9
|
/** Show/hide different elements of the UI */
|
|
10
10
|
export type ControlVisibilityFlags = {
|
|
11
11
|
[K in ControlNames]: boolean;
|
|
@@ -41,7 +41,7 @@ export interface AppProps {
|
|
|
41
41
|
view3dRef?: MutableRefObject<View3d | null>;
|
|
42
42
|
metadataFormatter?: (metadata: MetadataRecord) => MetadataRecord;
|
|
43
43
|
onControlPanelToggle?: (collapsed: boolean) => void;
|
|
44
|
-
showError?: (error:
|
|
44
|
+
showError?: (error: unknown, image?: Volume) => void;
|
|
45
45
|
onImageTitleChange?: (title: string | undefined) => void;
|
|
46
46
|
}
|
|
47
47
|
export {};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { MetadataRecord } from "../../shared/types";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { type ChannelsWidgetProps } from "../ChannelsWidget";
|
|
4
|
+
import { type CustomizeWidgetProps } from "../CustomizeWidget";
|
|
5
|
+
import { type GlobalVolumeControlsProps } from "../GlobalVolumeControls";
|
|
6
6
|
import "./styles.css";
|
|
7
|
-
|
|
8
|
-
interface ControlPanelProps extends PropsOf<typeof ChannelsWidget>, PropsOf<typeof GlobalVolumeControls>, PropsOf<typeof CustomizeWidget> {
|
|
7
|
+
interface ControlPanelProps extends ChannelsWidgetProps, GlobalVolumeControlsProps, CustomizeWidgetProps {
|
|
9
8
|
hasImage: boolean;
|
|
10
9
|
visibleControls: GlobalVolumeControlsProps["visibleControls"] & CustomizeWidgetProps["visibleControls"] & {
|
|
11
10
|
colorPresetsDropdown: boolean;
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import { type Volume } from "@aics/vole-core";
|
|
1
2
|
import React from "react";
|
|
2
3
|
import "./styles.css";
|
|
3
4
|
export type ErrorAlertDescription = {
|
|
4
5
|
title: string;
|
|
5
6
|
description: React.ReactNode;
|
|
6
7
|
};
|
|
8
|
+
type ErrorInfo = {
|
|
9
|
+
error: unknown;
|
|
10
|
+
count: number;
|
|
11
|
+
dims?: [number, number, number, number, number];
|
|
12
|
+
};
|
|
7
13
|
export type ErrorAlertProps = {
|
|
8
|
-
errors:
|
|
9
|
-
/** The number of times we've seen an error of the type that is currently being displayed before */
|
|
10
|
-
firstErrorCount?: number;
|
|
14
|
+
errors: ErrorInfo[];
|
|
11
15
|
afterClose?: () => void;
|
|
12
|
-
onSkipError?: () => void;
|
|
13
16
|
};
|
|
14
17
|
declare const ErrorAlert: React.FC<ErrorAlertProps>;
|
|
15
|
-
export declare const useErrorAlert: () => [React.ReactNode, (error: unknown) => void];
|
|
18
|
+
export declare const useErrorAlert: () => [React.ReactNode, (error: unknown, image?: Volume) => void];
|
|
16
19
|
export default ErrorAlert;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { VolumeDims } from "@aics/vole-core
|
|
1
|
+
import type { VolumeDims } from "@aics/vole-core";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import "./styles.css";
|
|
4
4
|
type ToolbarProps = {
|
|
@@ -19,6 +19,7 @@ type ToolbarProps = {
|
|
|
19
19
|
resetCameraButton: boolean;
|
|
20
20
|
showAxesButton: boolean;
|
|
21
21
|
showBoundingBoxButton: boolean;
|
|
22
|
+
scaleLevelControls: boolean;
|
|
22
23
|
};
|
|
23
24
|
};
|
|
24
25
|
declare const Toolbar: React.FC<ToolbarProps>;
|
|
@@ -11,7 +11,7 @@ export type UseVolumeOptions = {
|
|
|
11
11
|
/** Callback for when a single channel of the volume has loaded. */
|
|
12
12
|
onChannelLoaded?: (image: Volume, channelIndex: number, isInitialLoad: boolean) => void;
|
|
13
13
|
/** Callback for when image loading encounters an error. */
|
|
14
|
-
onError?: (error: unknown) => void;
|
|
14
|
+
onError?: (error: unknown, image?: Volume) => void;
|
|
15
15
|
/** The name of a channel which should be treated as a mask rather than as viewable data. */
|
|
16
16
|
maskChannelName?: string;
|
|
17
17
|
};
|
|
@@ -10,7 +10,7 @@ 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;
|
|
12
12
|
export declare const QUEUE_MAX_SIZE = 10;
|
|
13
|
-
export declare const QUEUE_MAX_LOW_PRIORITY_SIZE =
|
|
13
|
+
export declare const QUEUE_MAX_LOW_PRIORITY_SIZE = 6;
|
|
14
14
|
/** Maps an axis the user can "play" through to the direction to prefetch while playing that axis */
|
|
15
15
|
export declare const AXIS_TO_LOADER_PRIORITY: Record<AxisName | "t", PrefetchDirection>;
|
|
16
16
|
/** Maps channel data types to their minimum and maximum values */
|
|
@@ -5,6 +5,7 @@ export default class PlayControls {
|
|
|
5
5
|
playWaitingForLoad: boolean;
|
|
6
6
|
playHolding: boolean;
|
|
7
7
|
playTimeoutId: number;
|
|
8
|
+
private lastStepTime;
|
|
8
9
|
getVolumeIsLoaded?: () => boolean;
|
|
9
10
|
stepAxis?: (axis: PlayAxisName) => void;
|
|
10
11
|
onPlayingAxisChanged?: (axis: PlayAxisName | null) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LoadSpec, PrefetchDirection, RawArrayLoaderOptions, Volume, VolumeLoaderContext } from "@aics/vole-core";
|
|
1
|
+
import type { LoadSpec, PrefetchDirection, RawArrayLoaderOptions, Volume, VolumeLoaderContext, ZarrLoaderFetchOptions } from "@aics/vole-core";
|
|
2
2
|
import type { ThreadableVolumeLoader } from "@aics/vole-core/es/types/loaders/IVolumeLoader";
|
|
3
3
|
export type LoadSceneOptions = {
|
|
4
4
|
onCreateScene?: (volume: Volume, sceneIndex: number, loadSpec: LoadSpec) => void;
|
|
@@ -18,4 +18,5 @@ export default class SceneStore {
|
|
|
18
18
|
createVolume(scene: number, loadSpec: LoadSpec, onChannelLoaded?: (volume: Volume, channelIndex: number) => void): Promise<Volume>;
|
|
19
19
|
syncMultichannelLoading(sync: boolean): void;
|
|
20
20
|
setPrefetchPriority(priority: PrefetchDirection[]): void;
|
|
21
|
+
updateFetchOptions(fetchOptions: Partial<ZarrLoaderFetchOptions>): void;
|
|
21
22
|
}
|
package/LICENSE.txt
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
Allen Institute Software License – This software license is the 2-clause BSD license
|
|
2
|
-
plus clause a third clause that prohibits redistribution for commercial purposes without further permission.
|
|
3
|
-
|
|
4
|
-
Copyright © 2017. Allen Institute. All rights reserved.
|
|
5
|
-
|
|
6
|
-
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
|
7
|
-
following conditions are met:
|
|
8
|
-
|
|
9
|
-
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
|
10
|
-
following disclaimer.
|
|
11
|
-
|
|
12
|
-
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
|
13
|
-
following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
14
|
-
|
|
15
|
-
3. Redistributions for commercial purposes are not permitted without the Allen Institute’s written permission.
|
|
16
|
-
For purposes of this license, commercial purposes is the incorporation of the Allen Institute's software into
|
|
17
|
-
anything for which you will charge fees or other compensation. Contact terms@alleninstitute.org for commercial
|
|
18
|
-
licensing opportunities.
|
|
19
|
-
|
|
20
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
21
|
-
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
23
|
-
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
25
|
-
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
26
|
-
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|