@aics/vole-app 2.11.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.
- package/LICENSE +33 -0
- package/LICENSE.txt +26 -0
- package/README.md +45 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.eot +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.js +2337 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.svg +604 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.ttf +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.woff +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-500.woff2 +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.eot +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.js +2336 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.svg +604 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.ttf +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.woff +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-700.woff2 +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.eot +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.js +2337 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.svg +604 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.ttf +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.woff +0 -0
- package/es/aics-image-viewer/assets/fonts/open-sans/open-sans-regular.woff2 +0 -0
- package/es/aics-image-viewer/assets/icons/axes.js +20 -0
- package/es/aics-image-viewer/assets/icons/boundingBox.js +18 -0
- package/es/aics-image-viewer/assets/icons/camera.js +15 -0
- package/es/aics-image-viewer/assets/icons/channels.js +15 -0
- package/es/aics-image-viewer/assets/icons/closePanel.js +18 -0
- package/es/aics-image-viewer/assets/icons/download.js +17 -0
- package/es/aics-image-viewer/assets/icons/dropdownArrow.js +15 -0
- package/es/aics-image-viewer/assets/icons/index.js +24 -0
- package/es/aics-image-viewer/assets/icons/metadata.js +15 -0
- package/es/aics-image-viewer/assets/icons/preferences.js +15 -0
- package/es/aics-image-viewer/assets/icons/resetView.js +16 -0
- package/es/aics-image-viewer/assets/icons/svg.d.js +0 -0
- package/es/aics-image-viewer/assets/icons/turnTable.js +18 -0
- package/es/aics-image-viewer/assets/styles/animatedEllipsis.css +21 -0
- package/es/aics-image-viewer/assets/styles/globals.css +35 -0
- package/es/aics-image-viewer/assets/styles/noui-slider-override.css +1 -0
- package/es/aics-image-viewer/assets/styles/variables.css +1 -0
- package/es/aics-image-viewer/components/App/ChannelUpdater.js +96 -0
- package/es/aics-image-viewer/components/App/index.js +849 -0
- package/es/aics-image-viewer/components/App/styles.css +60 -0
- package/es/aics-image-viewer/components/App/types.js +1 -0
- package/es/aics-image-viewer/components/AxisClipSliders/index.js +285 -0
- package/es/aics-image-viewer/components/AxisClipSliders/styles.css +257 -0
- package/es/aics-image-viewer/components/BottomPanel/index.js +70 -0
- package/es/aics-image-viewer/components/BottomPanel/styles.css +85 -0
- package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +113 -0
- package/es/aics-image-viewer/components/CellViewerCanvasWrapper/styles.css +12 -0
- package/es/aics-image-viewer/components/ChannelsWidget.js +100 -0
- package/es/aics-image-viewer/components/ChannelsWidgetRow/index.js +158 -0
- package/es/aics-image-viewer/components/ChannelsWidgetRow/styles.css +38 -0
- package/es/aics-image-viewer/components/ColorPicker.js +120 -0
- package/es/aics-image-viewer/components/ControlPanel/index.js +180 -0
- package/es/aics-image-viewer/components/ControlPanel/styles.css +169 -0
- package/es/aics-image-viewer/components/CustomizeWidget.js +46 -0
- package/es/aics-image-viewer/components/ErrorAlert/index.js +144 -0
- package/es/aics-image-viewer/components/ErrorAlert/styles.css +22 -0
- package/es/aics-image-viewer/components/GlobalVolumeControls.js +38 -0
- package/es/aics-image-viewer/components/MetadataViewer/index.js +99 -0
- package/es/aics-image-viewer/components/MetadataViewer/styles.css +81 -0
- package/es/aics-image-viewer/components/StyleProvider/index.js +210 -0
- package/es/aics-image-viewer/components/TfEditor/index.js +584 -0
- package/es/aics-image-viewer/components/TfEditor/styles.css +88 -0
- package/es/aics-image-viewer/components/Toolbar/DownloadButton.js +55 -0
- package/es/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.js +22 -0
- package/es/aics-image-viewer/components/Toolbar/index.js +274 -0
- package/es/aics-image-viewer/components/Toolbar/styles.css +241 -0
- package/es/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.js +160 -0
- package/es/aics-image-viewer/components/ViewerStateProvider/index.js +261 -0
- package/es/aics-image-viewer/components/ViewerStateProvider/types.js +1 -0
- package/es/aics-image-viewer/components/shared/NumericInput/index.js +147 -0
- package/es/aics-image-viewer/components/shared/NumericInput/styles.css +64 -0
- package/es/aics-image-viewer/components/shared/SharedCheckBox.js +17 -0
- package/es/aics-image-viewer/components/shared/SliderRow/index.js +31 -0
- package/es/aics-image-viewer/components/shared/SliderRow/styles.css +19 -0
- package/es/aics-image-viewer/components/shared/SmarterSlider.js +40 -0
- package/es/aics-image-viewer/components/shared/ViewerIcon.js +22 -0
- package/es/aics-image-viewer/shared/colorPalette.js +19 -0
- package/es/aics-image-viewer/shared/constants.js +164 -0
- package/es/aics-image-viewer/shared/enums.js +18 -0
- package/es/aics-image-viewer/shared/types.js +6 -0
- package/es/aics-image-viewer/shared/utils/colorRepresentations.js +16 -0
- package/es/aics-image-viewer/shared/utils/controlPointsToLut.js +182 -0
- package/es/aics-image-viewer/shared/utils/hooks.js +51 -0
- package/es/aics-image-viewer/shared/utils/httpClient.js +57 -0
- package/es/aics-image-viewer/shared/utils/playControls.js +97 -0
- package/es/aics-image-viewer/shared/utils/sceneStore.js +140 -0
- package/es/aics-image-viewer/shared/utils/sliderValuesToImageValues.js +36 -0
- package/es/aics-image-viewer/shared/utils/test/viewerChannelSettings.test.js +132 -0
- package/es/aics-image-viewer/shared/utils/utilsService.js +54 -0
- package/es/aics-image-viewer/shared/utils/viewerChannelSettings.js +152 -0
- package/es/aics-image-viewer/shared/utils/viewerState.js +69 -0
- package/es/aics-image-viewer/shared/utils/webgl-debug.js +1103 -0
- package/es/index.js +4 -0
- package/package.json +130 -0
- package/type-declarations/aics-image-viewer/assets/icons/index.d.ts +14 -0
- package/type-declarations/aics-image-viewer/components/App/ChannelUpdater.d.ts +16 -0
- package/type-declarations/aics-image-viewer/components/App/index.d.ts +6 -0
- package/type-declarations/aics-image-viewer/components/App/types.d.ts +45 -0
- package/type-declarations/aics-image-viewer/components/AxisClipSliders/index.d.ts +24 -0
- package/type-declarations/aics-image-viewer/components/BottomPanel/index.d.ts +11 -0
- package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +33 -0
- package/type-declarations/aics-image-viewer/components/ChannelsWidget.d.ts +19 -0
- package/type-declarations/aics-image-viewer/components/ChannelsWidgetRow/index.d.ts +17 -0
- package/type-declarations/aics-image-viewer/components/ColorPicker.d.ts +13 -0
- package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +20 -0
- package/type-declarations/aics-image-viewer/components/CustomizeWidget.d.ts +15 -0
- package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +12 -0
- package/type-declarations/aics-image-viewer/components/GlobalVolumeControls.d.ts +21 -0
- package/type-declarations/aics-image-viewer/components/MetadataViewer/index.d.ts +7 -0
- package/type-declarations/aics-image-viewer/components/StyleProvider/index.d.ts +5 -0
- package/type-declarations/aics-image-viewer/components/TfEditor/index.d.ts +19 -0
- package/type-declarations/aics-image-viewer/components/Toolbar/DownloadButton.d.ts +8 -0
- package/type-declarations/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.d.ts +8 -0
- package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +31 -0
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.d.ts +34 -0
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/index.d.ts +33 -0
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/types.d.ts +105 -0
- package/type-declarations/aics-image-viewer/components/shared/NumericInput/index.d.ts +19 -0
- package/type-declarations/aics-image-viewer/components/shared/SharedCheckBox.d.ts +9 -0
- package/type-declarations/aics-image-viewer/components/shared/SliderRow/index.d.ts +17 -0
- package/type-declarations/aics-image-viewer/components/shared/SmarterSlider.d.ts +5 -0
- package/type-declarations/aics-image-viewer/components/shared/ViewerIcon.d.ts +9 -0
- package/type-declarations/aics-image-viewer/shared/constants.d.ts +40 -0
- package/type-declarations/aics-image-viewer/shared/enums.d.ts +15 -0
- package/type-declarations/aics-image-viewer/shared/types.d.ts +15 -0
- package/type-declarations/aics-image-viewer/shared/utils/colorRepresentations.d.ts +10 -0
- package/type-declarations/aics-image-viewer/shared/utils/controlPointsToLut.d.ts +53 -0
- package/type-declarations/aics-image-viewer/shared/utils/hooks.d.ts +14 -0
- package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +27 -0
- package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +17 -0
- package/type-declarations/aics-image-viewer/shared/utils/sliderValuesToImageValues.d.ts +10 -0
- package/type-declarations/aics-image-viewer/shared/utils/viewerChannelSettings.d.ts +46 -0
- package/type-declarations/aics-image-viewer/shared/utils/viewerState.d.ts +10 -0
- package/type-declarations/index.d.ts +7 -0
|
@@ -0,0 +1,849 @@
|
|
|
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 _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
3
|
+
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."); }
|
|
4
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
5
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
6
|
+
function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
|
|
7
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
8
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
9
|
+
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; }
|
|
10
|
+
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; }
|
|
11
|
+
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; }
|
|
12
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
13
|
+
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); }
|
|
14
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
15
|
+
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."); }
|
|
16
|
+
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; } }
|
|
17
|
+
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; }
|
|
18
|
+
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; } }
|
|
19
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
20
|
+
// 3rd Party Imports
|
|
21
|
+
import { LoadSpec, PrefetchDirection, RENDERMODE_PATHTRACE, RENDERMODE_RAYMARCH, View3d, VolumeFileFormat, VolumeLoaderContext } from "@aics/vole-core";
|
|
22
|
+
import { Layout } from "antd";
|
|
23
|
+
import { debounce, isEqual } from "lodash";
|
|
24
|
+
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
25
|
+
import { Box3, Vector3 } from "three";
|
|
26
|
+
import { AXIS_MARGIN_DEFAULT, CACHE_MAX_SIZE, CLIPPING_PANEL_HEIGHT_DEFAULT, CLIPPING_PANEL_HEIGHT_TALL, CONTROL_PANEL_CLOSE_WIDTH, getDefaultChannelColor, getDefaultViewerState, QUEUE_MAX_LOW_PRIORITY_SIZE, QUEUE_MAX_SIZE, SCALE_BAR_MARGIN_DEFAULT } from "../../shared/constants";
|
|
27
|
+
import { ImageType, RenderMode, ViewMode } from "../../shared/enums";
|
|
28
|
+
import { activeAxisMap } from "../../shared/types";
|
|
29
|
+
import { colorArrayToFloats } from "../../shared/utils/colorRepresentations";
|
|
30
|
+
import { controlPointsToRamp, initializeLut, rampToControlPoints, remapControlPointsForChannel } from "../../shared/utils/controlPointsToLut";
|
|
31
|
+
import { useConstructor, useStateWithGetter } from "../../shared/utils/hooks";
|
|
32
|
+
import PlayControls from "../../shared/utils/playControls";
|
|
33
|
+
import SceneStore from "../../shared/utils/sceneStore";
|
|
34
|
+
import { alphaSliderToImageValue, brightnessSliderToImageValue, densitySliderToImageValue, gammaSliderToImageValues } from "../../shared/utils/sliderValuesToImageValues";
|
|
35
|
+
import { getDisplayName, makeChannelIndexGrouping } from "../../shared/utils/viewerChannelSettings";
|
|
36
|
+
import { initializeOneChannelSetting } from "../../shared/utils/viewerState";
|
|
37
|
+
import CellViewerCanvasWrapper from "../CellViewerCanvasWrapper";
|
|
38
|
+
import ControlPanel from "../ControlPanel";
|
|
39
|
+
import { useErrorAlert } from "../ErrorAlert";
|
|
40
|
+
import StyleProvider from "../StyleProvider";
|
|
41
|
+
import Toolbar from "../Toolbar";
|
|
42
|
+
import { ViewerStateContext } from "../ViewerStateProvider";
|
|
43
|
+
import ChannelUpdater from "./ChannelUpdater";
|
|
44
|
+
import "../../assets/styles/globals.css";
|
|
45
|
+
import "./styles.css";
|
|
46
|
+
var Sider = Layout.Sider,
|
|
47
|
+
Content = Layout.Content;
|
|
48
|
+
var defaultVisibleControls = {
|
|
49
|
+
alphaMaskSlider: true,
|
|
50
|
+
autoRotateButton: true,
|
|
51
|
+
axisClipSliders: true,
|
|
52
|
+
brightnessSlider: true,
|
|
53
|
+
backgroundColorPicker: true,
|
|
54
|
+
boundingBoxColorPicker: true,
|
|
55
|
+
colorPresetsDropdown: true,
|
|
56
|
+
densitySlider: true,
|
|
57
|
+
levelsSliders: true,
|
|
58
|
+
interpolationControl: true,
|
|
59
|
+
saveSurfaceButtons: true,
|
|
60
|
+
fovCellSwitchControls: true,
|
|
61
|
+
viewModeRadioButtons: true,
|
|
62
|
+
resetCameraButton: true,
|
|
63
|
+
showAxesButton: true,
|
|
64
|
+
showBoundingBoxButton: true,
|
|
65
|
+
metadataViewer: true
|
|
66
|
+
};
|
|
67
|
+
var defaultProps = {
|
|
68
|
+
// rawData has a "dtype" which is expected to be "uint8", a "shape":[c,z,y,x] and a "buffer" which is a DataView
|
|
69
|
+
rawData: undefined,
|
|
70
|
+
// rawDims is the volume dims that normally come from a json file
|
|
71
|
+
rawDims: undefined,
|
|
72
|
+
imageUrl: "",
|
|
73
|
+
parentImageUrl: "",
|
|
74
|
+
appHeight: "100vh",
|
|
75
|
+
visibleControls: defaultVisibleControls,
|
|
76
|
+
viewerSettings: getDefaultViewerState(),
|
|
77
|
+
cellId: "",
|
|
78
|
+
imageDownloadHref: "",
|
|
79
|
+
parentImageDownloadHref: "",
|
|
80
|
+
pixelSize: undefined,
|
|
81
|
+
canvasMargin: "0 0 0 0",
|
|
82
|
+
view3dRef: undefined
|
|
83
|
+
};
|
|
84
|
+
var axisToLoaderPriority = {
|
|
85
|
+
t: PrefetchDirection.T_PLUS,
|
|
86
|
+
z: PrefetchDirection.Z_PLUS,
|
|
87
|
+
y: PrefetchDirection.Y_PLUS,
|
|
88
|
+
x: PrefetchDirection.X_PLUS
|
|
89
|
+
};
|
|
90
|
+
var setIndicatorPositions = function setIndicatorPositions(view3d, panelOpen, hasTime, hasScenes, isMode3d) {
|
|
91
|
+
// The height of the clipping panel includes the button, but we're trying to put these elements next to the button
|
|
92
|
+
var CLIPPING_PANEL_BUTTON_HEIGHT = 40;
|
|
93
|
+
// Move scale bars this far to the left when showing time series, to make room for timestep indicator
|
|
94
|
+
var SCALE_BAR_TIME_SERIES_OFFSET = 120;
|
|
95
|
+
var axisY = AXIS_MARGIN_DEFAULT[1];
|
|
96
|
+
var _SCALE_BAR_MARGIN_DEF = _slicedToArray(SCALE_BAR_MARGIN_DEFAULT, 2),
|
|
97
|
+
scaleBarX = _SCALE_BAR_MARGIN_DEF[0],
|
|
98
|
+
scaleBarY = _SCALE_BAR_MARGIN_DEF[1];
|
|
99
|
+
if (panelOpen) {
|
|
100
|
+
// If we have Time, Scene, X, Y, and Z sliders, the drawer will need to be a bit taller
|
|
101
|
+
var isTall = hasTime && hasScenes && isMode3d;
|
|
102
|
+
var clippingPanelFullHeight = isTall ? CLIPPING_PANEL_HEIGHT_TALL : CLIPPING_PANEL_HEIGHT_DEFAULT;
|
|
103
|
+
var clippingPanelHeight = clippingPanelFullHeight - CLIPPING_PANEL_BUTTON_HEIGHT;
|
|
104
|
+
// Move indicators up out of the way of the clipping panel
|
|
105
|
+
axisY += clippingPanelHeight;
|
|
106
|
+
scaleBarY += clippingPanelHeight;
|
|
107
|
+
}
|
|
108
|
+
if (hasTime) {
|
|
109
|
+
// Move scale bar left out of the way of timestep indicator
|
|
110
|
+
scaleBarX += SCALE_BAR_TIME_SERIES_OFFSET;
|
|
111
|
+
// Make sure the timestep indicator is showing
|
|
112
|
+
view3d.setShowTimestepIndicator(true);
|
|
113
|
+
}
|
|
114
|
+
view3d.setAxisPosition(AXIS_MARGIN_DEFAULT[0], axisY);
|
|
115
|
+
view3d.setTimestepIndicatorPosition(SCALE_BAR_MARGIN_DEFAULT[0], scaleBarY);
|
|
116
|
+
view3d.setScaleBarPosition(scaleBarX, scaleBarY);
|
|
117
|
+
};
|
|
118
|
+
var App = function App(props) {
|
|
119
|
+
var _scenes$length, _scenes, _image$imageInfo$volu, _image$imageInfo$subr, _image$imageInfo$time, _props$transform2, _props$transform4;
|
|
120
|
+
props = _objectSpread(_objectSpread({}, defaultProps), props);
|
|
121
|
+
|
|
122
|
+
// State management /////////////////////////////////////////////////////////
|
|
123
|
+
var viewerState = useContext(ViewerStateContext).ref;
|
|
124
|
+
var _viewerState$current = viewerState.current,
|
|
125
|
+
channelSettings = _viewerState$current.channelSettings,
|
|
126
|
+
setChannelSettings = _viewerState$current.setChannelSettings,
|
|
127
|
+
changeViewerSetting = _viewerState$current.changeViewerSetting,
|
|
128
|
+
changeChannelSetting = _viewerState$current.changeChannelSetting,
|
|
129
|
+
applyColorPresets = _viewerState$current.applyColorPresets,
|
|
130
|
+
setSavedViewerChannelSettings = _viewerState$current.setSavedViewerChannelSettings,
|
|
131
|
+
getCurrentViewerChannelSettings = _viewerState$current.getCurrentViewerChannelSettings,
|
|
132
|
+
getChannelsAwaitingReset = _viewerState$current.getChannelsAwaitingReset,
|
|
133
|
+
getChannelsAwaitingResetOnLoad = _viewerState$current.getChannelsAwaitingResetOnLoad,
|
|
134
|
+
onResetChannel = _viewerState$current.onResetChannel;
|
|
135
|
+
useMemo(function () {
|
|
136
|
+
if (props.viewerChannelSettings) {
|
|
137
|
+
setSavedViewerChannelSettings(props.viewerChannelSettings);
|
|
138
|
+
}
|
|
139
|
+
}, [props.viewerChannelSettings]);
|
|
140
|
+
var view3d = useConstructor(function () {
|
|
141
|
+
return new View3d();
|
|
142
|
+
});
|
|
143
|
+
if (props.view3dRef !== undefined) {
|
|
144
|
+
props.view3dRef.current = view3d;
|
|
145
|
+
}
|
|
146
|
+
var loadContext = useConstructor(function () {
|
|
147
|
+
return new VolumeLoaderContext(CACHE_MAX_SIZE, QUEUE_MAX_SIZE, QUEUE_MAX_LOW_PRIORITY_SIZE);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// install loadContext into view3d
|
|
151
|
+
view3d.loaderContext = loadContext;
|
|
152
|
+
var loader = useRef();
|
|
153
|
+
var _useState = useState(null),
|
|
154
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
155
|
+
image = _useState2[0],
|
|
156
|
+
setImage = _useState2[1];
|
|
157
|
+
var imageUrlRef = useRef("");
|
|
158
|
+
var _useErrorAlert = useErrorAlert(),
|
|
159
|
+
_useErrorAlert2 = _slicedToArray(_useErrorAlert, 2),
|
|
160
|
+
errorAlert = _useErrorAlert2[0],
|
|
161
|
+
_showError = _useErrorAlert2[1];
|
|
162
|
+
var showError = function showError(error) {
|
|
163
|
+
_showError(error);
|
|
164
|
+
setSendingQueryRequest(false);
|
|
165
|
+
};
|
|
166
|
+
useEffect(function () {
|
|
167
|
+
// Get notifications of loading errors which occur after the initial load, e.g. on time change or new channel load
|
|
168
|
+
view3d.setLoadErrorHandler(function (_vol, e) {
|
|
169
|
+
return showError(e);
|
|
170
|
+
});
|
|
171
|
+
return function () {
|
|
172
|
+
return view3d.setLoadErrorHandler(undefined);
|
|
173
|
+
};
|
|
174
|
+
}, [view3d]);
|
|
175
|
+
var hasRawImage = !!(props.rawData && props.rawDims);
|
|
176
|
+
var numScenes = hasRawImage ? 1 : (_scenes$length = (_scenes = props.imageUrl.scenes) === null || _scenes === void 0 ? void 0 : _scenes.length) !== null && _scenes$length !== void 0 ? _scenes$length : 1;
|
|
177
|
+
var numSlices = (_image$imageInfo$volu = image === null || image === void 0 ? void 0 : image.imageInfo.volumeSize) !== null && _image$imageInfo$volu !== void 0 ? _image$imageInfo$volu : {
|
|
178
|
+
x: 0,
|
|
179
|
+
y: 0,
|
|
180
|
+
z: 0
|
|
181
|
+
};
|
|
182
|
+
var numSlicesLoaded = (_image$imageInfo$subr = image === null || image === void 0 ? void 0 : image.imageInfo.subregionSize) !== null && _image$imageInfo$subr !== void 0 ? _image$imageInfo$subr : {
|
|
183
|
+
x: 0,
|
|
184
|
+
y: 0,
|
|
185
|
+
z: 0
|
|
186
|
+
};
|
|
187
|
+
var numTimesteps = (_image$imageInfo$time = image === null || image === void 0 ? void 0 : image.imageInfo.times) !== null && _image$imageInfo$time !== void 0 ? _image$imageInfo$time : 1;
|
|
188
|
+
|
|
189
|
+
// State for image loading/reloading
|
|
190
|
+
|
|
191
|
+
/** `true` when a channel's data has been loaded for the current image. */
|
|
192
|
+
var hasChannelLoadedRef = useRef([]);
|
|
193
|
+
// `true` when image data has been requested, but no data has been received yet
|
|
194
|
+
var _useState3 = useState(false),
|
|
195
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
196
|
+
sendingQueryRequest = _useState4[0],
|
|
197
|
+
setSendingQueryRequest = _useState4[1];
|
|
198
|
+
// `true` when all channels of the current image are loaded
|
|
199
|
+
var _useState5 = useState(false),
|
|
200
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
201
|
+
imageLoaded = _useState6[0],
|
|
202
|
+
setImageLoaded = _useState6[1];
|
|
203
|
+
// tracks which channels have been loaded
|
|
204
|
+
var _useStateWithGetter = useStateWithGetter([]),
|
|
205
|
+
_useStateWithGetter2 = _slicedToArray(_useStateWithGetter, 3),
|
|
206
|
+
channelVersions = _useStateWithGetter2[0],
|
|
207
|
+
setChannelVersions = _useStateWithGetter2[1],
|
|
208
|
+
getChannelVersions = _useStateWithGetter2[2];
|
|
209
|
+
// we need to keep track of channel ranges for remapping
|
|
210
|
+
var channelRangesRef = useRef([]);
|
|
211
|
+
var _useState7 = useState({}),
|
|
212
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
213
|
+
channelGroupedByType = _useState8[0],
|
|
214
|
+
setChannelGroupedByType = _useState8[1];
|
|
215
|
+
var _useState9 = useState(function () {
|
|
216
|
+
return window.innerWidth < CONTROL_PANEL_CLOSE_WIDTH;
|
|
217
|
+
}),
|
|
218
|
+
_useState10 = _slicedToArray(_useState9, 2),
|
|
219
|
+
controlPanelClosed = _useState10[0],
|
|
220
|
+
setControlPanelClosed = _useState10[1];
|
|
221
|
+
// Only allow auto-close once while the screen is too narrow.
|
|
222
|
+
var _useState11 = useState(false),
|
|
223
|
+
_useState12 = _slicedToArray(_useState11, 2),
|
|
224
|
+
hasAutoClosedControlPanel = _useState12[0],
|
|
225
|
+
setHasAutoClosedControlPanel = _useState12[1];
|
|
226
|
+
|
|
227
|
+
// Clipping panel state doesn't need to trigger renders on change, so it can go in a ref
|
|
228
|
+
var clippingPanelOpenRef = useRef(true);
|
|
229
|
+
|
|
230
|
+
// `PlayControls` manages playing through time and spatial axes, which isn't practical with "pure" React
|
|
231
|
+
// Playback state goes here, but the play/pause buttons that mainly control this class are down in `AxisClipSliders`
|
|
232
|
+
var playControls = useConstructor(function () {
|
|
233
|
+
return new PlayControls();
|
|
234
|
+
});
|
|
235
|
+
var _useState13 = useState(null),
|
|
236
|
+
_useState14 = _slicedToArray(_useState13, 2),
|
|
237
|
+
playingAxis = _useState14[0],
|
|
238
|
+
setPlayingAxis = _useState14[1];
|
|
239
|
+
playControls.onPlayingAxisChanged = function (axis) {
|
|
240
|
+
var _loader$current, _loader$current2;
|
|
241
|
+
(_loader$current = loader.current) === null || _loader$current === void 0 || _loader$current.setPrefetchPriority(axis ? [axisToLoaderPriority[axis]] : []);
|
|
242
|
+
(_loader$current2 = loader.current) === null || _loader$current2 === void 0 || _loader$current2.syncMultichannelLoading(axis ? true : false);
|
|
243
|
+
if (image) {
|
|
244
|
+
if (axis === null) {
|
|
245
|
+
// Playback has stopped - reset scale level bias
|
|
246
|
+
view3d.setScaleLevelBias(image, 0);
|
|
247
|
+
} else {
|
|
248
|
+
// Playback has started - unless entire axis is in memory (typical in X and Y), downlevel to speed things up
|
|
249
|
+
var shouldDownlevel = axis === "t" || numSlices[axis] !== numSlicesLoaded[axis];
|
|
250
|
+
view3d.setScaleLevelBias(image, shouldDownlevel ? 1 : 0);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
setPlayingAxis(axis);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// These last state functions are only ever used within this component - no need for a `useCallback`
|
|
257
|
+
|
|
258
|
+
var getOneChannelSetting = function getOneChannelSetting(channelName, settings) {
|
|
259
|
+
return (settings || viewerState.current.channelSettings).find(function (channel) {
|
|
260
|
+
return channel.name === channelName;
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
var setAllChannelsUnloaded = function setAllChannelsUnloaded(numberOfChannels) {
|
|
264
|
+
setChannelVersions(new Array(numberOfChannels).fill(0));
|
|
265
|
+
};
|
|
266
|
+
var setOneChannelLoaded = function setOneChannelLoaded(index) {
|
|
267
|
+
var newVersions = getChannelVersions().slice();
|
|
268
|
+
newVersions[index]++;
|
|
269
|
+
setChannelVersions(newVersions);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Image loading/initialization functions ///////////////////////////////////
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Updates a channel's ramp and control points after new data has been loaded.
|
|
276
|
+
*
|
|
277
|
+
* Also handles initializing the ramp/control points on initial load and resetting
|
|
278
|
+
* them when the channel is reset.
|
|
279
|
+
*/
|
|
280
|
+
var updateChannelTransferFunction = function updateChannelTransferFunction(aimg, thisChannelsSettings, channelIndex) {
|
|
281
|
+
var thisChannel = aimg.getChannel(channelIndex);
|
|
282
|
+
|
|
283
|
+
// If this is the first load of this image, auto-generate initial LUTs
|
|
284
|
+
if (!hasChannelLoadedRef.current[channelIndex] || !thisChannelsSettings.controlPoints || !thisChannelsSettings.ramp || getChannelsAwaitingResetOnLoad().has(channelIndex)) {
|
|
285
|
+
var viewerChannelSettings = getCurrentViewerChannelSettings();
|
|
286
|
+
var _initializeLut = initializeLut(aimg, channelIndex, viewerChannelSettings),
|
|
287
|
+
ramp = _initializeLut.ramp,
|
|
288
|
+
controlPoints = _initializeLut.controlPoints;
|
|
289
|
+
changeChannelSetting(channelIndex, {
|
|
290
|
+
controlPoints: controlPoints,
|
|
291
|
+
ramp: controlPointsToRamp(ramp)
|
|
292
|
+
});
|
|
293
|
+
onResetChannel(channelIndex);
|
|
294
|
+
} else {
|
|
295
|
+
// try not to update lut from here if we are in play mode
|
|
296
|
+
// if (playingAxis !== null) {
|
|
297
|
+
// do nothing here?
|
|
298
|
+
// tell gui that we have updated control pts?
|
|
299
|
+
//changeChannelSetting(channelIndex, "controlPoints", aimg.getChannel(channelIndex).lut.controlPoints);
|
|
300
|
+
// }
|
|
301
|
+
var oldRange = channelRangesRef.current[channelIndex];
|
|
302
|
+
if (thisChannelsSettings.useControlPoints) {
|
|
303
|
+
// control points were just automatically remapped - update in state
|
|
304
|
+
// now manually remap ramp using the channel's old range
|
|
305
|
+
var rampControlPoints = rampToControlPoints(thisChannelsSettings.ramp);
|
|
306
|
+
var remappedRampControlPoints = remapControlPointsForChannel(rampControlPoints, oldRange, thisChannel);
|
|
307
|
+
changeChannelSetting(channelIndex, {
|
|
308
|
+
ramp: controlPointsToRamp(remappedRampControlPoints),
|
|
309
|
+
controlPoints: thisChannel.lut.controlPoints
|
|
310
|
+
});
|
|
311
|
+
} else {
|
|
312
|
+
// ramp was just automatically remapped - update in state
|
|
313
|
+
var _ramp = controlPointsToRamp(thisChannel.lut.controlPoints);
|
|
314
|
+
// now manually remap control points using the channel's old range
|
|
315
|
+
var _controlPoints = thisChannelsSettings.controlPoints;
|
|
316
|
+
var remappedControlPoints = remapControlPointsForChannel(_controlPoints, oldRange, thisChannel);
|
|
317
|
+
changeChannelSetting(channelIndex, {
|
|
318
|
+
controlPoints: remappedControlPoints,
|
|
319
|
+
ramp: _ramp
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
var onChannelDataLoaded = function onChannelDataLoaded(aimg, thisChannelsSettings, channelIndex) {
|
|
325
|
+
var _getCurrentViewerChan;
|
|
326
|
+
var thisChannel = aimg.getChannel(channelIndex);
|
|
327
|
+
updateChannelTransferFunction(aimg, thisChannelsSettings, channelIndex);
|
|
328
|
+
|
|
329
|
+
// save the channel's new range for remapping next time
|
|
330
|
+
channelRangesRef.current[channelIndex] = [thisChannel.rawMin, thisChannel.rawMax];
|
|
331
|
+
view3d.updateLuts(aimg);
|
|
332
|
+
view3d.onVolumeData(aimg, [channelIndex]);
|
|
333
|
+
view3d.setVolumeChannelEnabled(aimg, channelIndex, thisChannelsSettings.volumeEnabled);
|
|
334
|
+
if (aimg.channelNames[channelIndex] === ((_getCurrentViewerChan = getCurrentViewerChannelSettings()) === null || _getCurrentViewerChan === void 0 ? void 0 : _getCurrentViewerChan.maskChannelName)) {
|
|
335
|
+
view3d.setVolumeChannelAsMask(aimg, channelIndex);
|
|
336
|
+
}
|
|
337
|
+
hasChannelLoadedRef.current[channelIndex] = true;
|
|
338
|
+
|
|
339
|
+
// when any channel data has arrived:
|
|
340
|
+
setSendingQueryRequest(false);
|
|
341
|
+
setOneChannelLoaded(channelIndex);
|
|
342
|
+
if (aimg.isLoaded()) {
|
|
343
|
+
view3d.updateActiveChannels(aimg);
|
|
344
|
+
setImageLoaded(true);
|
|
345
|
+
playControls.onImageLoaded();
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var setChannelStateForNewImage = function setChannelStateForNewImage(channelNames) {
|
|
349
|
+
var grouping = makeChannelIndexGrouping(channelNames, getCurrentViewerChannelSettings());
|
|
350
|
+
setChannelGroupedByType(grouping);
|
|
351
|
+
|
|
352
|
+
// compare each channel's new displayName to the old displayNames currently in state:
|
|
353
|
+
// same number of channels, and each channel has same displayName
|
|
354
|
+
var allNamesAreEqual = channelNames.every(function (name, idx) {
|
|
355
|
+
var _channelSettings$idx;
|
|
356
|
+
var displayName = getDisplayName(name, idx, getCurrentViewerChannelSettings());
|
|
357
|
+
return displayName === ((_channelSettings$idx = channelSettings[idx]) === null || _channelSettings$idx === void 0 ? void 0 : _channelSettings$idx.displayName);
|
|
358
|
+
});
|
|
359
|
+
if (allNamesAreEqual) {
|
|
360
|
+
var _newChannelSettings = channelNames.map(function (channel, index) {
|
|
361
|
+
return _objectSpread(_objectSpread({}, channelSettings[index]), {}, {
|
|
362
|
+
name: channel
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
setChannelSettings(_newChannelSettings);
|
|
366
|
+
return _newChannelSettings;
|
|
367
|
+
}
|
|
368
|
+
var newChannelSettings = channelNames.map(function (channel, index) {
|
|
369
|
+
var color = getDefaultChannelColor(index);
|
|
370
|
+
return initializeOneChannelSetting(channel, index, color, getCurrentViewerChannelSettings());
|
|
371
|
+
});
|
|
372
|
+
setChannelSettings(newChannelSettings);
|
|
373
|
+
return newChannelSettings;
|
|
374
|
+
};
|
|
375
|
+
var placeImageInViewer = function placeImageInViewer(aimg, newChannelSettings) {
|
|
376
|
+
setImage(aimg);
|
|
377
|
+
var channelSetting = newChannelSettings || channelSettings;
|
|
378
|
+
view3d.removeAllVolumes();
|
|
379
|
+
view3d.addVolume(aimg, {
|
|
380
|
+
// Immediately passing down channel parameters isn't strictly necessary, but keeps things looking consistent on load
|
|
381
|
+
channels: aimg.channelNames.map(function (name) {
|
|
382
|
+
var ch = getOneChannelSetting(name, channelSetting);
|
|
383
|
+
if (!ch) {
|
|
384
|
+
return {};
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
enabled: ch.volumeEnabled,
|
|
388
|
+
isosurfaceEnabled: ch.isosurfaceEnabled,
|
|
389
|
+
isovalue: ch.isovalue,
|
|
390
|
+
isosurfaceOpacity: ch.opacity,
|
|
391
|
+
color: ch.color
|
|
392
|
+
};
|
|
393
|
+
})
|
|
394
|
+
});
|
|
395
|
+
var mode3d = viewerSettings.viewMode === ViewMode.threeD;
|
|
396
|
+
setIndicatorPositions(view3d, clippingPanelOpenRef.current, aimg.imageInfo.times > 1, numScenes > 1, mode3d);
|
|
397
|
+
imageLoadHandlers.current.forEach(function (effect) {
|
|
398
|
+
return effect(aimg);
|
|
399
|
+
});
|
|
400
|
+
playControls.stepAxis = function (axis) {
|
|
401
|
+
if (axis === "t") {
|
|
402
|
+
changeViewerSetting("time", (viewerState.current.time + 1) % aimg.imageInfo.times);
|
|
403
|
+
} else {
|
|
404
|
+
var max = aimg.imageInfo.volumeSize[axis];
|
|
405
|
+
var current = viewerState.current.slice[axis] * max;
|
|
406
|
+
changeViewerSetting("slice", _objectSpread(_objectSpread({}, viewerState.current.slice), {}, _defineProperty({}, axis, (current + 1) % max / max)));
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
playControls.getVolumeIsLoaded = function () {
|
|
410
|
+
return aimg.isLoaded();
|
|
411
|
+
};
|
|
412
|
+
view3d.updateActiveChannels(aimg);
|
|
413
|
+
// make sure we pick up whether the image needs to be in single-slice mode
|
|
414
|
+
view3d.setCameraMode(viewerSettings.viewMode);
|
|
415
|
+
};
|
|
416
|
+
var openImage = /*#__PURE__*/function () {
|
|
417
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
|
|
418
|
+
var _getCurrentViewerChan2;
|
|
419
|
+
var _props, imageUrl, parentImageUrl, rawData, rawDims, scene, scenePaths, _scenes2, showParentImage, path, loadSpec, options, aimg, channelNames, newChannelSettings, requiredLoadSpec, requiredChannelsToLoad, maskChannelName, maskChannelIndex, slice;
|
|
420
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
421
|
+
while (1) switch (_context.prev = _context.next) {
|
|
422
|
+
case 0:
|
|
423
|
+
_props = props, imageUrl = _props.imageUrl, parentImageUrl = _props.parentImageUrl, rawData = _props.rawData, rawDims = _props.rawDims;
|
|
424
|
+
scene = viewerState.current.scene;
|
|
425
|
+
if (!(rawData && rawDims)) {
|
|
426
|
+
_context.next = 6;
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
scenePaths = [{
|
|
430
|
+
data: rawData,
|
|
431
|
+
metadata: rawDims
|
|
432
|
+
}];
|
|
433
|
+
_context.next = 12;
|
|
434
|
+
break;
|
|
435
|
+
case 6:
|
|
436
|
+
showParentImage = viewerState.current.imageType === ImageType.fullField && parentImageUrl !== undefined;
|
|
437
|
+
path = showParentImage ? parentImageUrl : imageUrl; // Don't reload if we're already looking at this image
|
|
438
|
+
if (!isEqual(path, imageUrlRef.current)) {
|
|
439
|
+
_context.next = 10;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
return _context.abrupt("return");
|
|
443
|
+
case 10:
|
|
444
|
+
imageUrlRef.current = path;
|
|
445
|
+
scenePaths = (_scenes2 = path.scenes) !== null && _scenes2 !== void 0 ? _scenes2 : [path];
|
|
446
|
+
case 12:
|
|
447
|
+
setSendingQueryRequest(true);
|
|
448
|
+
setImageLoaded(false);
|
|
449
|
+
hasChannelLoadedRef.current = [];
|
|
450
|
+
loadSpec = new LoadSpec();
|
|
451
|
+
loadSpec.time = viewerState.current.time;
|
|
452
|
+
options = {};
|
|
453
|
+
if (rawData && rawDims) {
|
|
454
|
+
options.fileType = VolumeFileFormat.DATA;
|
|
455
|
+
options.rawArrayOptions = {
|
|
456
|
+
data: rawData,
|
|
457
|
+
metadata: rawDims
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
_context.prev = 19;
|
|
461
|
+
loader.current = new SceneStore(loadContext, scenePaths);
|
|
462
|
+
_context.next = 23;
|
|
463
|
+
return loader.current.createVolume(scene, loadSpec, function (v, channelIndex) {
|
|
464
|
+
// NOTE: this callback runs *after* `onNewVolumeCreated` below, for every loaded channel
|
|
465
|
+
// TODO is this search by name necessary or will the `channelIndex` passed to the callback always match state?
|
|
466
|
+
var thisChannelSettings = viewerState.current.channelSettings[channelIndex];
|
|
467
|
+
onChannelDataLoaded(v, thisChannelSettings, channelIndex);
|
|
468
|
+
});
|
|
469
|
+
case 23:
|
|
470
|
+
aimg = _context.sent;
|
|
471
|
+
_context.next = 30;
|
|
472
|
+
break;
|
|
473
|
+
case 26:
|
|
474
|
+
_context.prev = 26;
|
|
475
|
+
_context.t0 = _context["catch"](19);
|
|
476
|
+
showError(_context.t0);
|
|
477
|
+
throw _context.t0;
|
|
478
|
+
case 30:
|
|
479
|
+
channelNames = aimg.imageInfo.channelNames;
|
|
480
|
+
newChannelSettings = setChannelStateForNewImage(channelNames); // order is important:
|
|
481
|
+
// we need to remove the old volume before triggering channels unloaded,
|
|
482
|
+
// which may cause calls on View3d to the old volume.
|
|
483
|
+
view3d.removeAllVolumes();
|
|
484
|
+
setAllChannelsUnloaded(channelNames.length);
|
|
485
|
+
placeImageInViewer(aimg, newChannelSettings);
|
|
486
|
+
channelRangesRef.current = new Array(channelNames.length).fill(undefined);
|
|
487
|
+
requiredLoadSpec = new LoadSpec();
|
|
488
|
+
requiredLoadSpec.time = viewerState.current.time;
|
|
489
|
+
|
|
490
|
+
// make the currently enabled channels "required":
|
|
491
|
+
// find all enabled indices in newChannelSettings:
|
|
492
|
+
requiredChannelsToLoad = newChannelSettings ? newChannelSettings.map(function (channel, index) {
|
|
493
|
+
return channel.volumeEnabled ? index : -1;
|
|
494
|
+
}).filter(function (index) {
|
|
495
|
+
return index >= 0;
|
|
496
|
+
}) : []; // add mask channel to required channels, if specified
|
|
497
|
+
maskChannelName = (_getCurrentViewerChan2 = getCurrentViewerChannelSettings()) === null || _getCurrentViewerChan2 === void 0 ? void 0 : _getCurrentViewerChan2.maskChannelName;
|
|
498
|
+
if (maskChannelName) {
|
|
499
|
+
maskChannelIndex = channelNames.indexOf(maskChannelName);
|
|
500
|
+
if (maskChannelIndex >= 0 && !requiredChannelsToLoad.includes(maskChannelIndex)) {
|
|
501
|
+
requiredChannelsToLoad.push(maskChannelIndex);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
requiredLoadSpec.channels = requiredChannelsToLoad;
|
|
505
|
+
|
|
506
|
+
// When in 2D Z-axis view mode, we restrict the subregion to only the current slice. This is
|
|
507
|
+
// to match an optimization that volume viewer does by loading Z-slices at a higher resolution,
|
|
508
|
+
// and ensures the very first volume that is loaded is the same as the one that
|
|
509
|
+
// will be shown whenever we switch back to the same viewer settings (2D Z-axis view mode).
|
|
510
|
+
// (We don't do this for ZX and YZ modes because we assume that the data won't be chunked along the
|
|
511
|
+
// X or Y axes in ways that would improve loading resolution, and we load the full 3D volume instead.)
|
|
512
|
+
if (viewerSettings.viewMode === ViewMode.xy) {
|
|
513
|
+
slice = viewerSettings.slice;
|
|
514
|
+
requiredLoadSpec.subregion = new Box3(new Vector3(0, 0, slice.z), new Vector3(1, 1, slice.z));
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// initiate loading only after setting up new channel settings,
|
|
518
|
+
// in case the loader callback fires before the state is set
|
|
519
|
+
loader.current.loadScene(scene, aimg, requiredLoadSpec)["catch"](function (e) {
|
|
520
|
+
showError(e);
|
|
521
|
+
throw e;
|
|
522
|
+
});
|
|
523
|
+
case 44:
|
|
524
|
+
case "end":
|
|
525
|
+
return _context.stop();
|
|
526
|
+
}
|
|
527
|
+
}, _callee, null, [[19, 26]]);
|
|
528
|
+
}));
|
|
529
|
+
return function openImage() {
|
|
530
|
+
return _ref.apply(this, arguments);
|
|
531
|
+
};
|
|
532
|
+
}();
|
|
533
|
+
|
|
534
|
+
// Imperative callbacks /////////////////////////////////////////////////////
|
|
535
|
+
|
|
536
|
+
var viewerSettings = viewerState.current;
|
|
537
|
+
var saveIsosurface = useCallback(function (channelIndex, type) {
|
|
538
|
+
if (image) view3d.saveChannelIsosurface(image, channelIndex, type);
|
|
539
|
+
}, [image]);
|
|
540
|
+
var saveScreenshot = useCallback(function () {
|
|
541
|
+
view3d.capture(function (dataUrl) {
|
|
542
|
+
var anchor = document.createElement("a");
|
|
543
|
+
anchor.href = dataUrl;
|
|
544
|
+
anchor.download = "screenshot.png";
|
|
545
|
+
anchor.click();
|
|
546
|
+
});
|
|
547
|
+
}, []);
|
|
548
|
+
var resetCamera = useCallback(function () {
|
|
549
|
+
return view3d.resetCamera();
|
|
550
|
+
}, []);
|
|
551
|
+
var onClippingPanelVisibleChange = useCallback(function (panelOpen, hasTime, hasScenes, mode3d) {
|
|
552
|
+
clippingPanelOpenRef.current = panelOpen;
|
|
553
|
+
setIndicatorPositions(view3d, panelOpen, hasTime, hasScenes, mode3d);
|
|
554
|
+
|
|
555
|
+
// Hide indicators while clipping panel is in motion - otherwise they pop to the right place prematurely
|
|
556
|
+
view3d.setShowScaleBar(false);
|
|
557
|
+
view3d.setShowTimestepIndicator(false);
|
|
558
|
+
view3d.setShowAxis(false);
|
|
559
|
+
}, [viewerSettings.showAxes]);
|
|
560
|
+
var onClippingPanelVisibleChangeEnd = useCallback(function () {
|
|
561
|
+
view3d.setShowScaleBar(true);
|
|
562
|
+
view3d.setShowTimestepIndicator(true);
|
|
563
|
+
if (viewerSettings.showAxes) {
|
|
564
|
+
view3d.setShowAxis(true);
|
|
565
|
+
}
|
|
566
|
+
}, [viewerSettings.showAxes]);
|
|
567
|
+
var getMetadata = useCallback(function () {
|
|
568
|
+
var _props2 = props,
|
|
569
|
+
metadata = _props2.metadata,
|
|
570
|
+
metadataFormatter = _props2.metadataFormatter;
|
|
571
|
+
var imageMetadata = image === null || image === void 0 ? void 0 : image.imageMetadata;
|
|
572
|
+
if (imageMetadata && metadataFormatter) {
|
|
573
|
+
imageMetadata = metadataFormatter(imageMetadata);
|
|
574
|
+
}
|
|
575
|
+
if (imageMetadata && Object.keys(imageMetadata).length > 0) {
|
|
576
|
+
return _objectSpread({
|
|
577
|
+
Image: imageMetadata
|
|
578
|
+
}, metadata);
|
|
579
|
+
} else {
|
|
580
|
+
return metadata || {};
|
|
581
|
+
}
|
|
582
|
+
}, [props.metadata, props.metadataFormatter, image]);
|
|
583
|
+
|
|
584
|
+
// Effects //////////////////////////////////////////////////////////////////
|
|
585
|
+
|
|
586
|
+
// On mount
|
|
587
|
+
useEffect(function () {
|
|
588
|
+
var onResize = function onResize() {
|
|
589
|
+
if (window.innerWidth < CONTROL_PANEL_CLOSE_WIDTH) {
|
|
590
|
+
if (!hasAutoClosedControlPanel) {
|
|
591
|
+
setControlPanelClosed(true);
|
|
592
|
+
setHasAutoClosedControlPanel(true);
|
|
593
|
+
}
|
|
594
|
+
} else {
|
|
595
|
+
setHasAutoClosedControlPanel(false);
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
var onResizeDebounced = debounce(onResize, 500);
|
|
599
|
+
window.addEventListener("resize", onResizeDebounced);
|
|
600
|
+
return function () {
|
|
601
|
+
return window.removeEventListener("resize", onResizeDebounced);
|
|
602
|
+
};
|
|
603
|
+
}, [hasAutoClosedControlPanel]);
|
|
604
|
+
|
|
605
|
+
// one-time init after view3d exists and before we start loading images
|
|
606
|
+
useEffect(function () {
|
|
607
|
+
view3d.setCameraMode(viewerSettings.viewMode);
|
|
608
|
+
}, []);
|
|
609
|
+
|
|
610
|
+
// Hook to trigger image load: on mount, when image source props/state change (`cellId`, `imageType`, `rawData`, etc)
|
|
611
|
+
useEffect(function () {
|
|
612
|
+
openImage();
|
|
613
|
+
}, [props.imageUrl, props.cellId, viewerSettings.imageType, props.rawDims, props.rawData]);
|
|
614
|
+
useEffect(function () {
|
|
615
|
+
return props.onControlPanelToggle && props.onControlPanelToggle(controlPanelClosed);
|
|
616
|
+
}, [controlPanelClosed, props.onControlPanelToggle]);
|
|
617
|
+
useEffect(function () {
|
|
618
|
+
// delayed for the animation to finish
|
|
619
|
+
window.setTimeout(function () {
|
|
620
|
+
window.dispatchEvent(new Event("resize"));
|
|
621
|
+
}, 200);
|
|
622
|
+
}, [controlPanelClosed]);
|
|
623
|
+
|
|
624
|
+
/** Custom effect hook for viewer updates that depend on `image`, so we don't have to repeatedly null-check it */
|
|
625
|
+
var useImageEffect = function useImageEffect(effect, deps) {
|
|
626
|
+
useEffect(function () {
|
|
627
|
+
if (image && imageLoaded) {
|
|
628
|
+
return effect(image);
|
|
629
|
+
}
|
|
630
|
+
}, [].concat(_toConsumableArray(deps), [image, imageLoaded]));
|
|
631
|
+
};
|
|
632
|
+
var imageLoadHandlers = useRef([]);
|
|
633
|
+
imageLoadHandlers.current = [];
|
|
634
|
+
/** `ImageEffect`s that also run right on image creation, so the image doesn't first render with default settings */
|
|
635
|
+
var useImageLoadEffect = function useImageLoadEffect(effect, deps) {
|
|
636
|
+
useImageEffect(effect, deps);
|
|
637
|
+
imageLoadHandlers.current.push(effect);
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
// Effects to imperatively sync `viewerSettings` to `view3d`
|
|
641
|
+
useImageEffect(function (_currentImage) {
|
|
642
|
+
view3d.setCameraMode(viewerSettings.viewMode);
|
|
643
|
+
view3d.resize(null);
|
|
644
|
+
}, [viewerSettings.viewMode]);
|
|
645
|
+
useImageEffect(function (_currentImage) {
|
|
646
|
+
if (viewerSettings.cameraState) {
|
|
647
|
+
view3d.setCameraState(viewerSettings.cameraState);
|
|
648
|
+
}
|
|
649
|
+
}, [viewerSettings.cameraState]);
|
|
650
|
+
useImageEffect(function (_currentImage) {
|
|
651
|
+
return view3d.setAutoRotate(viewerSettings.autorotate);
|
|
652
|
+
}, [viewerSettings.autorotate]);
|
|
653
|
+
useImageEffect(function (_currentImage) {
|
|
654
|
+
return view3d.setShowAxis(viewerSettings.showAxes);
|
|
655
|
+
}, [viewerSettings.showAxes]);
|
|
656
|
+
useImageEffect(function (_currentImage) {
|
|
657
|
+
return view3d.setBackgroundColor(colorArrayToFloats(viewerSettings.backgroundColor));
|
|
658
|
+
}, [viewerSettings.backgroundColor]);
|
|
659
|
+
useImageEffect(function (currentImage) {
|
|
660
|
+
return view3d.setBoundingBoxColor(currentImage, colorArrayToFloats(viewerSettings.boundingBoxColor));
|
|
661
|
+
}, [viewerSettings.boundingBoxColor]);
|
|
662
|
+
useImageEffect(function (currentImage) {
|
|
663
|
+
return view3d.setShowBoundingBox(currentImage, viewerSettings.showBoundingBox);
|
|
664
|
+
}, [viewerSettings.showBoundingBox]);
|
|
665
|
+
useImageEffect(function (image) {
|
|
666
|
+
// Check whether any channels are marked to be reset and apply it.
|
|
667
|
+
var channelsAwaitingReset = getChannelsAwaitingReset();
|
|
668
|
+
for (var i = 0; i < channelSettings.length; i++) {
|
|
669
|
+
if (channelsAwaitingReset.has(i)) {
|
|
670
|
+
var _initializeLut2 = initializeLut(image, i, getCurrentViewerChannelSettings()),
|
|
671
|
+
ramp = _initializeLut2.ramp,
|
|
672
|
+
controlPoints = _initializeLut2.controlPoints;
|
|
673
|
+
changeChannelSetting(i, {
|
|
674
|
+
controlPoints: controlPoints,
|
|
675
|
+
ramp: controlPointsToRamp(ramp)
|
|
676
|
+
});
|
|
677
|
+
onResetChannel(i);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}, [channelSettings]);
|
|
681
|
+
useImageLoadEffect(function (currentImage) {
|
|
682
|
+
var renderMode = viewerSettings.renderMode;
|
|
683
|
+
view3d.setMaxProjectMode(currentImage, renderMode === RenderMode.maxProject);
|
|
684
|
+
view3d.setVolumeRenderMode(renderMode === RenderMode.pathTrace ? RENDERMODE_PATHTRACE : RENDERMODE_RAYMARCH);
|
|
685
|
+
view3d.updateActiveChannels(currentImage);
|
|
686
|
+
}, [viewerSettings.renderMode]);
|
|
687
|
+
useImageEffect(function (currentImage) {
|
|
688
|
+
view3d.updateMaskAlpha(currentImage, alphaSliderToImageValue(viewerSettings.maskAlpha));
|
|
689
|
+
view3d.updateActiveChannels(currentImage);
|
|
690
|
+
}, [viewerSettings.maskAlpha]);
|
|
691
|
+
useImageLoadEffect(function (_currentImage) {
|
|
692
|
+
var isPathTracing = viewerSettings.renderMode === RenderMode.pathTrace;
|
|
693
|
+
var brightness = brightnessSliderToImageValue(viewerSettings.brightness, isPathTracing);
|
|
694
|
+
view3d.updateExposure(brightness);
|
|
695
|
+
}, [viewerSettings.brightness]);
|
|
696
|
+
useImageLoadEffect(function (currentImage) {
|
|
697
|
+
var isPathTracing = viewerSettings.renderMode === RenderMode.pathTrace;
|
|
698
|
+
var density = densitySliderToImageValue(viewerSettings.density, isPathTracing);
|
|
699
|
+
view3d.updateDensity(currentImage, density);
|
|
700
|
+
}, [viewerSettings.density]);
|
|
701
|
+
useImageLoadEffect(function (currentImage) {
|
|
702
|
+
var imageValues = gammaSliderToImageValues(viewerSettings.levels);
|
|
703
|
+
view3d.setGamma(currentImage, imageValues.min, imageValues.scale, imageValues.max);
|
|
704
|
+
}, [viewerSettings.levels]);
|
|
705
|
+
|
|
706
|
+
// `time` is special: because syncing it requires a load, it cannot be dependent on `image`
|
|
707
|
+
useEffect(function () {
|
|
708
|
+
if (image) {
|
|
709
|
+
setSendingQueryRequest(true);
|
|
710
|
+
setAllChannelsUnloaded(image.numChannels);
|
|
711
|
+
view3d.setTime(image, viewerSettings.time);
|
|
712
|
+
}
|
|
713
|
+
}, [viewerSettings.time]);
|
|
714
|
+
useEffect(function () {
|
|
715
|
+
if (image) {
|
|
716
|
+
var _loader$current3;
|
|
717
|
+
setSendingQueryRequest(true);
|
|
718
|
+
(_loader$current3 = loader.current) === null || _loader$current3 === void 0 || _loader$current3.loadScene(viewerSettings.scene, image)["catch"](function (e) {
|
|
719
|
+
return showError(e);
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
}, [viewerSettings.scene]);
|
|
723
|
+
useImageLoadEffect(function (currentImage) {
|
|
724
|
+
return view3d.setInterpolationEnabled(currentImage, viewerSettings.interpolationEnabled);
|
|
725
|
+
}, [viewerSettings.interpolationEnabled]);
|
|
726
|
+
useImageLoadEffect(function (currentImage) {
|
|
727
|
+
var _props$transform;
|
|
728
|
+
return view3d.setVolumeTranslation(currentImage, ((_props$transform = props.transform) === null || _props$transform === void 0 ? void 0 : _props$transform.translation) || [0, 0, 0]);
|
|
729
|
+
}, [(_props$transform2 = props.transform) === null || _props$transform2 === void 0 ? void 0 : _props$transform2.translation]);
|
|
730
|
+
useImageLoadEffect(function (currentImage) {
|
|
731
|
+
var _props$transform3;
|
|
732
|
+
return view3d.setVolumeRotation(currentImage, ((_props$transform3 = props.transform) === null || _props$transform3 === void 0 ? void 0 : _props$transform3.rotation) || [0, 0, 0]);
|
|
733
|
+
}, [(_props$transform4 = props.transform) === null || _props$transform4 === void 0 ? void 0 : _props$transform4.rotation]);
|
|
734
|
+
var usePerAxisClippingUpdater = function usePerAxisClippingUpdater(axis, _ref2, slice) {
|
|
735
|
+
var _ref3 = _slicedToArray(_ref2, 2),
|
|
736
|
+
minval = _ref3[0],
|
|
737
|
+
maxval = _ref3[1];
|
|
738
|
+
useImageEffect(
|
|
739
|
+
// Logic to determine axis clipping range, for each of x,y,z,3d slider:
|
|
740
|
+
// if slider was same as active axis view mode: [viewerSettings.slice[axis], viewerSettings.slice[axis] + 1.0/volumeSize[axis]]
|
|
741
|
+
// if in 3d mode: viewerSettings.region[axis]
|
|
742
|
+
// else: [0,1]
|
|
743
|
+
function (currentImage) {
|
|
744
|
+
var isOrthoAxis = false;
|
|
745
|
+
var axismin = 0.0;
|
|
746
|
+
var axismax = 1.0;
|
|
747
|
+
if (viewerSettings.viewMode === ViewMode.threeD) {
|
|
748
|
+
axismin = minval;
|
|
749
|
+
axismax = maxval;
|
|
750
|
+
isOrthoAxis = false;
|
|
751
|
+
} else {
|
|
752
|
+
isOrthoAxis = activeAxisMap[viewerSettings.viewMode] === axis;
|
|
753
|
+
var oneSlice = 1 / currentImage.imageInfo.volumeSize[axis];
|
|
754
|
+
axismin = isOrthoAxis ? slice : 0.0;
|
|
755
|
+
axismax = isOrthoAxis ? slice + oneSlice : 1.0;
|
|
756
|
+
if (axis === "z" && viewerSettings.viewMode === ViewMode.xy) {
|
|
757
|
+
view3d.setZSlice(currentImage, Math.floor(slice * currentImage.imageInfo.volumeSize.z));
|
|
758
|
+
if (!currentImage.isLoaded()) {
|
|
759
|
+
setImageLoaded(false);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
// view3d wants the coordinates in the -0.5 to 0.5 range
|
|
764
|
+
view3d.setAxisClip(currentImage, axis, axismin - 0.5, axismax - 0.5, isOrthoAxis);
|
|
765
|
+
view3d.setCameraMode(viewerSettings.viewMode);
|
|
766
|
+
}, [minval, maxval, slice, viewerSettings.viewMode]);
|
|
767
|
+
};
|
|
768
|
+
usePerAxisClippingUpdater("x", viewerSettings.region.x, viewerSettings.slice.x);
|
|
769
|
+
usePerAxisClippingUpdater("y", viewerSettings.region.y, viewerSettings.slice.y);
|
|
770
|
+
usePerAxisClippingUpdater("z", viewerSettings.region.z, viewerSettings.slice.z);
|
|
771
|
+
|
|
772
|
+
// Rendering ////////////////////////////////////////////////////////////////
|
|
773
|
+
|
|
774
|
+
var visibleControls = useMemo(function () {
|
|
775
|
+
return _objectSpread(_objectSpread({}, defaultVisibleControls), props.visibleControls);
|
|
776
|
+
}, [props.visibleControls]);
|
|
777
|
+
var pixelSize = useMemo(function () {
|
|
778
|
+
return image ? image.imageInfo.physicalPixelSize.toArray() : [1, 1, 1];
|
|
779
|
+
}, [image === null || image === void 0 ? void 0 : image.imageInfo.physicalPixelSize]);
|
|
780
|
+
return /*#__PURE__*/React.createElement(StyleProvider, null, errorAlert, /*#__PURE__*/React.createElement(Layout, {
|
|
781
|
+
className: "cell-viewer-app",
|
|
782
|
+
style: {
|
|
783
|
+
height: props.appHeight
|
|
784
|
+
}
|
|
785
|
+
}, channelSettings.map(function (channelState, index) {
|
|
786
|
+
return /*#__PURE__*/React.createElement(ChannelUpdater, {
|
|
787
|
+
key: "".concat(index, "_").concat(channelState.name),
|
|
788
|
+
channelState: channelState,
|
|
789
|
+
index: index,
|
|
790
|
+
view3d: view3d,
|
|
791
|
+
image: image,
|
|
792
|
+
version: channelVersions[index]
|
|
793
|
+
});
|
|
794
|
+
}), /*#__PURE__*/React.createElement(Sider, {
|
|
795
|
+
className: "control-panel-holder",
|
|
796
|
+
collapsible: true,
|
|
797
|
+
defaultCollapsed: false,
|
|
798
|
+
collapsedWidth: 50,
|
|
799
|
+
trigger: null,
|
|
800
|
+
collapsed: controlPanelClosed,
|
|
801
|
+
width: 500
|
|
802
|
+
}, /*#__PURE__*/React.createElement(ControlPanel, {
|
|
803
|
+
visibleControls: visibleControls,
|
|
804
|
+
collapsed: controlPanelClosed
|
|
805
|
+
// image state
|
|
806
|
+
,
|
|
807
|
+
imageName: image === null || image === void 0 ? void 0 : image.name,
|
|
808
|
+
hasImage: !!image,
|
|
809
|
+
pixelSize: pixelSize,
|
|
810
|
+
channelDataChannels: image === null || image === void 0 ? void 0 : image.channels,
|
|
811
|
+
channelGroupedByType: channelGroupedByType
|
|
812
|
+
// functions
|
|
813
|
+
,
|
|
814
|
+
setCollapsed: setControlPanelClosed,
|
|
815
|
+
saveIsosurface: saveIsosurface,
|
|
816
|
+
onApplyColorPresets: applyColorPresets,
|
|
817
|
+
viewerChannelSettings: props.viewerChannelSettings,
|
|
818
|
+
getMetadata: getMetadata
|
|
819
|
+
})), /*#__PURE__*/React.createElement(Layout, {
|
|
820
|
+
className: "cell-viewer-wrapper",
|
|
821
|
+
style: {
|
|
822
|
+
margin: props.canvasMargin
|
|
823
|
+
}
|
|
824
|
+
}, /*#__PURE__*/React.createElement(Content, null, /*#__PURE__*/React.createElement(Toolbar, {
|
|
825
|
+
fovDownloadHref: props.parentImageDownloadHref,
|
|
826
|
+
cellDownloadHref: props.imageDownloadHref,
|
|
827
|
+
hasParentImage: !!props.parentImageUrl,
|
|
828
|
+
hasCellId: !!props.cellId,
|
|
829
|
+
canPathTrace: view3d ? view3d.hasWebGL2() : false,
|
|
830
|
+
resetCamera: resetCamera,
|
|
831
|
+
downloadScreenshot: saveScreenshot,
|
|
832
|
+
visibleControls: visibleControls
|
|
833
|
+
}), /*#__PURE__*/React.createElement(CellViewerCanvasWrapper, {
|
|
834
|
+
view3d: view3d,
|
|
835
|
+
image: image,
|
|
836
|
+
loadingImage: sendingQueryRequest,
|
|
837
|
+
numSlices: numSlices,
|
|
838
|
+
numSlicesLoaded: numSlicesLoaded,
|
|
839
|
+
numTimesteps: numTimesteps,
|
|
840
|
+
numScenes: numScenes,
|
|
841
|
+
playControls: playControls,
|
|
842
|
+
playingAxis: playingAxis,
|
|
843
|
+
appHeight: props.appHeight,
|
|
844
|
+
visibleControls: visibleControls,
|
|
845
|
+
onClippingPanelVisibleChange: onClippingPanelVisibleChange,
|
|
846
|
+
onClippingPanelVisibleChangeEnd: onClippingPanelVisibleChangeEnd
|
|
847
|
+
})))));
|
|
848
|
+
};
|
|
849
|
+
export default App;
|