@aics/vole-app 3.4.4 → 3.6.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/es/aics-image-viewer/components/App/index.js +15 -5
- package/es/aics-image-viewer/components/ChannelsWidget.js +3 -1
- package/es/aics-image-viewer/components/ChannelsWidgetRow.js +29 -16
- package/es/aics-image-viewer/components/ColorPicker/index.js +9 -1
- package/es/aics-image-viewer/components/ControlPanel/CopySettingsButton.js +445 -0
- package/es/aics-image-viewer/components/ControlPanel/index.js +16 -5
- package/es/aics-image-viewer/components/ControlPanel/styles.css +29 -2
- package/es/aics-image-viewer/components/StyleProvider/index.js +17 -2
- package/es/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.js +1 -1
- package/es/aics-image-viewer/components/Toolbar/index.js +1 -1
- package/es/aics-image-viewer/components/Toolbar/styles.css +0 -10
- package/es/aics-image-viewer/components/{CellViewerCanvasWrapper → ViewerCanvasWrapper}/index.js +3 -2
- package/es/aics-image-viewer/components/dimension_sliders/AxisClipSliders.js +21 -8
- package/es/aics-image-viewer/components/dimension_sliders/RotationSliders.js +6 -8
- package/es/aics-image-viewer/components/dimension_sliders/SliderRows.js +8 -6
- package/es/aics-image-viewer/components/shared/ContextualAlert.js +101 -0
- package/es/aics-image-viewer/components/shared/ControlPanelRow/index.js +4 -2
- package/es/aics-image-viewer/components/shared/ControlPanelRow/styles.css +4 -3
- package/es/aics-image-viewer/components/useVolume.js +59 -25
- package/es/aics-image-viewer/shared/constants.js +25 -1
- package/es/aics-image-viewer/shared/types.js +1 -1
- package/es/aics-image-viewer/shared/utils/controlPointsToLut.js +4 -0
- package/es/aics-image-viewer/shared/utils/parseSnapshot.js +205 -0
- package/es/aics-image-viewer/shared/utils/{urlParsing.js → parseUrl.js} +55 -191
- package/es/aics-image-viewer/shared/utils/permissions.js +46 -0
- package/es/aics-image-viewer/shared/utils/test/camera.test.js +1 -2
- package/es/aics-image-viewer/shared/utils/test/{urlParsing.test.js → parseUrl.test.js} +28 -25
- package/es/aics-image-viewer/shared/utils/test/storage.test.js +2 -2
- package/es/aics-image-viewer/shared/utils/test/viewerChannelSettings.test.js +1 -1
- package/es/aics-image-viewer/state/deserialize.js +443 -331
- package/es/aics-image-viewer/state/reset.js +1 -1
- package/es/aics-image-viewer/state/serialize.js +168 -78
- package/es/aics-image-viewer/state/subscribers.js +1 -1
- package/es/aics-image-viewer/state/test/deserialize.test.js +63 -77
- package/es/aics-image-viewer/state/test/reset.test.js +2 -2
- package/es/aics-image-viewer/state/test/serialize.test.js +42 -43
- package/es/aics-image-viewer/state/test/test_data.js +119 -1
- package/es/aics-image-viewer/state/types.js +157 -245
- package/es/aics-image-viewer/state/util.js +39 -1
- package/es/index.js +4 -2
- package/package.json +26 -44
- package/type-declarations/aics-image-viewer/components/App/types.d.ts +3 -3
- package/type-declarations/aics-image-viewer/components/ChannelsWidget.d.ts +3 -0
- package/type-declarations/aics-image-viewer/components/ChannelsWidgetRow.d.ts +3 -0
- package/type-declarations/aics-image-viewer/components/ControlPanel/CopySettingsButton.d.ts +11 -0
- package/type-declarations/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.d.ts +1 -1
- package/type-declarations/aics-image-viewer/components/{CellViewerCanvasWrapper → ViewerCanvasWrapper}/index.d.ts +4 -3
- package/type-declarations/aics-image-viewer/components/dimension_sliders/AxisClipSliders.d.ts +7 -6
- package/type-declarations/aics-image-viewer/components/dimension_sliders/SliderRows.d.ts +1 -2
- package/type-declarations/aics-image-viewer/components/shared/ContextualAlert.d.ts +29 -0
- package/type-declarations/aics-image-viewer/components/shared/ControlPanelRow/index.d.ts +1 -0
- package/type-declarations/aics-image-viewer/components/useVolume.d.ts +3 -0
- package/type-declarations/aics-image-viewer/shared/constants.d.ts +2 -2
- package/type-declarations/aics-image-viewer/shared/types.d.ts +2 -2
- package/type-declarations/aics-image-viewer/shared/utils/controlPointsToLut.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/utils/parseSnapshot.d.ts +49 -0
- package/type-declarations/aics-image-viewer/shared/utils/{urlParsing.d.ts → parseUrl.d.ts} +3 -24
- package/type-declarations/aics-image-viewer/shared/utils/permissions.d.ts +7 -0
- package/type-declarations/aics-image-viewer/shared/utils/viewerChannelSettings.d.ts +1 -1
- package/type-declarations/aics-image-viewer/state/deserialize.d.ts +70 -35
- package/type-declarations/aics-image-viewer/state/reset.d.ts +1 -1
- package/type-declarations/aics-image-viewer/state/serialize.d.ts +44 -10
- package/type-declarations/aics-image-viewer/state/types.d.ts +265 -159
- package/type-declarations/aics-image-viewer/state/util.d.ts +3 -1
- package/type-declarations/index.d.ts +5 -3
- package/es/Globals.d.js +0 -0
- package/es/aics-image-viewer/shared/enums.js +0 -18
- package/es/aics-image-viewer/shared/utils/firebase/index.js +0 -109
- package/type-declarations/aics-image-viewer/shared/enums.d.ts +0 -15
- package/type-declarations/aics-image-viewer/shared/utils/firebase/index.d.ts +0 -69
- package/type-declarations/aics-image-viewer/shared/utils/math.d.ts +0 -1
- /package/es/aics-image-viewer/components/{CellViewerCanvasWrapper → ViewerCanvasWrapper}/styles.css +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
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
1
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
2
|
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; }
|
|
3
|
+
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); }
|
|
4
4
|
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
5
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
6
6
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
@@ -11,34 +11,19 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
|
11
11
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
12
12
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
13
13
|
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; }
|
|
14
|
-
import {
|
|
14
|
+
import { clamp, identity } from "lodash";
|
|
15
15
|
import { controlPointsToRamp, parseLutSetting } from "../shared/utils/controlPointsToLut";
|
|
16
16
|
import { removeUndefinedProperties } from "../shared/utils/datatypes";
|
|
17
|
-
import {
|
|
18
|
-
import { CameraTransformKeys, ViewerChannelSettingKeys, ViewerStateKeys } from "./types";
|
|
17
|
+
import { CameraTransformKeys, ChannelStateSnapshotKeys, ImageType, ImageTypeSnapshot, RenderMode, RenderModeSnapshot, ViewerStateSnapshotKeys, ViewMode, ViewModeSnapshot } from "./types";
|
|
19
18
|
var DEFAULT_CONTROL_POINT_COLOR = [255, 255, 255];
|
|
20
19
|
var DEFAULT_CONTROL_POINT_COLOR_CODE = "1";
|
|
21
20
|
var FLOAT_REGEX = /-?[0-9]*\.?[0-9]+/;
|
|
22
21
|
|
|
23
|
-
/** Match colon-separated pairs of alphanumeric strings */
|
|
24
|
-
var LUT_REGEX = /^-?[a-z0-9.]*:[ ]*-?[a-z0-9.]*$/;
|
|
25
|
-
|
|
26
22
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
23
|
+
* A valid lut specifier for `ViewerChannelSettings` is a float optionally prefixed with one of `v`, `p`, or `m`, or
|
|
24
|
+
* the string `autoij`.
|
|
29
25
|
*/
|
|
30
|
-
var
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Match comma-separated triplet of numeric strings.
|
|
34
|
-
*/
|
|
35
|
-
var SLICE_REGEX = new RegExp("^".concat(FLOAT_REGEX.source, ",").concat(FLOAT_REGEX.source, ",").concat(FLOAT_REGEX.source, "$"));
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Matches a sequence of three comma-separated min:max number pairs, representing
|
|
39
|
-
* the x, y, and z axes.
|
|
40
|
-
*/
|
|
41
|
-
var REGION_REGEX = new RegExp("^(".concat(FLOAT_REGEX.source, ":").concat(FLOAT_REGEX.source, ")(,").concat(FLOAT_REGEX.source, ":").concat(FLOAT_REGEX.source, "){2}$"));
|
|
26
|
+
var LUT_VALUE_REGEX = new RegExp("^([vpm]?".concat(FLOAT_REGEX.source, "|autoij)?$"));
|
|
42
27
|
var HEX_COLOR_REGEX = new RegExp("(([0-9a-fA-F]{6})|".concat(DEFAULT_CONTROL_POINT_COLOR_CODE, ")"));
|
|
43
28
|
|
|
44
29
|
/** Represents control points specified by bin indices. */
|
|
@@ -64,6 +49,147 @@ export var LEGACY_CONTROL_POINTS_REGEX = new RegExp("^".concat(CONTROL_POINT_REG
|
|
|
64
49
|
*/
|
|
65
50
|
export var CONTROL_POINTS_REGEX = new RegExp("^".concat(CONTROL_POINT_REGEX.source, "(:").concat(CONTROL_POINT_REGEX.source, ")*$"));
|
|
66
51
|
|
|
52
|
+
/** An array of exactly `N` `T`s. */
|
|
53
|
+
// adapted from https://github.com/microsoft/TypeScript/pull/40002
|
|
54
|
+
|
|
55
|
+
// MARK: Destringifiers
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a function that parses a string into a list of exactly `length` items split by `delimiter`,
|
|
59
|
+
* with each item further parsed by `itemParser`; or returns `undefined` if parsing failed.
|
|
60
|
+
*/
|
|
61
|
+
var tupleParser = function tupleParser(length) {
|
|
62
|
+
var itemParser = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : identity;
|
|
63
|
+
var delimiter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ":";
|
|
64
|
+
return function (stringified) {
|
|
65
|
+
var split = stringified.split(delimiter);
|
|
66
|
+
if (split.length !== length) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
var result = [];
|
|
70
|
+
var _iterator = _createForOfIteratorHelper(split),
|
|
71
|
+
_step;
|
|
72
|
+
try {
|
|
73
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
74
|
+
var value = _step.value;
|
|
75
|
+
var parsedValue = itemParser(value.trim());
|
|
76
|
+
if (parsedValue === undefined || Number.isNaN(parsedValue)) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
result.push(parsedValue);
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
_iterator.e(err);
|
|
83
|
+
} finally {
|
|
84
|
+
_iterator.f();
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
function parseControlPointSnapshots(controlPoints) {
|
|
90
|
+
if (!(controlPoints && (CONTROL_POINTS_REGEX.test(controlPoints) || LEGACY_CONTROL_POINTS_REGEX.test(controlPoints)))) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Parse raw control point data from the string into an array of [x, opacity, color] triplets.
|
|
95
|
+
var controlPointStrings;
|
|
96
|
+
if (LEGACY_CONTROL_POINTS_REGEX.test(controlPoints)) {
|
|
97
|
+
// Legacy format uses commas to separate control points.
|
|
98
|
+
controlPointStrings = controlPoints.split(",").map(function (cp) {
|
|
99
|
+
return cp.split(":");
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
// New format is all colon-separated, where every three elements represent a control point.
|
|
103
|
+
controlPointStrings = controlPoints.split(":").reduce(function (acc, _val, i, array) {
|
|
104
|
+
if ((i + 1) % 3 === 0) {
|
|
105
|
+
acc.push([array[i - 2], array[i - 1], array[i]]);
|
|
106
|
+
}
|
|
107
|
+
return acc;
|
|
108
|
+
}, []);
|
|
109
|
+
}
|
|
110
|
+
var newControlPoints = controlPointStrings.map(function (cp) {
|
|
111
|
+
var _cp = _slicedToArray(cp, 3),
|
|
112
|
+
x = _cp[0],
|
|
113
|
+
opacity = _cp[1],
|
|
114
|
+
color = _cp[2];
|
|
115
|
+
return {
|
|
116
|
+
x: Number.parseFloat(x),
|
|
117
|
+
opacity: Number.parseFloat(opacity),
|
|
118
|
+
color: color
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
return newControlPoints;
|
|
122
|
+
}
|
|
123
|
+
var parseBoolean = function parseBoolean(value) {
|
|
124
|
+
return value === "1" ? true : value === "0" ? false : undefined;
|
|
125
|
+
};
|
|
126
|
+
export var enumParser = function enumParser(enumValues) {
|
|
127
|
+
var variants = Object.values(enumValues);
|
|
128
|
+
var variantsLowercase = Object.fromEntries(variants.map(function (v) {
|
|
129
|
+
return [v.toLowerCase(), v];
|
|
130
|
+
}));
|
|
131
|
+
return function (value) {
|
|
132
|
+
return typeof value === "string" ? variantsLowercase[value.toLowerCase()] : undefined;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
var parseViewMode = enumParser(ViewModeSnapshot);
|
|
136
|
+
var parseRenderMode = enumParser(RenderModeSnapshot);
|
|
137
|
+
var parseImageType = enumParser(ImageTypeSnapshot);
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Helper function for parsing all keys of a stringified object back to their
|
|
141
|
+
* proper types.
|
|
142
|
+
*
|
|
143
|
+
* Accepts an object with string keys, and a map of parsers that convert the
|
|
144
|
+
* keys to their proper types, or return `undefined` when parsing fails.
|
|
145
|
+
*/
|
|
146
|
+
var destringify = function destringify(stringified, parsers) {
|
|
147
|
+
var result = {};
|
|
148
|
+
for (var _i = 0, _Object$keys = Object.keys(parsers); _i < _Object$keys.length; _i++) {
|
|
149
|
+
var k = _Object$keys[_i];
|
|
150
|
+
var key = k;
|
|
151
|
+
var parser = parsers[key];
|
|
152
|
+
var stringValue = stringified[key];
|
|
153
|
+
if (stringValue !== undefined) {
|
|
154
|
+
var parsed = parser(stringValue);
|
|
155
|
+
if (parsed !== undefined && !Number.isNaN(parsed)) {
|
|
156
|
+
result[key] = parsed;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Converts a `CameraStateStringified` into a `CameraStateSnapshot` by parsing each key from its stringified
|
|
165
|
+
* representation to its type in `CameraStateSnapshot`.
|
|
166
|
+
*/
|
|
167
|
+
export var destringifyCameraStateSnapshot = function destringifyCameraStateSnapshot(stringified) {
|
|
168
|
+
return destringify(stringified, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, CameraTransformKeys.Position, tupleParser(3, Number.parseFloat)), CameraTransformKeys.Target, tupleParser(3, Number.parseFloat)), CameraTransformKeys.Up, tupleParser(3, Number.parseFloat)), CameraTransformKeys.OrthoScale, Number.parseFloat), CameraTransformKeys.Fov, Number.parseFloat));
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Converts a `ViewerStateStringified` into a `ViewerStateSnapshot` by parsing each key from its stringified
|
|
173
|
+
* representation to its type in `ViewerStateSnapshot`.
|
|
174
|
+
*/
|
|
175
|
+
export var destringifyViewerStateSnapshot = function destringifyViewerStateSnapshot(stringified) {
|
|
176
|
+
var _destringify2;
|
|
177
|
+
return destringify(stringified, (_destringify2 = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_destringify2, ViewerStateSnapshotKeys.View, parseViewMode), ViewerStateSnapshotKeys.Mode, parseRenderMode), ViewerStateSnapshotKeys.MaskOpacity, Number.parseFloat), ViewerStateSnapshotKeys.ImageType, parseImageType), ViewerStateSnapshotKeys.ShowAxes, parseBoolean), ViewerStateSnapshotKeys.ShowBoundingBox, parseBoolean), ViewerStateSnapshotKeys.BoundingBoxColor, identity), ViewerStateSnapshotKeys.BackgroundColor, identity), ViewerStateSnapshotKeys.Autorotate, parseBoolean), ViewerStateSnapshotKeys.Brightness, Number.parseFloat), _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_destringify2, ViewerStateSnapshotKeys.Density, Number.parseFloat), ViewerStateSnapshotKeys.Levels, tupleParser(3, Number.parseFloat, ",")), ViewerStateSnapshotKeys.Interpolation, parseBoolean), ViewerStateSnapshotKeys.Region, tupleParser(3, tupleParser(2, Number.parseFloat), ",")), ViewerStateSnapshotKeys.Slice, tupleParser(3, Number.parseFloat, ",")), ViewerStateSnapshotKeys.Time, Number.parseInt), ViewerStateSnapshotKeys.Scene, Number.parseInt), ViewerStateSnapshotKeys.CameraState, function (cameraString) {
|
|
178
|
+
return destringifyCameraStateSnapshot(parseKeyValueList(cameraString));
|
|
179
|
+
}), ViewerStateSnapshotKeys.SingleChannelMode, parseBoolean), ViewerStateSnapshotKeys.SingleChannelIndex, Number.parseInt), _defineProperty(_defineProperty(_destringify2, ViewerStateSnapshotKeys.UseExactScaleLevel, parseBoolean), ViewerStateSnapshotKeys.ScaleLevelIndex, Number.parseInt)));
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Converts a `ChannelStateStringified` into a `ChannelStateSnapshot` by parsing each key from its stringified
|
|
184
|
+
* representation to its type in `ChannelStateSnapshot`.
|
|
185
|
+
*/
|
|
186
|
+
export var destringifyChannelStateSnapshot = function destringifyChannelStateSnapshot(stringified) {
|
|
187
|
+
var _destringify3;
|
|
188
|
+
return destringify(stringified, (_destringify3 = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_destringify3, ChannelStateSnapshotKeys.Color, identity), ChannelStateSnapshotKeys.Colorize, parseBoolean), ChannelStateSnapshotKeys.ColorizeAlpha, Number.parseFloat), ChannelStateSnapshotKeys.IsosurfaceAlpha, Number.parseFloat), ChannelStateSnapshotKeys.Lut, tupleParser(2)), ChannelStateSnapshotKeys.ControlPoints, parseControlPointSnapshots), ChannelStateSnapshotKeys.ControlPointsLegacy, parseControlPointSnapshots), ChannelStateSnapshotKeys.Ramp, tupleParser(2, Number.parseFloat)), ChannelStateSnapshotKeys.RampLegacy, tupleParser(2, Number.parseFloat)), ChannelStateSnapshotKeys.ControlPointsEnabled, parseBoolean), _defineProperty(_defineProperty(_defineProperty(_defineProperty(_destringify3, ChannelStateSnapshotKeys.VolumeEnabled, parseBoolean), ChannelStateSnapshotKeys.SurfaceEnabled, parseBoolean), ChannelStateSnapshotKeys.IsosurfaceValue, Number.parseFloat), ChannelStateSnapshotKeys.KeepRange, parseBoolean)));
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// MARK: Parsing Helpers
|
|
192
|
+
|
|
67
193
|
/**
|
|
68
194
|
* Parse a string list of comma-separated key:value pairs into
|
|
69
195
|
* a key-value object.
|
|
@@ -80,11 +206,11 @@ export function parseKeyValueList(data) {
|
|
|
80
206
|
}
|
|
81
207
|
var result = {};
|
|
82
208
|
var keyValuePairs = data.split(",");
|
|
83
|
-
var
|
|
84
|
-
|
|
209
|
+
var _iterator2 = _createForOfIteratorHelper(keyValuePairs),
|
|
210
|
+
_step2;
|
|
85
211
|
try {
|
|
86
|
-
for (
|
|
87
|
-
var pair =
|
|
212
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
213
|
+
var pair = _step2.value;
|
|
88
214
|
var splitIndex = pair.indexOf(":");
|
|
89
215
|
if (splitIndex === -1) {
|
|
90
216
|
continue;
|
|
@@ -94,78 +220,14 @@ export function parseKeyValueList(data) {
|
|
|
94
220
|
result[decodeURIComponent(key).trim()] = decodeURIComponent(value).trim();
|
|
95
221
|
}
|
|
96
222
|
} catch (err) {
|
|
97
|
-
|
|
223
|
+
_iterator2.e(err);
|
|
98
224
|
} finally {
|
|
99
|
-
|
|
225
|
+
_iterator2.f();
|
|
100
226
|
}
|
|
101
227
|
return result;
|
|
102
228
|
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Parses a string to a float and clamps the result to the [min, max] range.
|
|
106
|
-
* Returns `undefined` if the string is undefined or NaN.
|
|
107
|
-
* @param value String to parse as a float. Will be parsed with `Number.parseFloat`.
|
|
108
|
-
* @param min Minimum value, inclusive.
|
|
109
|
-
* @param max Maximum value, inclusive.
|
|
110
|
-
* @returns
|
|
111
|
-
* - The parsed number, clamped to the [min, max] range.
|
|
112
|
-
* - `undefined` if the string is undefined or NaN.
|
|
113
|
-
*/
|
|
114
|
-
export function parseStringFloat(value, min, max) {
|
|
115
|
-
if (value === undefined) {
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
var number = Number.parseFloat(value);
|
|
119
|
-
return Number.isNaN(number) ? undefined : clamp(number, min, max);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Parses a string to an integer and clamps the result to the [min, max] range.
|
|
124
|
-
* @param value String to parse as a float. Assumes base 10, parses with `Number.parseInt(value, 10)`.
|
|
125
|
-
* @param min Minimum value, inclusive.
|
|
126
|
-
* @param max Maximum value, inclusive.
|
|
127
|
-
* @returns
|
|
128
|
-
* - The parsed number, clamped to the [min, max] range.
|
|
129
|
-
* - `undefined` if the string is undefined or NaN.
|
|
130
|
-
*/
|
|
131
|
-
export function parseStringInt(value, min, max) {
|
|
132
|
-
if (value === undefined) {
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
var number = Number.parseInt(value, 10);
|
|
136
|
-
if (Number.isNaN(number)) {
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
return clamp(number, min, max);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Parses a string to an enum value; if the string is not in the enum, returns the default value.
|
|
144
|
-
* @param value String to parse.
|
|
145
|
-
* @param enumValues Enum. Cannot be a `const enum`, as these are removed at compile time.
|
|
146
|
-
* @param defaultValue Default value to return if the string is not in the enum.
|
|
147
|
-
* @returns A value from the enum or the default value. Note that the return type includes `undefined`
|
|
148
|
-
* if the `defaultValue` is `undefined`.
|
|
149
|
-
*/
|
|
150
|
-
export function parseStringEnum(value, enumValues) {
|
|
151
|
-
var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
|
|
152
|
-
if (value === undefined || !Object.values(enumValues).includes(value)) {
|
|
153
|
-
return defaultValue;
|
|
154
|
-
}
|
|
155
|
-
return value;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Parses a string boolean value ("1" as true, "0" as false), and returns `undefined` if the value is `undefined`.
|
|
160
|
-
*/
|
|
161
|
-
function parseStringBoolean(value) {
|
|
162
|
-
if (value === undefined) {
|
|
163
|
-
return undefined;
|
|
164
|
-
}
|
|
165
|
-
return value === "1";
|
|
166
|
-
}
|
|
167
229
|
export function parseHexColorAsColorArray(hexColor) {
|
|
168
|
-
if (
|
|
230
|
+
if (typeof hexColor !== "string" || !HEX_COLOR_STR_REGEX.test(hexColor)) {
|
|
169
231
|
return undefined;
|
|
170
232
|
}
|
|
171
233
|
// if (hexColor in COLOR_CODES) {
|
|
@@ -179,257 +241,267 @@ export function parseHexColorAsColorArray(hexColor) {
|
|
|
179
241
|
var b = Number.parseInt(hexColor.slice(4, 6), 16);
|
|
180
242
|
return [r, g, b];
|
|
181
243
|
}
|
|
182
|
-
|
|
183
|
-
|
|
244
|
+
|
|
245
|
+
/** Verifies that `value` is a `number`; if it is, clamps it between `min` and `max`. */
|
|
246
|
+
export var validateNumber = function validateNumber(value) {
|
|
247
|
+
var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -Infinity;
|
|
248
|
+
var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Infinity;
|
|
249
|
+
return typeof value === "number" && !Number.isNaN(value) ? clamp(value, min, max) : undefined;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/** Verifies that `value` is a `number`; if it is, truncates it to an integer and clamps it between `min` and `max`. */
|
|
253
|
+
export var validateInt = function validateInt(value) {
|
|
254
|
+
var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -Infinity;
|
|
255
|
+
var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Infinity;
|
|
256
|
+
return typeof value === "number" && !Number.isNaN(value) ? clamp(Math.trunc(value), min, max) : undefined;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
/** Verifies that a value is a `boolean`. */
|
|
260
|
+
var validateBoolean = function validateBoolean(value) {
|
|
261
|
+
return typeof value === "boolean" ? value : undefined;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/** Verifies that `value` is a list of length `length` and that all its items are valid per `validator`. */
|
|
265
|
+
var validateTuple = function validateTuple(value, length, validator) {
|
|
266
|
+
if (!Array.isArray(value) || value.length !== length) {
|
|
184
267
|
return undefined;
|
|
185
268
|
}
|
|
186
|
-
var
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
269
|
+
var result = [];
|
|
270
|
+
var _iterator3 = _createForOfIteratorHelper(value),
|
|
271
|
+
_step3;
|
|
272
|
+
try {
|
|
273
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
274
|
+
var v = _step3.value;
|
|
275
|
+
var validated = validator(v);
|
|
276
|
+
if (validated === undefined) {
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
result.push(validated);
|
|
280
|
+
}
|
|
281
|
+
} catch (err) {
|
|
282
|
+
_iterator3.e(err);
|
|
283
|
+
} finally {
|
|
284
|
+
_iterator3.f();
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Verifies that `value` is a three-element array whose items are valid per `validator`;
|
|
291
|
+
* if it is, converts it to an object with the form `{ x, y, z }`
|
|
292
|
+
*/
|
|
293
|
+
var validateXYZ = function validateXYZ(value, validator) {
|
|
294
|
+
var tuple = validateTuple(value, 3, validator);
|
|
295
|
+
if (tuple === undefined) {
|
|
194
296
|
return undefined;
|
|
195
297
|
}
|
|
298
|
+
var _tuple = _slicedToArray(tuple, 3),
|
|
299
|
+
x = _tuple[0],
|
|
300
|
+
y = _tuple[1],
|
|
301
|
+
z = _tuple[2];
|
|
196
302
|
return {
|
|
197
303
|
x: x,
|
|
198
304
|
y: y,
|
|
199
305
|
z: z
|
|
200
306
|
};
|
|
201
|
-
}
|
|
307
|
+
};
|
|
202
308
|
|
|
203
309
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
* @param options Optional parameters for parsing:
|
|
207
|
-
* - `min`: Minimum value for each number. Default is negative infinity.
|
|
208
|
-
* - `max`: Maximum value for each number. Default is positive infinity.
|
|
209
|
-
* - `separator`: Separator between numbers. Default is `,`.
|
|
210
|
-
* @returns
|
|
211
|
-
* - undefined if the string is undefined or could not be parsed.
|
|
212
|
-
* - An array of three numbers, clamped to the [min, max] range.
|
|
310
|
+
* Verifies that `value` is a two-element array of numbers, clamps both numbers between `min` and `max`,
|
|
311
|
+
* then sorts the numbers.
|
|
213
312
|
*/
|
|
214
|
-
function
|
|
215
|
-
var
|
|
216
|
-
|
|
313
|
+
var validateSortedPair = function validateSortedPair(value, min, max) {
|
|
314
|
+
var tuple = validateTuple(value, 2, function (number) {
|
|
315
|
+
return validateNumber(number, min, max);
|
|
316
|
+
});
|
|
317
|
+
if (tuple === undefined) {
|
|
217
318
|
return undefined;
|
|
218
319
|
}
|
|
219
|
-
var
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
z = _stringArr$split$map2[2];
|
|
229
|
-
if (x === undefined || y === undefined || z === undefined) {
|
|
320
|
+
var _tuple2 = _slicedToArray(tuple, 2),
|
|
321
|
+
minVal = _tuple2[0],
|
|
322
|
+
maxVal = _tuple2[1];
|
|
323
|
+
return minVal > maxVal ? [maxVal, minVal] : [minVal, maxVal];
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
/** Verifies that `value` is an object with `string` keys. */
|
|
327
|
+
var validateRecord = function validateRecord(value) {
|
|
328
|
+
if (_typeof(value) !== "object" || Array.isArray(value) || value === null) {
|
|
230
329
|
return undefined;
|
|
231
330
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (!region || !REGION_REGEX.test(region)) {
|
|
331
|
+
if (!Object.keys(value).every(function (key) {
|
|
332
|
+
return typeof key === "string";
|
|
333
|
+
})) {
|
|
236
334
|
return undefined;
|
|
237
335
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return undefined;
|
|
248
|
-
}
|
|
249
|
-
// Ensure sorted order
|
|
250
|
-
return min < max ? [min, max] : [max, min];
|
|
251
|
-
}),
|
|
252
|
-
_region$split$map4 = _slicedToArray(_region$split$map3, 3),
|
|
253
|
-
x = _region$split$map4[0],
|
|
254
|
-
y = _region$split$map4[1],
|
|
255
|
-
z = _region$split$map4[2];
|
|
256
|
-
// Check for undefined values
|
|
257
|
-
if (x === undefined || y === undefined || z === undefined) {
|
|
336
|
+
return value;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
/** Verifies that `value` is a valid lut specifier per `ViewerChannelSettings`. */
|
|
340
|
+
var validateLutValue = function validateLutValue(value) {
|
|
341
|
+
if (typeof value === "number") {
|
|
342
|
+
return clamp(value, 0, 255);
|
|
343
|
+
}
|
|
344
|
+
if (typeof value !== "string") {
|
|
258
345
|
return undefined;
|
|
259
346
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
347
|
+
var result = value.trim().toLowerCase();
|
|
348
|
+
if (LUT_VALUE_REGEX.test(result)) {
|
|
349
|
+
return result;
|
|
350
|
+
}
|
|
351
|
+
return undefined;
|
|
352
|
+
};
|
|
353
|
+
var enumSnapshotConverter = function enumSnapshotConverter(map) {
|
|
354
|
+
var entries = Object.entries(map);
|
|
355
|
+
var lowercaseMap = Object.fromEntries(entries.map(function (_ref) {
|
|
356
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
357
|
+
s = _ref2[0],
|
|
358
|
+
e = _ref2[1];
|
|
359
|
+
return [s.toLowerCase(), e];
|
|
360
|
+
}));
|
|
361
|
+
return function (value) {
|
|
362
|
+
return typeof value === "string" ? lowercaseMap[value.toLowerCase()] : undefined;
|
|
264
363
|
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
364
|
+
};
|
|
365
|
+
var snapshotToViewMode = enumSnapshotConverter(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, ViewModeSnapshot.threeD, ViewMode.threeD), ViewModeSnapshot.xy, ViewMode.xy), ViewModeSnapshot.xz, ViewMode.xz), ViewModeSnapshot.yz, ViewMode.yz));
|
|
366
|
+
var snapshotToRenderMode = enumSnapshotConverter(_defineProperty(_defineProperty(_defineProperty({}, RenderModeSnapshot.volumetric, RenderMode.volumetric), RenderModeSnapshot.maxProject, RenderMode.maxProject), RenderModeSnapshot.pathTrace, RenderMode.pathTrace));
|
|
367
|
+
var snapshotToImageType = enumSnapshotConverter(_defineProperty(_defineProperty({}, ImageTypeSnapshot.segmentedCell, ImageType.segmentedCell), ImageTypeSnapshot.fullField, ImageType.fullField));
|
|
368
|
+
|
|
369
|
+
// MARK: Parsers
|
|
370
|
+
|
|
371
|
+
/** Parses a `CameraStateSnapshot` to a `CameraState`. */
|
|
372
|
+
function snapshotToCameraState(snapshot) {
|
|
373
|
+
if (snapshot === undefined) {
|
|
268
374
|
return undefined;
|
|
269
375
|
}
|
|
270
|
-
var parsedCameraSettings = parseKeyValueList(cameraSettings);
|
|
271
376
|
var result = {
|
|
272
|
-
position:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
target: parseThreeNumberArray(parsedCameraSettings[CameraTransformKeys.Target], {
|
|
276
|
-
separator: ":"
|
|
277
|
-
}),
|
|
278
|
-
up: parseThreeNumberArray(parsedCameraSettings[CameraTransformKeys.Up], {
|
|
279
|
-
separator: ":"
|
|
280
|
-
}),
|
|
377
|
+
position: validateTuple(snapshot[CameraTransformKeys.Position], 3, validateNumber),
|
|
378
|
+
target: validateTuple(snapshot[CameraTransformKeys.Target], 3, validateNumber),
|
|
379
|
+
up: validateTuple(snapshot[CameraTransformKeys.Up], 3, validateNumber),
|
|
281
380
|
// Orthographic scales cannot be negative
|
|
282
|
-
orthoScale:
|
|
283
|
-
fov:
|
|
381
|
+
orthoScale: validateNumber(snapshot[CameraTransformKeys.OrthoScale], 0),
|
|
382
|
+
fov: validateNumber(snapshot[CameraTransformKeys.Fov], 0, 180)
|
|
284
383
|
};
|
|
285
384
|
return removeUndefinedProperties(result);
|
|
286
385
|
}
|
|
287
|
-
|
|
386
|
+
|
|
387
|
+
/** Parses a `ViewerStateSnapshot` to a `ViewerState`. */
|
|
388
|
+
export function snapshotToViewerState(snapshot) {
|
|
288
389
|
var result = {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
390
|
+
viewMode: snapshotToViewMode(snapshot[ViewerStateSnapshotKeys.View]),
|
|
391
|
+
maskAlpha: validateNumber(snapshot[ViewerStateSnapshotKeys.MaskOpacity], 0, 100),
|
|
392
|
+
imageType: snapshotToImageType(snapshot[ViewerStateSnapshotKeys.ImageType]),
|
|
393
|
+
showAxes: validateBoolean(snapshot[ViewerStateSnapshotKeys.ShowAxes]),
|
|
394
|
+
showBoundingBox: validateBoolean(snapshot[ViewerStateSnapshotKeys.ShowBoundingBox]),
|
|
395
|
+
boundingBoxColor: parseHexColorAsColorArray(snapshot[ViewerStateSnapshotKeys.BoundingBoxColor]),
|
|
396
|
+
backgroundColor: parseHexColorAsColorArray(snapshot[ViewerStateSnapshotKeys.BackgroundColor]),
|
|
397
|
+
autorotate: validateBoolean(snapshot[ViewerStateSnapshotKeys.Autorotate]),
|
|
398
|
+
brightness: validateNumber(snapshot[ViewerStateSnapshotKeys.Brightness], 0, 100),
|
|
399
|
+
density: validateNumber(snapshot[ViewerStateSnapshotKeys.Density], 0, 100),
|
|
400
|
+
levels: validateTuple(snapshot[ViewerStateSnapshotKeys.Levels], 3, function (value) {
|
|
401
|
+
return validateNumber(value, 0, 255);
|
|
301
402
|
}),
|
|
302
|
-
interpolationEnabled:
|
|
303
|
-
region:
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
403
|
+
interpolationEnabled: validateBoolean(snapshot[ViewerStateSnapshotKeys.Interpolation]),
|
|
404
|
+
region: validateXYZ(snapshot[ViewerStateSnapshotKeys.Region], function (value) {
|
|
405
|
+
return validateSortedPair(value, 0, 1);
|
|
406
|
+
}),
|
|
407
|
+
slice: validateXYZ(snapshot[ViewerStateSnapshotKeys.Slice], function (value) {
|
|
408
|
+
return validateNumber(value, 0, 1);
|
|
409
|
+
}),
|
|
410
|
+
time: validateInt(snapshot[ViewerStateSnapshotKeys.Time], 0, Number.POSITIVE_INFINITY),
|
|
411
|
+
scene: validateInt(snapshot[ViewerStateSnapshotKeys.Scene], 0, Number.POSITIVE_INFINITY),
|
|
412
|
+
renderMode: snapshotToRenderMode(snapshot[ViewerStateSnapshotKeys.Mode]),
|
|
413
|
+
singleChannelMode: validateBoolean(snapshot[ViewerStateSnapshotKeys.SingleChannelMode]),
|
|
414
|
+
singleChannelIndex: validateInt(snapshot[ViewerStateSnapshotKeys.SingleChannelIndex], 0, Number.POSITIVE_INFINITY),
|
|
415
|
+
useExactScaleLevel: validateBoolean(snapshot[ViewerStateSnapshotKeys.UseExactScaleLevel]),
|
|
416
|
+
scaleLevelIndex: validateInt(snapshot[ViewerStateSnapshotKeys.ScaleLevelIndex], 0, Number.MAX_SAFE_INTEGER),
|
|
417
|
+
cameraState: snapshotToCameraState(validateRecord(snapshot[ViewerStateSnapshotKeys.CameraState]))
|
|
313
418
|
};
|
|
314
|
-
|
|
315
|
-
// Handle viewmode, since they use different mappings
|
|
316
|
-
// TODO: Allow lowercase
|
|
317
|
-
if (params.view) {
|
|
318
|
-
var viewParamToViewMode = {
|
|
319
|
-
"3D": ViewMode.threeD,
|
|
320
|
-
Z: ViewMode.xy,
|
|
321
|
-
Y: ViewMode.xz,
|
|
322
|
-
X: ViewMode.yz
|
|
323
|
-
};
|
|
324
|
-
var allowedViews = Object.keys(viewParamToViewMode);
|
|
325
|
-
var view;
|
|
326
|
-
if (allowedViews.includes(params.view.toUpperCase())) {
|
|
327
|
-
view = params.view.toUpperCase();
|
|
328
|
-
} else {
|
|
329
|
-
view = "3D";
|
|
330
|
-
}
|
|
331
|
-
result.viewMode = viewParamToViewMode[view];
|
|
332
|
-
}
|
|
333
419
|
return removeUndefinedProperties(result);
|
|
334
420
|
}
|
|
335
|
-
function parseControlPoints(controlPoints) {
|
|
336
|
-
if (!(controlPoints && (CONTROL_POINTS_REGEX.test(controlPoints) || LEGACY_CONTROL_POINTS_REGEX.test(controlPoints)))) {
|
|
337
|
-
return undefined;
|
|
338
|
-
}
|
|
339
421
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
422
|
+
/** Attempts to parse an array of `ControlPointSnapshot`s to an array of `ControlPoint`s. */
|
|
423
|
+
function snapshotToControlPoints(controlPoints) {
|
|
424
|
+
var result = [];
|
|
425
|
+
var _iterator4 = _createForOfIteratorHelper(controlPoints),
|
|
426
|
+
_step4;
|
|
427
|
+
try {
|
|
428
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
429
|
+
var _parseHexColorAsColor;
|
|
430
|
+
var point = _step4.value;
|
|
431
|
+
var x = validateNumber(point.x);
|
|
432
|
+
var opacity = validateNumber(point.opacity, 0, 1);
|
|
433
|
+
var color = (_parseHexColorAsColor = parseHexColorAsColorArray(point.color)) !== null && _parseHexColorAsColor !== void 0 ? _parseHexColorAsColor : [].concat(DEFAULT_CONTROL_POINT_COLOR);
|
|
434
|
+
if (x === undefined || opacity === undefined || color === undefined) {
|
|
435
|
+
return undefined;
|
|
352
436
|
}
|
|
353
|
-
|
|
354
|
-
|
|
437
|
+
result.push({
|
|
438
|
+
x: x,
|
|
439
|
+
opacity: opacity,
|
|
440
|
+
color: color
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
// Sort control points by x value
|
|
444
|
+
} catch (err) {
|
|
445
|
+
_iterator4.e(err);
|
|
446
|
+
} finally {
|
|
447
|
+
_iterator4.f();
|
|
355
448
|
}
|
|
356
|
-
|
|
357
|
-
var _parseStringFloat, _parseStringFloat2, _parseHexColorAsColor;
|
|
358
|
-
var _cp = _slicedToArray(cp, 3),
|
|
359
|
-
x = _cp[0],
|
|
360
|
-
opacity = _cp[1],
|
|
361
|
-
color = _cp[2];
|
|
362
|
-
return {
|
|
363
|
-
x: (_parseStringFloat = parseStringFloat(x, -Infinity, Infinity)) !== null && _parseStringFloat !== void 0 ? _parseStringFloat : 0,
|
|
364
|
-
opacity: (_parseStringFloat2 = parseStringFloat(opacity, 0, 1)) !== null && _parseStringFloat2 !== void 0 ? _parseStringFloat2 : 1.0,
|
|
365
|
-
color: (_parseHexColorAsColor = parseHexColorAsColorArray(color)) !== null && _parseHexColorAsColor !== void 0 ? _parseHexColorAsColor : DEFAULT_CONTROL_POINT_COLOR
|
|
366
|
-
};
|
|
367
|
-
});
|
|
368
|
-
// Sort control points by x value
|
|
369
|
-
return newControlPoints.sort(function (a, b) {
|
|
449
|
+
return result.sort(function (a, b) {
|
|
370
450
|
return a.x - b.x;
|
|
371
451
|
});
|
|
372
452
|
}
|
|
373
453
|
|
|
374
454
|
/**
|
|
375
|
-
* Parses a
|
|
376
|
-
* @param
|
|
377
|
-
* @param jsonState The serialized ViewerChannelSetting to parse, as an object.
|
|
378
|
-
* @returns A ViewerChannelSetting object.
|
|
455
|
+
* Parses a `ChannelStateSnapshot` to a `ViewerChannelSetting`.
|
|
456
|
+
* @param channelId Either the index or the name of the channel, to be turned into a `match` value.
|
|
457
|
+
* @param jsonState The serialized `ViewerChannelSetting` to parse, as an object.
|
|
458
|
+
* @returns A `ViewerChannelSetting` object.
|
|
379
459
|
*/
|
|
380
|
-
export function
|
|
460
|
+
export function snapshotToViewerChannelSetting(channelId, jsonState) {
|
|
381
461
|
// Missing/undefined fields should be handled downstream.
|
|
382
462
|
var result = {
|
|
383
|
-
match:
|
|
384
|
-
enabled:
|
|
385
|
-
surfaceEnabled:
|
|
386
|
-
isovalue:
|
|
387
|
-
keepIntensityRange:
|
|
388
|
-
surfaceOpacity:
|
|
389
|
-
colorizeEnabled:
|
|
390
|
-
colorizeAlpha:
|
|
391
|
-
controlPointsEnabled:
|
|
463
|
+
match: channelId,
|
|
464
|
+
enabled: validateBoolean(jsonState[ChannelStateSnapshotKeys.VolumeEnabled]),
|
|
465
|
+
surfaceEnabled: validateBoolean(jsonState[ChannelStateSnapshotKeys.SurfaceEnabled]),
|
|
466
|
+
isovalue: validateNumber(jsonState[ChannelStateSnapshotKeys.IsosurfaceValue], -Infinity, Infinity),
|
|
467
|
+
keepIntensityRange: validateBoolean(jsonState[ChannelStateSnapshotKeys.KeepRange]),
|
|
468
|
+
surfaceOpacity: validateNumber(jsonState[ChannelStateSnapshotKeys.IsosurfaceAlpha], 0, 1),
|
|
469
|
+
colorizeEnabled: validateBoolean(jsonState[ChannelStateSnapshotKeys.Colorize]),
|
|
470
|
+
colorizeAlpha: validateNumber(jsonState[ChannelStateSnapshotKeys.ColorizeAlpha], 0, 1),
|
|
471
|
+
controlPointsEnabled: validateBoolean(jsonState[ChannelStateSnapshotKeys.ControlPointsEnabled])
|
|
392
472
|
};
|
|
393
|
-
|
|
394
|
-
|
|
473
|
+
var color = jsonState[ChannelStateSnapshotKeys.Color];
|
|
474
|
+
if (typeof color === "string" && HEX_COLOR_STR_REGEX.test(color)) {
|
|
475
|
+
result.color = color;
|
|
395
476
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
_jsonState$ViewerChan2 = _slicedToArray(_jsonState$ViewerChan, 2),
|
|
399
|
-
min = _jsonState$ViewerChan2[0],
|
|
400
|
-
max = _jsonState$ViewerChan2[1];
|
|
477
|
+
var lut = validateTuple(jsonState[ChannelStateSnapshotKeys.Lut], 2, validateLutValue);
|
|
478
|
+
if (lut !== undefined) {
|
|
401
479
|
result.intensity = _objectSpread(_objectSpread({}, result.intensity), {}, {
|
|
402
|
-
lut:
|
|
480
|
+
lut: lut
|
|
403
481
|
});
|
|
404
482
|
}
|
|
405
|
-
if (jsonState[
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
_jsonState$ViewerChan4 = _slicedToArray(_jsonState$ViewerChan3, 2),
|
|
409
|
-
_min = _jsonState$ViewerChan4[0],
|
|
410
|
-
_max = _jsonState$ViewerChan4[1];
|
|
483
|
+
if (jsonState[ChannelStateSnapshotKeys.Ramp]) {
|
|
484
|
+
var ramp = validateSortedPair(jsonState[ChannelStateSnapshotKeys.Ramp]);
|
|
485
|
+
if (ramp !== undefined) {
|
|
411
486
|
result.intensity = _objectSpread(_objectSpread({}, result.intensity), {}, {
|
|
412
|
-
ramp:
|
|
487
|
+
ramp: ramp
|
|
413
488
|
});
|
|
414
489
|
}
|
|
415
|
-
} else if (jsonState[
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
_min2 = _jsonState$ViewerChan6[0],
|
|
420
|
-
_max2 = _jsonState$ViewerChan6[1];
|
|
421
|
-
result.ramp = [Number.parseFloat(_min2), Number.parseFloat(_max2)];
|
|
490
|
+
} else if (jsonState[ChannelStateSnapshotKeys.RampLegacy]) {
|
|
491
|
+
var _ramp = validateSortedPair(jsonState[ChannelStateSnapshotKeys.RampLegacy]);
|
|
492
|
+
if (_ramp !== undefined) {
|
|
493
|
+
result.ramp = _ramp;
|
|
422
494
|
}
|
|
423
495
|
}
|
|
424
|
-
if (jsonState[
|
|
425
|
-
var parsedResult =
|
|
496
|
+
if (Array.isArray(jsonState[ChannelStateSnapshotKeys.ControlPoints])) {
|
|
497
|
+
var parsedResult = snapshotToControlPoints(jsonState[ChannelStateSnapshotKeys.ControlPoints]);
|
|
426
498
|
if (parsedResult) {
|
|
427
499
|
result.intensity = _objectSpread(_objectSpread({}, result.intensity), {}, {
|
|
428
500
|
controlPoints: parsedResult
|
|
429
501
|
});
|
|
430
502
|
}
|
|
431
|
-
} else if (jsonState[
|
|
432
|
-
var _parsedResult =
|
|
503
|
+
} else if (Array.isArray(jsonState[ChannelStateSnapshotKeys.ControlPointsLegacy])) {
|
|
504
|
+
var _parsedResult = snapshotToControlPoints(jsonState[ChannelStateSnapshotKeys.ControlPointsLegacy]);
|
|
433
505
|
if (_parsedResult) {
|
|
434
506
|
result.controlPoints = _parsedResult;
|
|
435
507
|
}
|
|
@@ -438,10 +510,10 @@ export function deserializeViewerChannelSetting(channelIndex, jsonState) {
|
|
|
438
510
|
}
|
|
439
511
|
|
|
440
512
|
/**
|
|
441
|
-
* Parses a `
|
|
513
|
+
* Parses a `ChannelStateSnapshot` object into a partial `ChannelState`.
|
|
442
514
|
*
|
|
443
|
-
* This is used to convert
|
|
444
|
-
* leaving absent or invalid values undefined.
|
|
515
|
+
* This is used to convert from serialized formats (URL params, JSON) into
|
|
516
|
+
* internal channel state fields, leaving absent or invalid values undefined.
|
|
445
517
|
*
|
|
446
518
|
* This function optionally accepts the target channel's `Histogram`. This
|
|
447
519
|
* argument is required to parse the following params correctly:
|
|
@@ -455,68 +527,59 @@ export function deserializeViewerChannelSetting(channelIndex, jsonState) {
|
|
|
455
527
|
* If `histogram` is left undefined, e.g. because the channel has not yet been
|
|
456
528
|
* loaded, these params are ignored.
|
|
457
529
|
*/
|
|
458
|
-
export function
|
|
530
|
+
export function snapshotToChannelState(jsonState, histogram) {
|
|
459
531
|
var result = {
|
|
460
|
-
volumeEnabled:
|
|
461
|
-
isosurfaceEnabled:
|
|
462
|
-
isovalue:
|
|
463
|
-
keepIntensityRange:
|
|
464
|
-
opacity:
|
|
465
|
-
colorizeEnabled:
|
|
466
|
-
colorizeAlpha:
|
|
467
|
-
useControlPoints:
|
|
468
|
-
color: parseHexColorAsColorArray(jsonState[
|
|
532
|
+
volumeEnabled: validateBoolean(jsonState[ChannelStateSnapshotKeys.VolumeEnabled]),
|
|
533
|
+
isosurfaceEnabled: validateBoolean(jsonState[ChannelStateSnapshotKeys.SurfaceEnabled]),
|
|
534
|
+
isovalue: validateNumber(jsonState[ChannelStateSnapshotKeys.IsosurfaceValue], -Infinity, Infinity),
|
|
535
|
+
keepIntensityRange: validateBoolean(jsonState[ChannelStateSnapshotKeys.KeepRange]),
|
|
536
|
+
opacity: validateNumber(jsonState[ChannelStateSnapshotKeys.IsosurfaceAlpha], 0, 1),
|
|
537
|
+
colorizeEnabled: validateBoolean(jsonState[ChannelStateSnapshotKeys.Colorize]),
|
|
538
|
+
colorizeAlpha: validateNumber(jsonState[ChannelStateSnapshotKeys.ColorizeAlpha], 0, 1),
|
|
539
|
+
useControlPoints: validateBoolean(jsonState[ChannelStateSnapshotKeys.ControlPointsEnabled]),
|
|
540
|
+
color: parseHexColorAsColorArray(jsonState[ChannelStateSnapshotKeys.Color])
|
|
469
541
|
};
|
|
470
|
-
var
|
|
542
|
+
var lutRaw = validateTuple(jsonState[ChannelStateSnapshotKeys.Lut], 2, validateLutValue);
|
|
471
543
|
var pointsFromLut = undefined;
|
|
472
|
-
if (histogram !== undefined &&
|
|
473
|
-
var
|
|
474
|
-
_lutSerialized$split2 = _slicedToArray(_lutSerialized$split, 2),
|
|
475
|
-
min = _lutSerialized$split2[0],
|
|
476
|
-
max = _lutSerialized$split2[1];
|
|
477
|
-
var lut = parseLutSetting(histogram, [min.trim(), max.trim()]);
|
|
544
|
+
if (histogram !== undefined && lutRaw !== undefined) {
|
|
545
|
+
var lut = parseLutSetting(histogram, lutRaw);
|
|
478
546
|
pointsFromLut = lut === null || lut === void 0 ? void 0 : lut.controlPoints.map(function (point) {
|
|
479
547
|
return _objectSpread(_objectSpread({}, point), {}, {
|
|
480
548
|
x: histogram.getValueFromBinIndex(point.x)
|
|
481
549
|
});
|
|
482
550
|
});
|
|
483
551
|
}
|
|
484
|
-
if (jsonState[
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
_min3 = _jsonState$ViewerChan8[0],
|
|
489
|
-
_max3 = _jsonState$ViewerChan8[1];
|
|
490
|
-
result.ramp = [Number.parseFloat(_min3), Number.parseFloat(_max3)];
|
|
552
|
+
if (jsonState[ChannelStateSnapshotKeys.Ramp]) {
|
|
553
|
+
var ramp = validateSortedPair(jsonState[ChannelStateSnapshotKeys.Ramp]);
|
|
554
|
+
if (ramp !== undefined) {
|
|
555
|
+
result.ramp = ramp;
|
|
491
556
|
}
|
|
492
|
-
} else if (jsonState[
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
result.ramp = [_min4, _max4];
|
|
502
|
-
}
|
|
557
|
+
} else if (jsonState[ChannelStateSnapshotKeys.RampLegacy]) {
|
|
558
|
+
var _ramp2 = validateSortedPair(jsonState[ChannelStateSnapshotKeys.RampLegacy]);
|
|
559
|
+
if (histogram !== undefined && _ramp2 !== undefined) {
|
|
560
|
+
var _ramp3 = _slicedToArray(_ramp2, 2),
|
|
561
|
+
rawMin = _ramp3[0],
|
|
562
|
+
rawMax = _ramp3[1];
|
|
563
|
+
var min = histogram.getValueFromBinIndex(rawMin);
|
|
564
|
+
var max = histogram.getValueFromBinIndex(rawMax);
|
|
565
|
+
result.ramp = [min, max];
|
|
503
566
|
}
|
|
504
567
|
} else if (pointsFromLut !== undefined) {
|
|
505
568
|
result.ramp = controlPointsToRamp(pointsFromLut);
|
|
506
569
|
}
|
|
507
|
-
if (jsonState[
|
|
508
|
-
var parsedResult =
|
|
570
|
+
if (Array.isArray(jsonState[ChannelStateSnapshotKeys.ControlPoints])) {
|
|
571
|
+
var parsedResult = snapshotToControlPoints(jsonState[ChannelStateSnapshotKeys.ControlPoints]);
|
|
509
572
|
if (parsedResult) {
|
|
510
573
|
result.controlPoints = parsedResult;
|
|
511
574
|
}
|
|
512
|
-
} else if (jsonState[
|
|
575
|
+
} else if (Array.isArray(jsonState[ChannelStateSnapshotKeys.ControlPointsLegacy])) {
|
|
513
576
|
if (histogram !== undefined) {
|
|
514
|
-
var _parsedResult2 =
|
|
577
|
+
var _parsedResult2 = snapshotToControlPoints(jsonState[ChannelStateSnapshotKeys.ControlPointsLegacy]);
|
|
515
578
|
if (_parsedResult2) {
|
|
516
|
-
result.controlPoints = _parsedResult2.map(function (
|
|
517
|
-
var opacity =
|
|
518
|
-
color =
|
|
519
|
-
x =
|
|
579
|
+
result.controlPoints = _parsedResult2.map(function (_ref3) {
|
|
580
|
+
var opacity = _ref3.opacity,
|
|
581
|
+
color = _ref3.color,
|
|
582
|
+
x = _ref3.x;
|
|
520
583
|
return {
|
|
521
584
|
opacity: opacity,
|
|
522
585
|
color: color,
|
|
@@ -529,4 +592,53 @@ export function deserializeChannelState(jsonState, histogram) {
|
|
|
529
592
|
result.controlPoints = pointsFromLut;
|
|
530
593
|
}
|
|
531
594
|
return removeUndefinedProperties(result);
|
|
532
|
-
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Parses a stringified viewer state snapshot (`ViewerStateStringified`) to a
|
|
599
|
+
* `ViewerState`.
|
|
600
|
+
*
|
|
601
|
+
* This is equivalent to (and implemented by) calling
|
|
602
|
+
* `destringifyViewerStateSnapshot`, then `snapshotToViewerState`.
|
|
603
|
+
*/
|
|
604
|
+
export var stringSnapshotToViewerState = function stringSnapshotToViewerState(stringified) {
|
|
605
|
+
return snapshotToViewerState(destringifyViewerStateSnapshot(stringified));
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Parses a stringified channel state snapshot (`ChannelStateStringified`) to a
|
|
610
|
+
* `ViewerChannelSetting`.
|
|
611
|
+
*
|
|
612
|
+
* This is equivalent to (and implemented by) calling
|
|
613
|
+
* `destringifyChannelStateSnapshot`, then `snapshotToViewerChannelSetting`.
|
|
614
|
+
*
|
|
615
|
+
* @param channelIndex Index of the channel, to be turned into a `match` value.
|
|
616
|
+
* @param jsonState The serialized `ViewerChannelSetting` to parse, as an object.
|
|
617
|
+
* @returns A `ViewerChannelSetting` object.
|
|
618
|
+
*/
|
|
619
|
+
export var stringSnapshotToViewerChannelSetting = function stringSnapshotToViewerChannelSetting(channelIndex, jsonState) {
|
|
620
|
+
return snapshotToViewerChannelSetting(channelIndex, destringifyChannelStateSnapshot(jsonState));
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Parses a stringified channel state snapshot (`ChannelStateStringified`)
|
|
625
|
+
* into a partial `ChannelState`.
|
|
626
|
+
*
|
|
627
|
+
* This is equivalent to (and implemented by) calling
|
|
628
|
+
* `destringifyChannelStateSnapshot`, then `snapshotToChannelState`.
|
|
629
|
+
*
|
|
630
|
+
* This function optionally accepts the target channel's `Histogram`. This
|
|
631
|
+
* argument is required to parse the following params correctly:
|
|
632
|
+
*
|
|
633
|
+
* - `lut`, which contains instructions for how to set the channel's
|
|
634
|
+
* intensities *relative to its intensity distribution*.
|
|
635
|
+
* - `rmp`, the legacy ramp parameter represented as histogram bin indices
|
|
636
|
+
* - `cps`, the legacy control points parameter where `x` values are
|
|
637
|
+
* represented as histogram bin indices
|
|
638
|
+
*
|
|
639
|
+
* If `histogram` is left undefined, e.g. because the channel has not yet been
|
|
640
|
+
* loaded, these params are ignored.
|
|
641
|
+
*/
|
|
642
|
+
export var stringSnapshotToChannelState = function stringSnapshotToChannelState(jsonState, histogram) {
|
|
643
|
+
return snapshotToChannelState(destringifyChannelStateSnapshot(jsonState), histogram);
|
|
644
|
+
};
|