@aics/vole-app 2.14.0 → 3.1.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.
Files changed (81) hide show
  1. package/es/Globals.d.js +0 -0
  2. package/es/aics-image-viewer/components/App/ChannelUpdater.js +21 -3
  3. package/es/aics-image-viewer/components/App/index.js +184 -198
  4. package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +10 -9
  5. package/es/aics-image-viewer/components/ChannelsWidget.js +35 -22
  6. package/es/aics-image-viewer/components/ChannelsWidgetRow/index.js +26 -52
  7. package/es/aics-image-viewer/components/ChannelsWidgetRow/styles.css +0 -6
  8. package/es/aics-image-viewer/components/ColorPicker.js +1 -1
  9. package/es/aics-image-viewer/components/ControlPanel/index.js +5 -4
  10. package/es/aics-image-viewer/components/CustomizeWidget.js +12 -8
  11. package/es/aics-image-viewer/components/ErrorAlert/index.js +4 -4
  12. package/es/aics-image-viewer/components/GlobalVolumeControls.js +15 -12
  13. package/es/aics-image-viewer/components/StyleProvider/index.js +4 -2
  14. package/es/aics-image-viewer/components/TfEditor/index.js +304 -154
  15. package/es/aics-image-viewer/components/TfEditor/styles.css +53 -31
  16. package/es/aics-image-viewer/components/Toolbar/DownloadButton.js +1 -1
  17. package/es/aics-image-viewer/components/Toolbar/index.js +18 -16
  18. package/es/aics-image-viewer/components/shared/SharedCheckBox.js +1 -1
  19. package/es/aics-image-viewer/components/shared/SliderRow/index.js +8 -3
  20. package/es/aics-image-viewer/components/shared/SliderRow/styles.css +7 -0
  21. package/es/aics-image-viewer/components/shared/SmarterSlider.js +1 -1
  22. package/es/aics-image-viewer/components/shared/ViewerIcon.js +1 -1
  23. package/es/aics-image-viewer/components/useVolume.js +59 -58
  24. package/es/aics-image-viewer/shared/constants.js +2 -2
  25. package/es/aics-image-viewer/shared/utils/controlPointsToLut.js +57 -24
  26. package/es/aics-image-viewer/shared/utils/sceneStore.js +5 -3
  27. package/es/aics-image-viewer/shared/utils/storage.js +238 -0
  28. package/es/aics-image-viewer/shared/utils/test/storage.test.js +264 -0
  29. package/es/aics-image-viewer/shared/utils/test/urlParsing.test.js +240 -108
  30. package/es/aics-image-viewer/shared/utils/test/viewerChannelSettings.test.js +1 -1
  31. package/es/aics-image-viewer/shared/utils/urlParsing.js +278 -153
  32. package/es/aics-image-viewer/shared/utils/viewerState.js +4 -24
  33. package/es/aics-image-viewer/state/reset.js +111 -0
  34. package/es/aics-image-viewer/state/store.js +90 -0
  35. package/es/aics-image-viewer/state/subscribers.js +153 -0
  36. package/es/aics-image-viewer/state/test/reset.test.js +247 -0
  37. package/es/aics-image-viewer/state/util.js +71 -0
  38. package/es/index.js +3 -3
  39. package/package.json +18 -11
  40. package/type-declarations/aics-image-viewer/components/App/ChannelUpdater.d.ts +2 -4
  41. package/type-declarations/aics-image-viewer/components/App/types.d.ts +3 -3
  42. package/type-declarations/aics-image-viewer/components/AxisClipSliders/index.d.ts +6 -6
  43. package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +5 -14
  44. package/type-declarations/aics-image-viewer/components/ChannelsWidget.d.ts +3 -6
  45. package/type-declarations/aics-image-viewer/components/ChannelsWidgetRow/index.d.ts +3 -6
  46. package/type-declarations/aics-image-viewer/components/ColorPicker.d.ts +1 -1
  47. package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +6 -7
  48. package/type-declarations/aics-image-viewer/components/CustomizeWidget.d.ts +2 -8
  49. package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +4 -0
  50. package/type-declarations/aics-image-viewer/components/GlobalVolumeControls.d.ts +2 -9
  51. package/type-declarations/aics-image-viewer/components/MetadataViewer/index.d.ts +1 -1
  52. package/type-declarations/aics-image-viewer/components/StyleProvider/index.d.ts +1 -1
  53. package/type-declarations/aics-image-viewer/components/TfEditor/index.d.ts +10 -3
  54. package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +3 -12
  55. package/type-declarations/aics-image-viewer/components/shared/SliderRow/index.d.ts +2 -1
  56. package/type-declarations/aics-image-viewer/components/shared/SmarterSlider.d.ts +1 -1
  57. package/type-declarations/aics-image-viewer/components/shared/ViewerIcon.d.ts +1 -1
  58. package/type-declarations/aics-image-viewer/components/useVolume.d.ts +7 -4
  59. package/type-declarations/aics-image-viewer/shared/constants.d.ts +5 -5
  60. package/type-declarations/aics-image-viewer/shared/types.d.ts +1 -1
  61. package/type-declarations/aics-image-viewer/shared/utils/controlPointsToLut.d.ts +9 -5
  62. package/type-declarations/aics-image-viewer/shared/utils/firebase/index.d.ts +1 -1
  63. package/type-declarations/aics-image-viewer/shared/utils/hooks.d.ts +1 -1
  64. package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +1 -1
  65. package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +8 -4
  66. package/type-declarations/aics-image-viewer/shared/utils/storage.d.ts +15 -0
  67. package/type-declarations/aics-image-viewer/shared/utils/urlParsing.d.ts +94 -31
  68. package/type-declarations/aics-image-viewer/shared/utils/viewerChannelSettings.d.ts +39 -1
  69. package/type-declarations/aics-image-viewer/shared/utils/viewerState.d.ts +3 -6
  70. package/type-declarations/aics-image-viewer/state/reset.d.ts +29 -0
  71. package/type-declarations/aics-image-viewer/state/store.d.ts +30 -0
  72. package/type-declarations/aics-image-viewer/state/subscribers.d.ts +4 -0
  73. package/type-declarations/aics-image-viewer/state/types.d.ts +46 -0
  74. package/type-declarations/aics-image-viewer/state/util.d.ts +8 -0
  75. package/type-declarations/index.d.ts +4 -4
  76. package/es/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.js +0 -163
  77. package/es/aics-image-viewer/components/ViewerStateProvider/index.js +0 -259
  78. package/type-declarations/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.d.ts +0 -34
  79. package/type-declarations/aics-image-viewer/components/ViewerStateProvider/index.d.ts +0 -33
  80. package/type-declarations/aics-image-viewer/components/ViewerStateProvider/types.d.ts +0 -107
  81. /package/es/aics-image-viewer/{components/ViewerStateProvider → state}/types.js +0 -0
@@ -1,10 +1,10 @@
1
1
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
- var _ViewerChannelSetting, _ViewerChannelSetting2, _ViewerChannelSetting3, _ViewerChannelSetting4, _ViewerChannelSetting5, _ViewerChannelSetting6, _ViewerChannelSetting7, _ViewerChannelSetting8, _ViewerChannelSetting9, _ViewerChannelSetting10, _ViewerChannelSetting11, _ViewerStateKeys$View, _ViewerStateKeys$Mode, _ViewerStateKeys$Mask, _ViewerStateKeys$Imag, _ViewerStateKeys$Axes, _ViewerStateKeys$Boun, _ViewerStateKeys$Boun2, _ViewerStateKeys$Back, _ViewerStateKeys$Auto, _ViewerStateKeys$Brig, _ViewerStateKeys$Dens, _ViewerStateKeys$Leve, _ViewerStateKeys$Inte, _ViewerStateKeys$Regi, _ViewerStateKeys$Slic, _ViewerStateKeys$Time, _ViewerStateKeys$Scen, _ViewerStateKeys$Came;
2
+ var _ViewerChannelSetting, _ViewerChannelSetting2, _ViewerChannelSetting3, _ViewerChannelSetting4, _ViewerChannelSetting5, _ViewerChannelSetting6, _ViewerChannelSetting7, _ViewerChannelSetting8, _ViewerChannelSetting9, _ViewerChannelSetting10, _ViewerChannelSetting11, _ViewerChannelSetting12, _ViewerChannelSetting13, _ViewerChannelSetting14, _ViewerStateKeys$View, _ViewerStateKeys$Mode, _ViewerStateKeys$Mask, _ViewerStateKeys$Imag, _ViewerStateKeys$Axes, _ViewerStateKeys$Boun, _ViewerStateKeys$Boun2, _ViewerStateKeys$Back, _ViewerStateKeys$Auto, _ViewerStateKeys$Brig, _ViewerStateKeys$Dens, _ViewerStateKeys$Leve, _ViewerStateKeys$Inte, _ViewerStateKeys$Regi, _ViewerStateKeys$Slic, _ViewerStateKeys$Time, _ViewerStateKeys$Scen, _ViewerStateKeys$Came;
3
3
  function _regeneratorRuntime() { "use strict"; /*! 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; }
4
- 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; }
5
- 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; }
6
4
  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); }
7
5
  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); }); }; }
6
+ 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; }
7
+ 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; }
8
8
  function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
9
9
  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."); }
10
10
  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; } }
@@ -28,54 +28,55 @@ import { ImageType, RenderMode, ViewMode } from "../enums";
28
28
  import { removeMatchingProperties, removeUndefinedProperties } from "./datatypes";
29
29
  import FirebaseRequest from "./firebase";
30
30
  import { clamp } from "./math";
31
+ import { readStoredMetadata, readStoredScenes } from "./storage";
31
32
  export var ENCODED_COMMA_REGEX = /%2C/g;
32
33
  export var ENCODED_COLON_REGEX = /%3A/g;
33
34
  var DEFAULT_CONTROL_POINT_COLOR = [255, 255, 255];
34
35
  var DEFAULT_CONTROL_POINT_COLOR_CODE = "1";
35
-
36
- /** If the `url` query param equals this, parse image url(s) and metadata from local storage instead of params */
37
- var URL_FETCH_FROM_STORAGE = "storage";
38
-
39
- // TODO: refactor regexes to be composed of one another rather than duplicating code
40
- // const COLOR_CODES: Record<string, ColorArray> = {
41
- // "0": [0, 0, 0],
42
- // "1": [255, 255, 255],
43
- // "-1": [255, 255, 255],
44
- // w: [255, 255, 255],
45
- // k: [0, 0, 0],
46
- // };
47
- // const COLOR_CODE_REGEX = new RegExp(`(${Object.keys(COLOR_CODES).join("|")})`);
48
- // const HEX_COLOR_REGEX = new RegExp(`(([0-9a-fA-F]{6})|${COLOR_CODE_REGEX.source})`);
49
-
36
+ var FLOAT_REGEX = /-?[0-9]*.?[0-9]+/;
50
37
  var CHANNEL_STATE_KEY_REGEX = /^c[0-9]+$/;
38
+
51
39
  /** Match colon-separated pairs of alphanumeric strings */
52
40
  var LUT_REGEX = /^-?[a-z0-9.]*:[ ]*-?[a-z0-9.]*$/;
53
- /** Match colon-separated pairs of numeric strings */
54
- var RAMP_REGEX = /^-?[0-9.]*:-?[0-9.]*$/;
41
+
42
+ /**
43
+ * Match colon-separated pairs of numeric strings, representing histogram bin
44
+ * indices or intensity values.
45
+ */
46
+ var RAMP_REGEX = new RegExp("^".concat(FLOAT_REGEX.source, ":").concat(FLOAT_REGEX.source, "$"));
47
+
55
48
  /**
56
49
  * Match comma-separated triplet of numeric strings.
57
50
  */
58
- var SLICE_REGEX = /^[0-9.]*,[0-9.]*,[0-9.]*$/;
51
+ var SLICE_REGEX = new RegExp("^".concat(FLOAT_REGEX.source, ",").concat(FLOAT_REGEX.source, ",").concat(FLOAT_REGEX.source, "$"));
52
+
59
53
  /**
60
54
  * Matches a sequence of three comma-separated min:max number pairs, representing
61
55
  * the x, y, and z axes.
62
56
  */
63
- var REGION_REGEX = /^([0-9.]*:[0-9.]*)(,[0-9.]*:[0-9.]*){2}$/;
57
+ var REGION_REGEX = new RegExp("^(".concat(FLOAT_REGEX.source, ":").concat(FLOAT_REGEX.source, ")(,").concat(FLOAT_REGEX.source, ":").concat(FLOAT_REGEX.source, "){2}$"));
64
58
  var HEX_COLOR_REGEX = new RegExp("(([0-9a-fA-F]{6})|".concat(DEFAULT_CONTROL_POINT_COLOR_CODE, ")"));
65
- var NUMERIC_REGEX = /-?[0-9.]*/;
66
- var CONTROL_POINT_REGEX = new RegExp("(".concat(NUMERIC_REGEX.source, ":").concat(NUMERIC_REGEX.source, ":").concat(HEX_COLOR_REGEX.source, ")"));
59
+
60
+ /** Represents control points specified by bin indices. */
61
+ var CONTROL_POINT_REGEX = new RegExp("(".concat(FLOAT_REGEX.source, ":").concat(FLOAT_REGEX.source, ":").concat(HEX_COLOR_REGEX.source, ")"));
67
62
  var HEX_COLOR_STR_REGEX = new RegExp("^".concat(HEX_COLOR_REGEX.source, "$"));
68
63
 
69
64
  /**
70
65
  * LEGACY: Matches a COMMA-separated list of control points, where each control point is represented
71
66
  * by a triplet of `{x}:{opacity}:{hex color}`.
72
- * The hex color can be replaced with `w` to represent white (`ffffff`).
67
+ * The hex color can be replaced with `1` to represent white (`ffffff`).
73
68
  */
74
69
  export var LEGACY_CONTROL_POINTS_REGEX = new RegExp("^".concat(CONTROL_POINT_REGEX.source, "(,").concat(CONTROL_POINT_REGEX.source, ")*$"));
70
+
75
71
  /**
76
- * Matches a COLON-separated list of control points, where each control point is represented
77
- * by a triplet of `{x}:{opacity}:{hex color}`.
78
- * The hex color can be replaced with `w` to represent white (`ffffff`).
72
+ * Matches a COLON-separated list of control points, where each control point is
73
+ * represented by a triplet of `{x}:{opacity}:{hex color}`.
74
+ * - `x` is a value that will either be parsed as a histogram bin index (legacy,
75
+ * for `ControlPointsLegacy`) or intensity value (for `ControlPoints`),
76
+ * depending on on which field is being parsed.
77
+ * - Opacity is a float in the [0, 1] range.
78
+ * - The hex color is a 6-digit hex color (e.g. `ffeecc`), and can be replaced
79
+ * with `1` to represent white (`ffffff`).
79
80
  */
80
81
  export var CONTROL_POINTS_REGEX = new RegExp("^".concat(CONTROL_POINT_REGEX.source, "(:").concat(CONTROL_POINT_REGEX.source, ")*$"));
81
82
 
@@ -122,12 +123,15 @@ export var ViewerChannelSettingKeys = /*#__PURE__*/function (ViewerChannelSettin
122
123
  ViewerChannelSettingKeys["ColorizeAlpha"] = "cza";
123
124
  ViewerChannelSettingKeys["IsosurfaceAlpha"] = "isa";
124
125
  ViewerChannelSettingKeys["Lut"] = "lut";
125
- ViewerChannelSettingKeys["Ramp"] = "rmp";
126
- ViewerChannelSettingKeys["ControlPoints"] = "cps";
126
+ ViewerChannelSettingKeys["ControlPoints"] = "cpt";
127
+ ViewerChannelSettingKeys["ControlPointsLegacy"] = "cps";
128
+ ViewerChannelSettingKeys["Ramp"] = "ram";
129
+ ViewerChannelSettingKeys["RampLegacy"] = "rmp";
127
130
  ViewerChannelSettingKeys["ControlPointsEnabled"] = "cpe";
128
131
  ViewerChannelSettingKeys["VolumeEnabled"] = "ven";
129
132
  ViewerChannelSettingKeys["SurfaceEnabled"] = "sen";
130
133
  ViewerChannelSettingKeys["IsosurfaceValue"] = "isv";
134
+ ViewerChannelSettingKeys["KeepRange"] = "pin";
131
135
  return ViewerChannelSettingKeys;
132
136
  }({});
133
137
 
@@ -139,12 +143,15 @@ _ViewerChannelSetting2 = ViewerChannelSettingKeys.Colorize;
139
143
  _ViewerChannelSetting3 = ViewerChannelSettingKeys.ColorizeAlpha;
140
144
  _ViewerChannelSetting4 = ViewerChannelSettingKeys.IsosurfaceAlpha;
141
145
  _ViewerChannelSetting5 = ViewerChannelSettingKeys.Lut;
142
- _ViewerChannelSetting6 = ViewerChannelSettingKeys.ControlPoints;
143
- _ViewerChannelSetting7 = ViewerChannelSettingKeys.ControlPointsEnabled;
144
- _ViewerChannelSetting8 = ViewerChannelSettingKeys.Ramp;
145
- _ViewerChannelSetting9 = ViewerChannelSettingKeys.VolumeEnabled;
146
- _ViewerChannelSetting10 = ViewerChannelSettingKeys.SurfaceEnabled;
147
- _ViewerChannelSetting11 = ViewerChannelSettingKeys.IsosurfaceValue;
146
+ _ViewerChannelSetting6 = ViewerChannelSettingKeys.ControlPointsLegacy;
147
+ _ViewerChannelSetting7 = ViewerChannelSettingKeys.ControlPoints;
148
+ _ViewerChannelSetting8 = ViewerChannelSettingKeys.ControlPointsEnabled;
149
+ _ViewerChannelSetting9 = ViewerChannelSettingKeys.RampLegacy;
150
+ _ViewerChannelSetting10 = ViewerChannelSettingKeys.Ramp;
151
+ _ViewerChannelSetting11 = ViewerChannelSettingKeys.VolumeEnabled;
152
+ _ViewerChannelSetting12 = ViewerChannelSettingKeys.SurfaceEnabled;
153
+ _ViewerChannelSetting13 = ViewerChannelSettingKeys.IsosurfaceValue;
154
+ _ViewerChannelSetting14 = ViewerChannelSettingKeys.KeepRange;
148
155
  export var ViewerChannelSettingParams = /*#__PURE__*/_createClass(function ViewerChannelSettingParams() {
149
156
  _classCallCheck(this, ViewerChannelSettingParams);
150
157
  /** Color, as a 6-digit hex color. */
@@ -183,30 +190,53 @@ export var ViewerChannelSettingParams = /*#__PURE__*/_createClass(function Viewe
183
190
  */
184
191
  _defineProperty(this, _ViewerChannelSetting5, undefined);
185
192
  /**
186
- * Control points for the transfer function. If provided, overrides the
187
- * `lut` field when calculating the control points. Should be a list
188
- * of `x:opacity:color` triplets, separated by colon.
189
- * - `x` is a numeric intensity value.
193
+ * Legacy specifier for control points for the transfer function as a list of
194
+ * `x:opacity:color` triplets, separated by colon. Uses histogram bin indices
195
+ * instead of intensity values.
196
+ * - `x` is a histogram bin index in the [0, 255] range.
190
197
  * - `opacity` is a float in the [0, 1] range.
191
198
  * - `color` is a 6-digit hex color, e.g. `ff0000`.
199
+ *
200
+ * Will be overridden by the ControlPoints field (`cpt`) if provided.
192
201
  */
193
202
  _defineProperty(this, _ViewerChannelSetting6, undefined);
194
203
  /**
195
- * Whether to show advanced mode, which will show control points instead of
196
- * ramp values defined by the LUT. "1" is enabled, disabled by default.
204
+ * Control points for the transfer function, formatted as a list of
205
+ * `x:opacity:color` triplets, separated by colons.
206
+ * - `x` is a numeric intensity value.
207
+ * - `opacity` is a float in the [0, 1] range.
208
+ * - `color` is a 6-digit hex color, e.g. `ff0000`.
209
+ *
210
+ * If provided, overrides the `lut` field when calculating the control points.
197
211
  */
198
212
  _defineProperty(this, _ViewerChannelSetting7, undefined);
199
213
  /**
200
- * Raw ramp values, which should be two numeric values separated by a colon.
201
- * If provided, overrides the `lut` field when calculating the ramp values.
214
+ * Whether to show advanced mode, which will show control points instead of
215
+ * ramp values defined by the LUT. "1" is enabled, disabled by default.
202
216
  */
203
217
  _defineProperty(this, _ViewerChannelSetting8, undefined);
204
- /** Volume enabled. "1" is enabled. Disabled by default. */
218
+ /**
219
+ * Legacy specifier for the transfer function ramp which uses histogram bin
220
+ * indices instead of intensity values, formatted as `min:max`. Will be
221
+ * overridden by the Ramp field (`ram`) if provided.
222
+ */
205
223
  _defineProperty(this, _ViewerChannelSetting9, undefined);
206
- /** Isosurface enabled. "1" is enabled. Disabled by default. */
224
+ /**
225
+ * Ramp min and max intensity values (`min:max`). If provided, overrides the
226
+ * `lut` field when calculating the ramp.
227
+ */
207
228
  _defineProperty(this, _ViewerChannelSetting10, undefined);
208
- /** Isosurface value, in the [0, 255] range. Set to `128` by default. */
229
+ /** Volume enabled. "1" is enabled. Disabled by default. */
209
230
  _defineProperty(this, _ViewerChannelSetting11, undefined);
231
+ /** Isosurface enabled. "1" is enabled. Disabled by default. */
232
+ _defineProperty(this, _ViewerChannelSetting12, undefined);
233
+ /** Isosurface value, in the [0, 255] range. Set to `128` by default. */
234
+ _defineProperty(this, _ViewerChannelSetting13, undefined);
235
+ /**
236
+ * Whether to keep the current contrast settings when loading a new volume.
237
+ * "1" is enabled. Disabled by default.
238
+ */
239
+ _defineProperty(this, _ViewerChannelSetting14, undefined);
210
240
  });
211
241
  /**
212
242
  * Channels, matching the pattern `c0`, `c1`, etc. corresponding to the index of the channel being configured.
@@ -298,8 +328,15 @@ export var ViewerStateParams = /*#__PURE__*/_createClass(function ViewerStatePar
298
328
  var DataParams = /*#__PURE__*/_createClass(function DataParams() {
299
329
  _classCallCheck(this, DataParams);
300
330
  /**
301
- * One or more volume URLs to load. If multiple URLs are provided, they should
302
- * be separated by commas.
331
+ * One or more volume URLs to load.
332
+ *
333
+ * This parameter may represent a single image with multiple data sources by delimiting each source URL with `,`.
334
+ * It may also represent multiple scenes by delimiting each scene URL (and/or each collection of multiple
335
+ * `,`-delimited source URLs) with `+`. E.g. `url1+url2,url3` represents a collection of two scenes, where the first
336
+ * scene comes from `url1` and the second is a combination of the channels from the images at `url2` and `url3`.
337
+ *
338
+ * When parsing, we do our best to account for `%`-encoding, including the possibility that each source/scene URL was
339
+ * encoded separately, then concatenated with the proper delimiters, then encoded again.
303
340
  */
304
341
  _defineProperty(this, "url", undefined);
305
342
  /**
@@ -310,14 +347,24 @@ var DataParams = /*#__PURE__*/_createClass(function DataParams() {
310
347
  * See `ManifestJson` for the type definition.
311
348
  */
312
349
  _defineProperty(this, "manifest", undefined);
313
- /**
314
- * The name of a dataset in the Cell Feature Explorer database. Used with `id`.
315
- */
350
+ /** The name of a dataset in the Cell Feature Explorer database. Used with `id`. */
316
351
  _defineProperty(this, "dataset", undefined);
352
+ /** The ID of a cell within the loaded dataset. Used with `dataset`. */
353
+ _defineProperty(this, "id", undefined);
354
+ /** The key of a collection of scenes stored in local storage. Overrides `url`. */
355
+ _defineProperty(this, "collectionid", undefined);
317
356
  /**
318
- * The ID of a cell within the loaded dataset. Used with `dataset`.
357
+ * The origin of an opening window that wants to send a message to this window.
358
+ *
359
+ * The presence of this param implies that this window has just been opened by another app, and the opening app has
360
+ * more data to send. Until that message is received, we fall back to `url`. Once that message arrives, the scenes to
361
+ * open are written to local storage at a new `collectionid` and `msgorigin` is removed, allowing the window to
362
+ * switch to reading local storage.
363
+ *
364
+ * All this happens independently of URL parsing, so the only meaningful thing this parsing code does with this param
365
+ * is check whether it is present.
319
366
  */
320
- _defineProperty(this, "id", undefined);
367
+ _defineProperty(this, "msgorigin", undefined);
321
368
  });
322
369
  var DeprecatedParams = /*#__PURE__*/_createClass(function DeprecatedParams() {
323
370
  _classCallCheck(this, DeprecatedParams);
@@ -328,6 +375,10 @@ var DeprecatedParams = /*#__PURE__*/_createClass(function DeprecatedParams() {
328
375
  /** Deprecated query parameter for channel colors. */
329
376
  _defineProperty(this, "colors", undefined);
330
377
  });
378
+ /**
379
+ * A message sent from an external application after this app was opened,
380
+ * containing data that was too large to pack into the URL.
381
+ */
331
382
  var allowedParamKeys = [].concat(_toConsumableArray(Object.keys(new ViewerStateParams())), _toConsumableArray(Object.keys(new DataParams())), _toConsumableArray(Object.keys(new DeprecatedParams())));
332
383
  var isParamKey = function isParamKey(key) {
333
384
  return allowedParamKeys.indexOf(key) !== -1;
@@ -362,39 +413,63 @@ export function getAllowedParams(searchParams) {
362
413
  }
363
414
  return result;
364
415
  }
365
- var decodeURL = function decodeURL(url) {
366
- var decodedUrl = decodeURIComponent(url);
367
- return decodedUrl.endsWith("/") ? decodedUrl.slice(0, -1) : decodedUrl;
368
- };
369
416
 
370
- /** Try to parse a `string` as a list of 2 or more URLs. Returns `undefined` if the string is not a valid URL list. */
371
- var tryDecodeURLList = function tryDecodeURLList(url) {
372
- var delim = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ",";
373
- if (typeof delim === "string" ? !url.includes(delim) : !delim.test(url)) {
374
- return undefined;
375
- }
376
- var urls = url.split(delim).map(function (u) {
377
- return decodeURL(u);
417
+ /** Tries to retrieve the given `param` from a `search` string without using `URLSearchParams`, to avoid decoding. */
418
+ var getSearchParamRaw = function getSearchParamRaw(search, param) {
419
+ var trimmedSearch = search.startsWith("?") ? search.slice(1) : search;
420
+ var entries = trimmedSearch.split("&");
421
+ var key = param + "=";
422
+ var foundKeyValue = entries.find(function (keyValue) {
423
+ return keyValue.startsWith(key);
378
424
  });
425
+ return foundKeyValue === null || foundKeyValue === void 0 ? void 0 : foundKeyValue.slice(key.length);
426
+ };
379
427
 
380
- // Verify that all urls are valid
381
- var _iterator2 = _createForOfIteratorHelper(urls),
382
- _step2;
383
- try {
384
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
385
- var u = _step2.value;
386
- try {
387
- new URL(u);
388
- } catch (_e) {
389
- return undefined;
428
+ /**
429
+ * Applies `decodeURIComponent` over and over until `url` either seems to be a valid `URL` or satisfies `condition`.
430
+ */
431
+ var decodeURLUntilParseable = function decodeURLUntilParseable(url) {
432
+ var condition = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (_url) {
433
+ return false;
434
+ };
435
+ var decoded = url;
436
+ while (!condition(decoded) && !URL.canParse(decoded)) {
437
+ try {
438
+ var nextDecoded = decodeURIComponent(decoded);
439
+ if (nextDecoded === decoded) {
440
+ return decoded;
390
441
  }
442
+ decoded = nextDecoded;
443
+ } catch (_unused) {
444
+ return decoded;
391
445
  }
392
- } catch (err) {
393
- _iterator2.e(err);
394
- } finally {
395
- _iterator2.f();
396
446
  }
397
- return urls;
447
+ return decoded;
448
+ };
449
+
450
+ /** Parses the `url` query param into a 2D URL array: one or more scenes, with one or more sources per scene. */
451
+ export var parseImageURLParam = function parseImageURLParam(urlParam) {
452
+ // Decode until either any valid delimiters appear or `urlParam` is parseable as a single URL.
453
+ var decodedScenes = decodeURLUntilParseable(urlParam, function (url) {
454
+ return /[+ ,]/.test(url);
455
+ });
456
+ // Split into scene URLs.
457
+ var sceneUrls = decodedScenes.split(/[+ ]/);
458
+ return sceneUrls.map(function (scene) {
459
+ // Split each scene into multiple sources, if any.
460
+ var decodedSources = decodeURLUntilParseable(scene, function (url) {
461
+ return url.includes(",");
462
+ });
463
+ var sourceUrls = decodedSources.split(",");
464
+ if (sourceUrls.length === 1) {
465
+ return sourceUrls;
466
+ }
467
+
468
+ // Try to make sure the source URLs are decoded as well.
469
+ return sourceUrls.map(function (source) {
470
+ return decodeURLUntilParseable(source);
471
+ });
472
+ });
398
473
  };
399
474
 
400
475
  //// DATA PARSING //////////////////////
@@ -415,20 +490,20 @@ export function parseKeyValueList(data) {
415
490
  }
416
491
  var result = {};
417
492
  var keyValuePairs = data.split(",");
418
- var _iterator3 = _createForOfIteratorHelper(keyValuePairs),
419
- _step3;
493
+ var _iterator2 = _createForOfIteratorHelper(keyValuePairs),
494
+ _step2;
420
495
  try {
421
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
422
- var pair = _step3.value;
496
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
497
+ var pair = _step2.value;
423
498
  var splitIndex = pair.indexOf(":");
424
499
  var key = pair.slice(0, splitIndex);
425
500
  var value = pair.slice(splitIndex + 1);
426
501
  result[decodeURIComponent(key).trim()] = decodeURIComponent(value).trim();
427
502
  }
428
503
  } catch (err) {
429
- _iterator3.e(err);
504
+ _iterator2.e(err);
430
505
  } finally {
431
- _iterator3.f();
506
+ _iterator2.f();
432
507
  }
433
508
  return result;
434
509
  }
@@ -723,22 +798,22 @@ function parseControlPoints(controlPoints) {
723
798
  }
724
799
 
725
800
  // Parse raw control point data from the string into an array of [x, opacity, color] triplets.
726
- var rawControlPointData;
801
+ var controlPointStrings;
727
802
  if (LEGACY_CONTROL_POINTS_REGEX.test(controlPoints)) {
728
803
  // Legacy format uses commas to separate control points.
729
- rawControlPointData = controlPoints.split(",").map(function (cp) {
804
+ controlPointStrings = controlPoints.split(",").map(function (cp) {
730
805
  return cp.split(":");
731
806
  });
732
807
  } else {
733
808
  // New format is all colon-separated, where every three elements represent a control point.
734
- rawControlPointData = controlPoints.split(":").reduce(function (acc, _val, i, array) {
809
+ controlPointStrings = controlPoints.split(":").reduce(function (acc, _val, i, array) {
735
810
  if ((i + 1) % 3 === 0) {
736
811
  acc.push([array[i - 2], array[i - 1], array[i]]);
737
812
  }
738
813
  return acc;
739
814
  }, []);
740
815
  }
741
- var newControlPoints = rawControlPointData.map(function (cp) {
816
+ var newControlPoints = controlPointStrings.map(function (cp) {
742
817
  var _parseStringFloat, _parseStringFloat2, _parseHexColorAsColor;
743
818
  var _cp = _slicedToArray(cp, 3),
744
819
  x = _cp[0],
@@ -770,7 +845,8 @@ export function deserializeViewerChannelSetting(channelIndex, jsonState) {
770
845
  match: channelIndex,
771
846
  enabled: parseStringBoolean(jsonState[ViewerChannelSettingKeys.VolumeEnabled]),
772
847
  surfaceEnabled: parseStringBoolean(jsonState[ViewerChannelSettingKeys.SurfaceEnabled]),
773
- isovalue: parseStringFloat(jsonState[ViewerChannelSettingKeys.IsosurfaceValue], 0, 255),
848
+ isovalue: parseStringFloat(jsonState[ViewerChannelSettingKeys.IsosurfaceValue], -Infinity, Infinity),
849
+ keepIntensityRange: parseStringBoolean(jsonState[ViewerChannelSettingKeys.KeepRange]),
774
850
  surfaceOpacity: parseStringFloat(jsonState[ViewerChannelSettingKeys.IsosurfaceAlpha], 0, 1),
775
851
  colorizeEnabled: parseStringBoolean(jsonState[ViewerChannelSettingKeys.Colorize]),
776
852
  colorizeAlpha: parseStringFloat(jsonState[ViewerChannelSettingKeys.ColorizeAlpha], 0, 1),
@@ -784,17 +860,41 @@ export function deserializeViewerChannelSetting(channelIndex, jsonState) {
784
860
  _jsonState$ViewerChan2 = _slicedToArray(_jsonState$ViewerChan, 2),
785
861
  min = _jsonState$ViewerChan2[0],
786
862
  max = _jsonState$ViewerChan2[1];
787
- result.lut = [min.trim(), max.trim()];
863
+ result.intensity = _objectSpread(_objectSpread({}, result.intensity), {}, {
864
+ lut: [min.trim(), max.trim()]
865
+ });
788
866
  }
789
- if (jsonState[ViewerChannelSettingKeys.Ramp] && RAMP_REGEX.test(jsonState.rmp)) {
790
- var _jsonState$ViewerChan3 = jsonState[ViewerChannelSettingKeys.Ramp].split(":"),
791
- _jsonState$ViewerChan4 = _slicedToArray(_jsonState$ViewerChan3, 2),
792
- _min = _jsonState$ViewerChan4[0],
793
- _max = _jsonState$ViewerChan4[1];
794
- result.ramp = [Number.parseFloat(_min), Number.parseFloat(_max)];
867
+ if (jsonState[ViewerChannelSettingKeys.Ramp]) {
868
+ if (RAMP_REGEX.test(jsonState[ViewerChannelSettingKeys.Ramp])) {
869
+ var _jsonState$ViewerChan3 = jsonState[ViewerChannelSettingKeys.Ramp].split(":"),
870
+ _jsonState$ViewerChan4 = _slicedToArray(_jsonState$ViewerChan3, 2),
871
+ _min = _jsonState$ViewerChan4[0],
872
+ _max = _jsonState$ViewerChan4[1];
873
+ result.intensity = _objectSpread(_objectSpread({}, result.intensity), {}, {
874
+ ramp: [Number.parseFloat(_min), Number.parseFloat(_max)]
875
+ });
876
+ }
877
+ } else if (jsonState[ViewerChannelSettingKeys.RampLegacy]) {
878
+ if (RAMP_REGEX.test(jsonState[ViewerChannelSettingKeys.RampLegacy])) {
879
+ var _jsonState$ViewerChan5 = jsonState[ViewerChannelSettingKeys.RampLegacy].split(":"),
880
+ _jsonState$ViewerChan6 = _slicedToArray(_jsonState$ViewerChan5, 2),
881
+ _min2 = _jsonState$ViewerChan6[0],
882
+ _max2 = _jsonState$ViewerChan6[1];
883
+ result.ramp = [Number.parseFloat(_min2), Number.parseFloat(_max2)];
884
+ }
795
885
  }
796
886
  if (jsonState[ViewerChannelSettingKeys.ControlPoints]) {
797
- result.controlPoints = parseControlPoints(jsonState[ViewerChannelSettingKeys.ControlPoints]);
887
+ var parsedResult = parseControlPoints(jsonState[ViewerChannelSettingKeys.ControlPoints]);
888
+ if (parsedResult) {
889
+ result.intensity = _objectSpread(_objectSpread({}, result.intensity), {}, {
890
+ controlPoints: parsedResult
891
+ });
892
+ }
893
+ } else if (jsonState[ViewerChannelSettingKeys.ControlPointsLegacy]) {
894
+ var _parsedResult = parseControlPoints(jsonState[ViewerChannelSettingKeys.ControlPointsLegacy]);
895
+ if (_parsedResult) {
896
+ result.controlPoints = _parsedResult;
897
+ }
798
898
  }
799
899
  return result;
800
900
  }
@@ -807,13 +907,11 @@ export function deserializeViewerChannelSetting(channelIndex, jsonState) {
807
907
  * @returns A `ViewerChannelSettingParams` object with the serialized parameters. Undefined values are removed.
808
908
  */
809
909
  export function serializeViewerChannelSetting(channelSetting, removeDefaults) {
810
- var _channelSetting$isova, _channelSetting$opaci, _channelSetting$color, _channelSetting$ramp;
910
+ var _channelSetting$isova, _channelSetting$opaci, _channelSetting$color, _channelSetting$ramp, _removeUndefinedPrope;
811
911
  if (removeDefaults) {
812
912
  channelSetting = removeMatchingProperties(channelSetting, getDefaultChannelState());
813
913
  }
814
- return removeUndefinedProperties(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, ViewerChannelSettingKeys.VolumeEnabled, serializeBoolean(channelSetting.volumeEnabled)), ViewerChannelSettingKeys.SurfaceEnabled, serializeBoolean(channelSetting.isosurfaceEnabled)), ViewerChannelSettingKeys.IsosurfaceValue, (_channelSetting$isova = channelSetting.isovalue) === null || _channelSetting$isova === void 0 ? void 0 : _channelSetting$isova.toString()), ViewerChannelSettingKeys.IsosurfaceAlpha, (_channelSetting$opaci = channelSetting.opacity) === null || _channelSetting$opaci === void 0 ? void 0 : _channelSetting$opaci.toString()), ViewerChannelSettingKeys.Colorize, serializeBoolean(channelSetting.colorizeEnabled)), ViewerChannelSettingKeys.ColorizeAlpha, (_channelSetting$color = channelSetting.colorizeAlpha) === null || _channelSetting$color === void 0 ? void 0 : _channelSetting$color.toString()), ViewerChannelSettingKeys.Color, channelSetting.color && colorArrayToHex(channelSetting.color)), ViewerChannelSettingKeys.ControlPoints, channelSetting.controlPoints && serializeControlPoints(channelSetting.controlPoints)), ViewerChannelSettingKeys.ControlPointsEnabled, serializeBoolean(channelSetting.useControlPoints)), ViewerChannelSettingKeys.Ramp, (_channelSetting$ramp = channelSetting.ramp) === null || _channelSetting$ramp === void 0 ? void 0 : _channelSetting$ramp.map(function (value) {
815
- return formatFloat(value);
816
- }).join(":")));
914
+ return removeUndefinedProperties((_removeUndefinedPrope = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_removeUndefinedPrope, ViewerChannelSettingKeys.VolumeEnabled, serializeBoolean(channelSetting.volumeEnabled)), ViewerChannelSettingKeys.SurfaceEnabled, serializeBoolean(channelSetting.isosurfaceEnabled)), ViewerChannelSettingKeys.IsosurfaceValue, (_channelSetting$isova = channelSetting.isovalue) === null || _channelSetting$isova === void 0 ? void 0 : _channelSetting$isova.toString()), ViewerChannelSettingKeys.IsosurfaceAlpha, (_channelSetting$opaci = channelSetting.opacity) === null || _channelSetting$opaci === void 0 ? void 0 : _channelSetting$opaci.toString()), ViewerChannelSettingKeys.Colorize, serializeBoolean(channelSetting.colorizeEnabled)), ViewerChannelSettingKeys.ColorizeAlpha, (_channelSetting$color = channelSetting.colorizeAlpha) === null || _channelSetting$color === void 0 ? void 0 : _channelSetting$color.toString()), ViewerChannelSettingKeys.Color, channelSetting.color && colorArrayToHex(channelSetting.color)), ViewerChannelSettingKeys.ControlPoints, channelSetting.controlPoints && serializeControlPoints(channelSetting.controlPoints)), ViewerChannelSettingKeys.ControlPointsEnabled, serializeBoolean(channelSetting.useControlPoints)), ViewerChannelSettingKeys.Ramp, (_channelSetting$ramp = channelSetting.ramp) === null || _channelSetting$ramp === void 0 ? void 0 : _channelSetting$ramp.join(":")), _defineProperty(_removeUndefinedPrope, ViewerChannelSettingKeys.KeepRange, serializeBoolean(channelSetting.keepIntensityRange))));
817
915
  }
818
916
  export function deserializeViewerState(params) {
819
917
  var result = {
@@ -957,7 +1055,7 @@ function loadDataset(_x, _x2, _x3) {
957
1055
  }
958
1056
  function _loadDataset() {
959
1057
  _loadDataset = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(firestore, dataset, id) {
960
- var db, args, datasets, datasetMeta, _iterator4, _step4, d, innerDatasets, names, matchingName, datasetData, baseUrl, fileInfo;
1058
+ var db, args, datasets, datasetMeta, _iterator3, _step3, d, innerDatasets, names, matchingName, datasetData, baseUrl, fileInfo;
961
1059
  return _regeneratorRuntime().wrap(function _callee$(_context) {
962
1060
  while (1) switch (_context.prev = _context.next) {
963
1061
  case 0:
@@ -968,15 +1066,15 @@ function _loadDataset() {
968
1066
  case 4:
969
1067
  datasets = _context.sent;
970
1068
  datasetMeta = undefined;
971
- _iterator4 = _createForOfIteratorHelper(datasets);
1069
+ _iterator3 = _createForOfIteratorHelper(datasets);
972
1070
  _context.prev = 7;
973
- _iterator4.s();
1071
+ _iterator3.s();
974
1072
  case 9:
975
- if ((_step4 = _iterator4.n()).done) {
1073
+ if ((_step3 = _iterator3.n()).done) {
976
1074
  _context.next = 19;
977
1075
  break;
978
1076
  }
979
- d = _step4.value;
1077
+ d = _step3.value;
980
1078
  innerDatasets = d.datasets;
981
1079
  names = Object.keys(innerDatasets);
982
1080
  matchingName = names.find(function (name) {
@@ -997,10 +1095,10 @@ function _loadDataset() {
997
1095
  case 21:
998
1096
  _context.prev = 21;
999
1097
  _context.t0 = _context["catch"](7);
1000
- _iterator4.e(_context.t0);
1098
+ _iterator3.e(_context.t0);
1001
1099
  case 24:
1002
1100
  _context.prev = 24;
1003
- _iterator4.f();
1101
+ _iterator3.f();
1004
1102
  return _context.finish(24);
1005
1103
  case 27:
1006
1104
  if (!(datasetMeta === undefined)) {
@@ -1048,16 +1146,14 @@ export function loadFromManifest(_x4) {
1048
1146
 
1049
1147
  /**
1050
1148
  * Parses a set of URL search parameters into props for the viewer.
1051
- * @param urlSearchParams The URLSearchParams object to parse.
1052
- * @param firestore Optional Firestore instance. If provided, the function can
1053
- * load data from a Firestore dataset if the `dataset` and `id` parameters are
1054
- * provided.
1149
+ * @param search The query string to parse, which must be valid in the `URLSearchParams constructor
1150
+ * @param firestore Optional Firestore instance. If provided, the function can load data from a
1151
+ * Firestore dataset if the `dataset` and `id` parameters are provided.
1055
1152
  * @returns An object containing:
1056
1153
  * - `args`: Partial AppProps object.
1057
1154
  * - `viewerSettings`: Partial ViewerState object.
1058
1155
  *
1059
- * `args` can be passed as props to the `ImageViewerApp`, and `viewerSettings`
1060
- * can be passed to `ViewerStateProvider`.
1156
+ * `args` can be passed as props to the `ImageViewerApp`, and `viewerSettings` can be passed to `ViewerStateProvider`.
1061
1157
  */
1062
1158
  function _loadFromManifest() {
1063
1159
  _loadFromManifest = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(manifestUrl) {
@@ -1134,19 +1230,15 @@ export function parseViewerUrlParams(_x5, _x6) {
1134
1230
  return _parseViewerUrlParams.apply(this, arguments);
1135
1231
  }
1136
1232
 
1137
- /**
1138
- * Serializes the ViewerState and ChannelState of a ViewerStateContext into a URLSearchParams object.
1139
- * @param state ViewerStateContext to serialize.
1140
- * @param removeDefaults If true, shortens parameters by removing any properties that match the default state.
1141
- * This includes the output of GET_DEFAULT_VIEWER_STATE and GET_DEFAULT_CHANNEL_STATE.
1142
- */
1233
+ /** Adds the data in a newly-arrived `ViewerMessage` to an existing stored `AppProps` instance. */
1143
1234
  function _parseViewerUrlParams() {
1144
- _parseViewerUrlParams = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(urlSearchParams, firestore) {
1145
- var params, args, viewerSettings, deprecatedChannelSettings, channelSettings, scenes, _yield$loadFromManife, manifestScenes, manifestMetadata, _localStorage$getItem, _tryDecodeURLList, getFromStorage, urlParam, sceneUrls, metadataJson, firstScene, firstUrl, imageUrls, datasetArgs;
1235
+ _parseViewerUrlParams = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(search, firestore) {
1236
+ var searchParams, params, args, viewerSettings, deprecatedChannelSettings, channelSettings, scenes, _yield$loadFromManife, manifestScenes, manifestMetadata, collectionid, msgorigin, getFromStorage, urlParamFromStorage, urlParam, firstScene, firstUrl, imageUrls, datasetArgs;
1146
1237
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
1147
1238
  while (1) switch (_context3.prev = _context3.next) {
1148
1239
  case 0:
1149
- params = getAllowedParams(urlSearchParams);
1240
+ searchParams = new URLSearchParams(search);
1241
+ params = getAllowedParams(searchParams);
1150
1242
  args = {}; // Parse viewer state
1151
1243
  viewerSettings = deserializeViewerState(params); // Parse channel settings. If per-channel settings are provided, they will override
1152
1244
  // the old `ch` query parameter.
@@ -1155,38 +1247,33 @@ function _parseViewerUrlParams() {
1155
1247
  args.viewerChannelSettings = channelSettings !== null && channelSettings !== void 0 ? channelSettings : deprecatedChannelSettings;
1156
1248
 
1157
1249
  // Parse data sources (URL or dataset/id pair)
1158
- if (!(params.manifest !== undefined || params.url !== undefined)) {
1159
- _context3.next = 33;
1250
+ if (!(params.manifest !== undefined || params.url !== undefined || params.collectionid !== undefined)) {
1251
+ _context3.next = 35;
1160
1252
  break;
1161
1253
  }
1162
1254
  if (!params.manifest) {
1163
- _context3.next = 17;
1255
+ _context3.next = 18;
1164
1256
  break;
1165
1257
  }
1166
- _context3.next = 10;
1258
+ _context3.next = 11;
1167
1259
  return loadFromManifest(params.manifest);
1168
- case 10:
1260
+ case 11:
1169
1261
  _yield$loadFromManife = _context3.sent;
1170
1262
  manifestScenes = _yield$loadFromManife.scenes;
1171
1263
  manifestMetadata = _yield$loadFromManife.metadata;
1172
1264
  scenes = manifestScenes;
1173
1265
  args.metadata = manifestMetadata !== null && manifestMetadata !== void 0 ? manifestMetadata : undefined;
1174
- _context3.next = 22;
1266
+ _context3.next = 24;
1175
1267
  break;
1176
- case 17:
1177
- // Load from URL
1178
- getFromStorage = params.url === URL_FETCH_FROM_STORAGE;
1179
- urlParam = getFromStorage ? (_localStorage$getItem = localStorage.getItem("url")) !== null && _localStorage$getItem !== void 0 ? _localStorage$getItem : params.url : params.url; // split encoded url into a list of one or more scenes...
1180
- sceneUrls = (_tryDecodeURLList = tryDecodeURLList(urlParam, /[+ ]/)) !== null && _tryDecodeURLList !== void 0 ? _tryDecodeURLList : [urlParam]; // ...and each scene into a list of multiple sources, if any.
1181
- scenes = sceneUrls.map(function (scene) {
1182
- var _tryDecodeURLList2;
1183
- return (_tryDecodeURLList2 = tryDecodeURLList(scene)) !== null && _tryDecodeURLList2 !== void 0 ? _tryDecodeURLList2 : decodeURL(scene);
1184
- });
1185
- if (getFromStorage) {
1186
- metadataJson = localStorage.getItem("meta");
1187
- args.metadata = metadataJson !== null ? JSON.parse(metadataJson) : undefined;
1188
- }
1189
- case 22:
1268
+ case 18:
1269
+ // Load from URL or storage
1270
+ collectionid = params.collectionid, msgorigin = params.msgorigin;
1271
+ getFromStorage = collectionid !== undefined && msgorigin === undefined;
1272
+ urlParamFromStorage = getFromStorage ? readStoredScenes(collectionid) : undefined;
1273
+ urlParam = urlParamFromStorage !== null && urlParamFromStorage !== void 0 ? urlParamFromStorage : getSearchParamRaw(search, "url");
1274
+ scenes = parseImageURLParam(urlParam);
1275
+ args.metadata = readStoredMetadata(scenes);
1276
+ case 24:
1190
1277
  firstScene = scenes[0]; // Get the very first URL for the download button
1191
1278
  firstUrl = Array.isArray(firstScene) ? firstScene[0] : firstScene; // If there's only one url, just pass that
1192
1279
  imageUrls = scenes.length > 1 || firstScene.length > 1 ? {
@@ -1217,24 +1304,24 @@ function _parseViewerUrlParams() {
1217
1304
  }]
1218
1305
  };
1219
1306
  }
1220
- _context3.next = 38;
1307
+ _context3.next = 40;
1221
1308
  break;
1222
- case 33:
1309
+ case 35:
1223
1310
  if (!(params.dataset && params.id && firestore)) {
1224
- _context3.next = 38;
1311
+ _context3.next = 40;
1225
1312
  break;
1226
1313
  }
1227
- _context3.next = 36;
1314
+ _context3.next = 38;
1228
1315
  return loadDataset(firestore, params.dataset, params.id);
1229
- case 36:
1316
+ case 38:
1230
1317
  datasetArgs = _context3.sent;
1231
1318
  args = _objectSpread(_objectSpread({}, args), datasetArgs);
1232
- case 38:
1319
+ case 40:
1233
1320
  return _context3.abrupt("return", {
1234
1321
  args: removeUndefinedProperties(args),
1235
1322
  viewerSettings: removeUndefinedProperties(viewerSettings)
1236
1323
  });
1237
- case 39:
1324
+ case 41:
1238
1325
  case "end":
1239
1326
  return _context3.stop();
1240
1327
  }
@@ -1242,6 +1329,44 @@ function _parseViewerUrlParams() {
1242
1329
  }));
1243
1330
  return _parseViewerUrlParams.apply(this, arguments);
1244
1331
  }
1332
+ export function addViewerParamsFromMessage(args, message) {
1333
+ var _message$scenes;
1334
+ // get scenes
1335
+ var imageUrl = args.imageUrl;
1336
+ var scenes = (_message$scenes = message.scenes) !== null && _message$scenes !== void 0 ? _message$scenes : typeof imageUrl === "string" ? [imageUrl] : imageUrl.scenes;
1337
+ var firstScene = scenes[0];
1338
+ var newImageUrl = scenes.length === 1 && typeof firstScene === "string" ? firstScene : {
1339
+ scenes: scenes
1340
+ };
1341
+
1342
+ // get metadata
1343
+ var meta = message.meta;
1344
+ var messageMeta = meta && scenes.map(function (scene) {
1345
+ if (Array.isArray(scene)) {
1346
+ // can't handle multi-source scenes (yet)
1347
+ return undefined;
1348
+ }
1349
+ return meta[scene];
1350
+ });
1351
+ var newMetadata = messageMeta !== null && messageMeta !== void 0 ? messageMeta : args.metadata;
1352
+ if (newMetadata === undefined) {
1353
+ return _objectSpread(_objectSpread({}, args), {}, {
1354
+ imageUrl: newImageUrl
1355
+ });
1356
+ } else {
1357
+ return _objectSpread(_objectSpread({}, args), {}, {
1358
+ imageUrl: newImageUrl,
1359
+ metadata: newMetadata
1360
+ });
1361
+ }
1362
+ }
1363
+
1364
+ /**
1365
+ * Serializes the ViewerState and ChannelState of a ViewerStateContext into a URLSearchParams object.
1366
+ * @param state ViewerStateContext to serialize.
1367
+ * @param removeDefaults If true, shortens parameters by removing any properties that match the default state.
1368
+ * This includes the output of GET_DEFAULT_VIEWER_STATE and GET_DEFAULT_CHANNEL_STATE.
1369
+ */
1245
1370
  export function serializeViewerUrlParams(state) {
1246
1371
  var _state$channelSetting;
1247
1372
  var removeDefaults = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;