@aics/vole-app 2.15.0 → 3.1.2
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/ChannelUpdater.js +21 -3
- package/es/aics-image-viewer/components/App/index.js +156 -199
- package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +10 -9
- package/es/aics-image-viewer/components/ChannelsWidget.js +35 -22
- package/es/aics-image-viewer/components/ChannelsWidgetRow/index.js +27 -71
- package/es/aics-image-viewer/components/ChannelsWidgetRow/styles.css +0 -6
- package/es/aics-image-viewer/components/ColorPicker.js +1 -1
- package/es/aics-image-viewer/components/ControlPanel/index.js +5 -4
- package/es/aics-image-viewer/components/CustomizeWidget.js +12 -8
- package/es/aics-image-viewer/components/ErrorAlert/index.js +4 -4
- package/es/aics-image-viewer/components/GlobalVolumeControls.js +12 -10
- package/es/aics-image-viewer/components/StyleProvider/index.js +4 -2
- package/es/aics-image-viewer/components/TfEditor/index.js +304 -154
- package/es/aics-image-viewer/components/TfEditor/styles.css +53 -31
- package/es/aics-image-viewer/components/Toolbar/DownloadButton.js +1 -1
- package/es/aics-image-viewer/components/Toolbar/index.js +18 -16
- package/es/aics-image-viewer/components/shared/SharedCheckBox.js +1 -1
- package/es/aics-image-viewer/components/shared/SliderRow/styles.css +1 -0
- package/es/aics-image-viewer/components/shared/SmarterSlider.js +1 -1
- package/es/aics-image-viewer/components/shared/ViewerIcon.js +1 -1
- package/es/aics-image-viewer/components/useVolume.js +68 -59
- package/es/aics-image-viewer/shared/constants.js +2 -2
- package/es/aics-image-viewer/shared/utils/controlPointsToLut.js +57 -24
- package/es/aics-image-viewer/shared/utils/sceneStore.js +14 -4
- package/es/aics-image-viewer/shared/utils/storage.js +238 -0
- package/es/aics-image-viewer/shared/utils/test/storage.test.js +264 -0
- package/es/aics-image-viewer/shared/utils/test/urlParsing.test.js +249 -109
- package/es/aics-image-viewer/shared/utils/test/viewerChannelSettings.test.js +1 -1
- package/es/aics-image-viewer/shared/utils/urlParsing.js +287 -154
- package/es/aics-image-viewer/shared/utils/viewerState.js +4 -24
- package/es/aics-image-viewer/state/reset.js +111 -0
- package/es/aics-image-viewer/state/store.js +90 -0
- package/es/aics-image-viewer/state/subscribers.js +153 -0
- package/es/aics-image-viewer/state/test/reset.test.js +247 -0
- package/es/aics-image-viewer/state/util.js +71 -0
- package/es/index.js +3 -3
- package/package.json +18 -11
- package/type-declarations/aics-image-viewer/components/App/ChannelUpdater.d.ts +2 -4
- package/type-declarations/aics-image-viewer/components/App/types.d.ts +3 -3
- package/type-declarations/aics-image-viewer/components/AxisClipSliders/index.d.ts +6 -6
- package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +5 -14
- package/type-declarations/aics-image-viewer/components/ChannelsWidget.d.ts +3 -6
- package/type-declarations/aics-image-viewer/components/ChannelsWidgetRow/index.d.ts +3 -6
- package/type-declarations/aics-image-viewer/components/ColorPicker.d.ts +1 -1
- package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +6 -7
- package/type-declarations/aics-image-viewer/components/CustomizeWidget.d.ts +2 -8
- package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +4 -0
- package/type-declarations/aics-image-viewer/components/GlobalVolumeControls.d.ts +2 -9
- package/type-declarations/aics-image-viewer/components/MetadataViewer/index.d.ts +1 -1
- package/type-declarations/aics-image-viewer/components/StyleProvider/index.d.ts +1 -1
- package/type-declarations/aics-image-viewer/components/TfEditor/index.d.ts +10 -3
- package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +3 -12
- package/type-declarations/aics-image-viewer/components/shared/SliderRow/index.d.ts +1 -1
- package/type-declarations/aics-image-viewer/components/shared/SmarterSlider.d.ts +1 -1
- package/type-declarations/aics-image-viewer/components/shared/ViewerIcon.d.ts +1 -1
- package/type-declarations/aics-image-viewer/components/useVolume.d.ts +7 -4
- package/type-declarations/aics-image-viewer/shared/constants.d.ts +5 -5
- package/type-declarations/aics-image-viewer/shared/types.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/utils/controlPointsToLut.d.ts +9 -5
- package/type-declarations/aics-image-viewer/shared/utils/firebase/index.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/utils/hooks.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +8 -4
- package/type-declarations/aics-image-viewer/shared/utils/storage.d.ts +15 -0
- package/type-declarations/aics-image-viewer/shared/utils/urlParsing.d.ts +94 -31
- package/type-declarations/aics-image-viewer/shared/utils/viewerChannelSettings.d.ts +39 -1
- package/type-declarations/aics-image-viewer/shared/utils/viewerState.d.ts +3 -6
- package/type-declarations/aics-image-viewer/state/reset.d.ts +29 -0
- package/type-declarations/aics-image-viewer/state/store.d.ts +30 -0
- package/type-declarations/aics-image-viewer/state/subscribers.d.ts +4 -0
- package/type-declarations/aics-image-viewer/state/types.d.ts +46 -0
- package/type-declarations/aics-image-viewer/state/util.d.ts +8 -0
- package/type-declarations/index.d.ts +4 -4
- package/es/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.js +0 -163
- package/es/aics-image-viewer/components/ViewerStateProvider/index.js +0 -259
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/ResetStateProvider.d.ts +0 -34
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/index.d.ts +0 -33
- package/type-declarations/aics-image-viewer/components/ViewerStateProvider/types.d.ts +0 -107
- /package/es/aics-image-viewer/{components/ViewerStateProvider → state}/types.js +0 -0
|
@@ -15,7 +15,8 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
15
15
|
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; } }
|
|
16
16
|
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
17
17
|
import { Lut } from "@aics/vole-core";
|
|
18
|
-
import {
|
|
18
|
+
import { PushpinFilled, PushpinOutlined } from "@ant-design/icons";
|
|
19
|
+
import { Button, Checkbox, Dropdown, InputNumber, Tooltip } from "antd";
|
|
19
20
|
import * as d3 from "d3";
|
|
20
21
|
import "nouislider/distribute/nouislider.css";
|
|
21
22
|
import React, { useCallback, useMemo, useRef, useState } from "react";
|
|
@@ -25,6 +26,7 @@ import { colorArrayToObject, colorArrayToString, colorObjectToArray } from "../.
|
|
|
25
26
|
import { controlPointsToRamp, rampToControlPoints } from "../../shared/utils/controlPointsToLut";
|
|
26
27
|
import { useRefWithSetter } from "../../shared/utils/hooks";
|
|
27
28
|
import SliderRow from "../shared/SliderRow";
|
|
29
|
+
import ViewerIcon from "../shared/ViewerIcon";
|
|
28
30
|
import "./styles.css";
|
|
29
31
|
|
|
30
32
|
/**The color picker opens next to control points like a context menu. This constant gives it a bit of space. */
|
|
@@ -50,11 +52,12 @@ var TFEDITOR_MARGINS = {
|
|
|
50
52
|
left: 25
|
|
51
53
|
};
|
|
52
54
|
var MOUSE_EVENT_BUTTONS_PRIMARY = 1;
|
|
53
|
-
var
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
var TfEditorSliderHandle = /*#__PURE__*/function (TfEditorSliderHandle) {
|
|
56
|
+
TfEditorSliderHandle["Min"] = "min";
|
|
57
|
+
TfEditorSliderHandle["Max"] = "max";
|
|
58
|
+
TfEditorSliderHandle["Isosurface"] = "surf";
|
|
59
|
+
return TfEditorSliderHandle;
|
|
60
|
+
}(TfEditorSliderHandle || {});
|
|
58
61
|
var TF_GENERATORS = {
|
|
59
62
|
autoXF: function autoXF(histo) {
|
|
60
63
|
// Currently unused. min and max are the first and last bins whose values are >=10% that of the max bin
|
|
@@ -88,6 +91,7 @@ var TF_GENERATORS = {
|
|
|
88
91
|
}
|
|
89
92
|
};
|
|
90
93
|
|
|
94
|
+
// RAMP SLIDER HANDLE
|
|
91
95
|
// *---*
|
|
92
96
|
// | |
|
|
93
97
|
// | |
|
|
@@ -108,18 +112,34 @@ var sliderHandleSymbol = {
|
|
|
108
112
|
context.closePath();
|
|
109
113
|
}
|
|
110
114
|
};
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
115
|
+
|
|
116
|
+
// ISOVALUE SLIDER HANDLE
|
|
117
|
+
// / \ / \
|
|
118
|
+
// \ \/ /
|
|
119
|
+
// \ /
|
|
120
|
+
// *--*
|
|
121
|
+
// start ^ ^ end
|
|
122
|
+
var LINE_WIDTH = 2;
|
|
123
|
+
// the "base" is the 5-sided area where both lines meet - think of a square with side length
|
|
124
|
+
// `LINE_WIDTH`, rotated 45deg, with the bottom corner cut off where the slider line meets the handle
|
|
125
|
+
var BASE_AREA = Math.pow(LINE_WIDTH, 2) * 0.75;
|
|
126
|
+
var BASE_HEIGHT = (Math.SQRT2 - 0.5) * LINE_WIDTH;
|
|
127
|
+
// how much the base "sticks out" horizontally on either side of the slider line
|
|
128
|
+
var BASE_MARGIN = (Math.SQRT2 - 1) * 0.5 * LINE_WIDTH;
|
|
129
|
+
var isovalueHandleSymbol = {
|
|
130
|
+
draw: function draw(context, size) {
|
|
131
|
+
var linesArea = Math.max(size - BASE_AREA, 0);
|
|
132
|
+
var margin = BASE_MARGIN + linesArea / (2 * Math.SQRT2 * LINE_WIDTH);
|
|
133
|
+
context.moveTo(1, 0);
|
|
134
|
+
context.lineTo(margin + 1, -margin);
|
|
135
|
+
context.lineTo(margin + 1 - Math.SQRT2, -margin - Math.SQRT2);
|
|
136
|
+
context.lineTo(0, -BASE_HEIGHT);
|
|
137
|
+
context.lineTo(-margin - 1 + Math.SQRT2, -margin - Math.SQRT2);
|
|
138
|
+
context.lineTo(-margin - 1, -margin);
|
|
139
|
+
context.lineTo(-1, 0);
|
|
140
|
+
context.closePath();
|
|
141
|
+
}
|
|
142
|
+
};
|
|
123
143
|
|
|
124
144
|
/** For when all control points are outside the plot's range: just fill the plot with the settings from 1 point */
|
|
125
145
|
var coverRangeWithPoint = function coverRangeWithPoint(point, plotMin, plotMax) {
|
|
@@ -263,9 +283,9 @@ var TfEditor = function TfEditor(props) {
|
|
|
263
283
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
264
284
|
draggedPointIdx = _useState4[0],
|
|
265
285
|
_setDraggedPointIdx = _useState4[1];
|
|
266
|
-
var _setCPs = useCallback(function (
|
|
286
|
+
var _setCPs = useCallback(function (controlPoints) {
|
|
267
287
|
return changeChannelSetting({
|
|
268
|
-
controlPoints:
|
|
288
|
+
controlPoints: controlPoints
|
|
269
289
|
});
|
|
270
290
|
}, [changeChannelSetting]);
|
|
271
291
|
var setRamp = useCallback(function (ramp) {
|
|
@@ -274,6 +294,12 @@ var TfEditor = function TfEditor(props) {
|
|
|
274
294
|
});
|
|
275
295
|
}, [changeChannelSetting]);
|
|
276
296
|
|
|
297
|
+
// The temporary isovalue used while dragging the isovalue slider, which we only want to update on slider release
|
|
298
|
+
var _useState5 = useState(0),
|
|
299
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
300
|
+
draggedIsovalue = _useState6[0],
|
|
301
|
+
setDraggedIsovalue = _useState6[1];
|
|
302
|
+
|
|
277
303
|
// these bits of state need their freshest, most up-to-date values available in mouse event handlers. make refs!
|
|
278
304
|
var _useRefWithSetter = useRefWithSetter(_setCPs, props.controlPoints),
|
|
279
305
|
_useRefWithSetter2 = _slicedToArray(_useRefWithSetter, 2),
|
|
@@ -286,10 +312,10 @@ var TfEditor = function TfEditor(props) {
|
|
|
286
312
|
|
|
287
313
|
// Either `null` when the control panel is closed, or an x offset into the plot to position the color picker.
|
|
288
314
|
// Positive: offset right from the left edge of the plot; negative: offset left from the right edge of the plot.
|
|
289
|
-
var
|
|
290
|
-
|
|
291
|
-
colorPickerPosition =
|
|
292
|
-
setColorPickerPosition =
|
|
315
|
+
var _useState7 = useState(null),
|
|
316
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
317
|
+
colorPickerPosition = _useState8[0],
|
|
318
|
+
setColorPickerPosition = _useState8[1];
|
|
293
319
|
var lastColorRef = useRef(TFEDITOR_DEFAULT_COLOR);
|
|
294
320
|
var svgRef = useRef(null); // need access to SVG element to measure mouse position
|
|
295
321
|
|
|
@@ -301,22 +327,16 @@ var TfEditor = function TfEditor(props) {
|
|
|
301
327
|
var xScale = useMemo(function () {
|
|
302
328
|
return d3.scaleLinear().domain([plotMin, plotMax]).range([0, innerWidth]);
|
|
303
329
|
}, [innerWidth, plotMin, plotMax]);
|
|
304
|
-
var plotMinU8 = useMemo(function () {
|
|
305
|
-
return absoluteToBin(plotMin, histogram);
|
|
306
|
-
}, [plotMin, histogram]);
|
|
307
|
-
var plotMaxU8 = useMemo(function () {
|
|
308
|
-
return absoluteToBin(plotMax, histogram);
|
|
309
|
-
}, [plotMax, histogram]);
|
|
310
330
|
var yScale = useMemo(function () {
|
|
311
331
|
return d3.scaleLinear().domain([0, 1]).range([innerHeight, 0]);
|
|
312
332
|
}, [innerHeight]);
|
|
313
|
-
var
|
|
333
|
+
var mouseEventToPlotValues = function mouseEventToPlotValues(event) {
|
|
314
334
|
var _svgRef$current$getBo, _svgRef$current;
|
|
315
335
|
var svgRect = (_svgRef$current$getBo = (_svgRef$current = svgRef.current) === null || _svgRef$current === void 0 ? void 0 : _svgRef$current.getBoundingClientRect()) !== null && _svgRef$current$getBo !== void 0 ? _svgRef$current$getBo : {
|
|
316
336
|
x: 0,
|
|
317
337
|
y: 0
|
|
318
338
|
};
|
|
319
|
-
return [
|
|
339
|
+
return [xScale.invert(clamp(event.clientX - svgRect.x - TFEDITOR_MARGINS.left, 0, innerWidth)), yScale.invert(clamp(event.clientY - svgRect.y - TFEDITOR_MARGINS.top, 0, innerHeight))];
|
|
320
340
|
};
|
|
321
341
|
var dragControlPoint = function dragControlPoint(draggedIdx, x, opacity) {
|
|
322
342
|
var newControlPoints = _toConsumableArray(controlPointsRef.current);
|
|
@@ -341,13 +361,18 @@ var TfEditor = function TfEditor(props) {
|
|
|
341
361
|
}
|
|
342
362
|
setControlPoints(newControlPoints);
|
|
343
363
|
};
|
|
344
|
-
var
|
|
345
|
-
if (handle ===
|
|
364
|
+
var dragSlider = function dragSlider(handle, x) {
|
|
365
|
+
if (handle === TfEditorSliderHandle.Min) {
|
|
366
|
+
// dragging the min slider
|
|
346
367
|
var max = props.ramp[1];
|
|
347
368
|
setRamp([Math.min(x, max), max]);
|
|
348
|
-
} else {
|
|
369
|
+
} else if (handle === TfEditorSliderHandle.Max) {
|
|
370
|
+
// dragging the max slider
|
|
349
371
|
var min = props.ramp[0];
|
|
350
372
|
setRamp([min, Math.max(x, min)]);
|
|
373
|
+
} else {
|
|
374
|
+
// dragging the isosurface slider
|
|
375
|
+
setDraggedIsovalue(x);
|
|
351
376
|
}
|
|
352
377
|
};
|
|
353
378
|
var handlePlotPointerDown = function handlePlotPointerDown(event) {
|
|
@@ -355,10 +380,10 @@ var TfEditor = function TfEditor(props) {
|
|
|
355
380
|
// Advanced mode - we're either creating a new control point or selecting/dragging an existing one
|
|
356
381
|
if (draggedPointIdxRef.current === null && event.button === 0) {
|
|
357
382
|
// this click is not on an existing point - create a new one
|
|
358
|
-
var
|
|
359
|
-
|
|
360
|
-
x =
|
|
361
|
-
opacity =
|
|
383
|
+
var _mouseEventToPlotValu = mouseEventToPlotValues(event),
|
|
384
|
+
_mouseEventToPlotValu2 = _slicedToArray(_mouseEventToPlotValu, 2),
|
|
385
|
+
x = _mouseEventToPlotValu2[0],
|
|
386
|
+
opacity = _mouseEventToPlotValu2[1];
|
|
362
387
|
var point = {
|
|
363
388
|
x: x,
|
|
364
389
|
opacity: opacity,
|
|
@@ -398,20 +423,25 @@ var TfEditor = function TfEditor(props) {
|
|
|
398
423
|
}
|
|
399
424
|
event.stopPropagation();
|
|
400
425
|
event.preventDefault();
|
|
401
|
-
var
|
|
402
|
-
|
|
403
|
-
x =
|
|
404
|
-
opacity =
|
|
426
|
+
var _mouseEventToPlotValu3 = mouseEventToPlotValues(event),
|
|
427
|
+
_mouseEventToPlotValu4 = _slicedToArray(_mouseEventToPlotValu3, 2),
|
|
428
|
+
x = _mouseEventToPlotValu4[0],
|
|
429
|
+
opacity = _mouseEventToPlotValu4[1];
|
|
405
430
|
|
|
406
431
|
// `draggedPointIdxRef` may either be a number (control point index) or a string (ramp slider handle).
|
|
407
432
|
// The result of this check should always be the same as `props.useControlPoints`, but this narrows the type for TS
|
|
408
433
|
if (typeof draggedPointIdxRef.current === "number") {
|
|
409
434
|
dragControlPoint(draggedPointIdxRef.current, x, opacity);
|
|
410
435
|
} else {
|
|
411
|
-
|
|
436
|
+
dragSlider(draggedPointIdxRef.current, x);
|
|
412
437
|
}
|
|
413
438
|
};
|
|
414
439
|
var handleDragEnd = function handleDragEnd(event) {
|
|
440
|
+
if (draggedPointIdx === TfEditorSliderHandle.Isosurface) {
|
|
441
|
+
changeChannelSetting({
|
|
442
|
+
isovalue: draggedIsovalue
|
|
443
|
+
});
|
|
444
|
+
}
|
|
415
445
|
setDraggedPointIdx(null);
|
|
416
446
|
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
417
447
|
};
|
|
@@ -444,25 +474,29 @@ var TfEditor = function TfEditor(props) {
|
|
|
444
474
|
};
|
|
445
475
|
var controlPointsToRender = useMemo(function () {
|
|
446
476
|
var points = props.useControlPoints ? props.controlPoints.slice() : rampToControlPoints(props.ramp);
|
|
447
|
-
return fitControlPointsToRange(points,
|
|
448
|
-
}, [props.controlPoints, props.ramp, props.useControlPoints,
|
|
477
|
+
return fitControlPointsToRange(points, plotMin, plotMax);
|
|
478
|
+
}, [props.controlPoints, props.ramp, props.useControlPoints, plotMin, plotMax]);
|
|
449
479
|
|
|
450
480
|
/** d3-generated svg data string representing both the line between points and the region filled with gradient */
|
|
451
481
|
var areaPath = useMemo(function () {
|
|
452
482
|
var _areaGenerator;
|
|
453
483
|
var areaGenerator = d3.area().x(function (d) {
|
|
454
|
-
return xScale(
|
|
484
|
+
return xScale(d.x);
|
|
455
485
|
}).y0(function (d) {
|
|
456
486
|
return yScale(d.opacity);
|
|
457
487
|
}).y1(innerHeight).curve(d3.curveLinear);
|
|
458
488
|
return (_areaGenerator = areaGenerator(controlPointsToRender)) !== null && _areaGenerator !== void 0 ? _areaGenerator : undefined;
|
|
459
|
-
}, [controlPointsToRender, xScale, yScale, innerHeight
|
|
489
|
+
}, [controlPointsToRender, xScale, yScale, innerHeight]);
|
|
460
490
|
|
|
461
491
|
/** d3-generated svg data string representing the "basic mode" min/max slider handles */
|
|
462
492
|
var sliderHandlePath = useMemo(function () {
|
|
463
493
|
var _d3$symbol$type$size;
|
|
464
494
|
return (_d3$symbol$type$size = d3.symbol().type(sliderHandleSymbol).size(80)()) !== null && _d3$symbol$type$size !== void 0 ? _d3$symbol$type$size : undefined;
|
|
465
495
|
}, []);
|
|
496
|
+
var isovalueHandlePath = useMemo(function () {
|
|
497
|
+
var _d3$symbol$type$size2;
|
|
498
|
+
return (_d3$symbol$type$size2 = d3.symbol().type(isovalueHandleSymbol).size(21)()) !== null && _d3$symbol$type$size2 !== void 0 ? _d3$symbol$type$size2 : undefined;
|
|
499
|
+
}, []);
|
|
466
500
|
|
|
467
501
|
// The below `useCallback`s are used as "ref callbacks" - passed as the `ref` prop of SVG elements in order to render
|
|
468
502
|
// these elements' content using D3. They are called when the ref'd component mounts and unmounts, and whenever their
|
|
@@ -504,6 +538,8 @@ var TfEditor = function TfEditor(props) {
|
|
|
504
538
|
if (numBins < 1) {
|
|
505
539
|
return;
|
|
506
540
|
}
|
|
541
|
+
var plotMinU8 = histogram.findFractionalBinOfValue(plotMin);
|
|
542
|
+
var plotMaxU8 = histogram.findFractionalBinOfValue(plotMax);
|
|
507
543
|
var _getHistogramBinLengt = getHistogramBinLengths(histogram),
|
|
508
544
|
binLengths = _getHistogramBinLengt.binLengths,
|
|
509
545
|
max = _getHistogramBinLengt.max;
|
|
@@ -516,100 +552,113 @@ var TfEditor = function TfEditor(props) {
|
|
|
516
552
|
.data(binLengthsToRender) // bind the histogram bins to this selection
|
|
517
553
|
.join("rect") // ensure we have exactly as many bound `rect` elements in the DOM as we have histogram bins
|
|
518
554
|
.attr("class", "bar").attr("width", barWidth).attr("x", function (_len, idx) {
|
|
519
|
-
return xScale(
|
|
555
|
+
return xScale(histogram.getValueFromBinIndex(idx + start));
|
|
520
556
|
}) // set position and height from data
|
|
521
557
|
.attr("y", function (len) {
|
|
522
558
|
return binScale(len);
|
|
523
559
|
}).attr("height", function (len) {
|
|
524
560
|
return innerHeight - binScale(len);
|
|
525
561
|
});
|
|
526
|
-
}, [xScale, histogram, innerWidth, innerHeight,
|
|
562
|
+
}, [xScale, histogram, innerWidth, innerHeight, plotMin, plotMax]);
|
|
527
563
|
var applyTFGenerator = useCallback(function (generator) {
|
|
528
564
|
setSelectedPointIdx(null);
|
|
529
565
|
lastColorRef.current = TFEDITOR_DEFAULT_COLOR;
|
|
530
566
|
var lut = TF_GENERATORS[generator](histogram);
|
|
567
|
+
var valueIndexedControlPoints = lut.controlPoints.map(function (cp) {
|
|
568
|
+
return _objectSpread(_objectSpread({}, cp), {}, {
|
|
569
|
+
x: histogram.getValueFromBinIndex(cp.x)
|
|
570
|
+
});
|
|
571
|
+
});
|
|
531
572
|
if (props.useControlPoints) {
|
|
532
|
-
setControlPoints(
|
|
573
|
+
setControlPoints(valueIndexedControlPoints.map(function (cp) {
|
|
533
574
|
return _objectSpread(_objectSpread({}, cp), {}, {
|
|
534
575
|
color: TFEDITOR_DEFAULT_COLOR
|
|
535
576
|
});
|
|
536
577
|
}));
|
|
537
578
|
} else {
|
|
538
|
-
setRamp(controlPointsToRamp(
|
|
579
|
+
setRamp(controlPointsToRamp(valueIndexedControlPoints));
|
|
539
580
|
}
|
|
540
581
|
}, [histogram, props.useControlPoints, setControlPoints, setRamp]);
|
|
541
|
-
var
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
cy: yScale(cp.opacity),
|
|
563
|
-
style: {
|
|
564
|
-
fill: colorArrayToString(cp.color)
|
|
565
|
-
},
|
|
566
|
-
r: 5,
|
|
567
|
-
onPointerDown: function onPointerDown() {
|
|
568
|
-
return setDraggedPointIdx(i);
|
|
569
|
-
},
|
|
570
|
-
onContextMenu: handleControlPointContextMenu
|
|
582
|
+
var controlPointCircles = null;
|
|
583
|
+
if (props.volumeEnabled && props.useControlPoints) {
|
|
584
|
+
// create one svg circle element for each control point
|
|
585
|
+
controlPointCircles = props.controlPoints.filter(function (cp) {
|
|
586
|
+
return plotMin <= cp.x && cp.x <= plotMax;
|
|
587
|
+
}) // filter out-of-range points
|
|
588
|
+
.map(function (cp, i) {
|
|
589
|
+
return /*#__PURE__*/React.createElement("circle", {
|
|
590
|
+
key: i,
|
|
591
|
+
className: i === selectedPointIdx ? "selected" : "",
|
|
592
|
+
cx: xScale(cp.x),
|
|
593
|
+
cy: yScale(cp.opacity),
|
|
594
|
+
style: {
|
|
595
|
+
fill: colorArrayToString(cp.color)
|
|
596
|
+
},
|
|
597
|
+
r: 5,
|
|
598
|
+
onPointerDown: function onPointerDown() {
|
|
599
|
+
return setDraggedPointIdx(i);
|
|
600
|
+
},
|
|
601
|
+
onContextMenu: handleControlPointContextMenu
|
|
602
|
+
});
|
|
571
603
|
});
|
|
572
|
-
}
|
|
604
|
+
}
|
|
573
605
|
// move selected control point to the end so it's drawn last and not occluded by other nearby points
|
|
574
606
|
if (controlPointCircles !== null && selectedPointIdx !== null) {
|
|
575
607
|
controlPointCircles.push(controlPointCircles.splice(selectedPointIdx, 1)[0]);
|
|
576
608
|
}
|
|
577
|
-
var
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
609
|
+
var dragClass = draggedPointIdx === null ? "" : typeof draggedPointIdx === "number" ? " dragging-point" : " dragging-slider";
|
|
610
|
+
var isovalue = draggedPointIdx === TfEditorSliderHandle.Isosurface ? draggedIsovalue : props.isovalue;
|
|
611
|
+
var useRamp = props.volumeEnabled && !props.useControlPoints;
|
|
612
|
+
var _props$channelData = props.channelData,
|
|
613
|
+
rawMin = _props$channelData.rawMin,
|
|
614
|
+
rawMax = _props$channelData.rawMax;
|
|
615
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
616
|
+
className: "tf-editor"
|
|
617
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
618
|
+
className: "tf-editor-control-row"
|
|
619
|
+
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Button, {
|
|
620
|
+
size: "small",
|
|
621
|
+
onClick: function onClick() {
|
|
583
622
|
return changeChannelSetting({
|
|
584
|
-
|
|
623
|
+
plotMin: rawMin,
|
|
624
|
+
plotMax: rawMax
|
|
585
625
|
});
|
|
586
|
-
},
|
|
587
|
-
style: {
|
|
588
|
-
marginLeft: "auto"
|
|
589
626
|
}
|
|
590
|
-
}, "
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
627
|
+
}, "Fit to data"), /*#__PURE__*/React.createElement(Button, {
|
|
628
|
+
size: "small",
|
|
629
|
+
onClick: function onClick() {
|
|
630
|
+
return changeChannelSetting({
|
|
631
|
+
plotMin: typeRange.min,
|
|
632
|
+
plotMax: typeRange.max
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}, "Full range")), /*#__PURE__*/React.createElement("div", null, "Plot min/max", /*#__PURE__*/React.createElement(InputNumber, {
|
|
636
|
+
value: plotMin,
|
|
594
637
|
onChange: function onChange(v) {
|
|
595
|
-
return v !== null &&
|
|
638
|
+
return v !== null && changeChannelSetting({
|
|
639
|
+
plotMin: v,
|
|
640
|
+
plotMax: Math.max(v + 1, plotMax)
|
|
641
|
+
});
|
|
596
642
|
},
|
|
597
643
|
formatter: numberFormatter,
|
|
598
644
|
min: typeRange.min,
|
|
599
|
-
max:
|
|
645
|
+
max: typeRange.max - 1,
|
|
600
646
|
size: "small",
|
|
601
647
|
controls: false
|
|
602
648
|
}), /*#__PURE__*/React.createElement(InputNumber, {
|
|
603
|
-
value:
|
|
649
|
+
value: plotMax,
|
|
604
650
|
onChange: function onChange(v) {
|
|
605
|
-
return v !== null &&
|
|
651
|
+
return v !== null && changeChannelSetting({
|
|
652
|
+
plotMax: v,
|
|
653
|
+
plotMin: Math.min(v - 1, plotMin)
|
|
654
|
+
});
|
|
606
655
|
},
|
|
607
656
|
formatter: numberFormatter,
|
|
608
|
-
min:
|
|
657
|
+
min: typeRange.min + 1,
|
|
609
658
|
max: typeRange.max,
|
|
610
659
|
size: "small",
|
|
611
660
|
controls: false
|
|
612
|
-
})), colorPickerPosition !== null && /*#__PURE__*/React.createElement("div", {
|
|
661
|
+
}))), colorPickerPosition !== null && /*#__PURE__*/React.createElement("div", {
|
|
613
662
|
className: "tf-editor-popover"
|
|
614
663
|
}, /*#__PURE__*/React.createElement("div", {
|
|
615
664
|
className: "tf-editor-cover",
|
|
@@ -623,7 +672,7 @@ var TfEditor = function TfEditor(props) {
|
|
|
623
672
|
onChange: handleChangeColor,
|
|
624
673
|
disableAlpha: true
|
|
625
674
|
}))), /*#__PURE__*/React.createElement("svg", {
|
|
626
|
-
className: "tf-editor-svg
|
|
675
|
+
className: "tf-editor-svg".concat(dragClass),
|
|
627
676
|
ref: svgRef,
|
|
628
677
|
width: props.width,
|
|
629
678
|
height: props.height,
|
|
@@ -637,7 +686,7 @@ var TfEditor = function TfEditor(props) {
|
|
|
637
686
|
transform: "translate(".concat(TFEDITOR_MARGINS.left, ",").concat(TFEDITOR_MARGINS.top, ")")
|
|
638
687
|
}, /*#__PURE__*/React.createElement("g", {
|
|
639
688
|
ref: histogramRef
|
|
640
|
-
}), /*#__PURE__*/React.createElement("path", {
|
|
689
|
+
}), props.volumeEnabled && /*#__PURE__*/React.createElement("path", {
|
|
641
690
|
className: "line",
|
|
642
691
|
fill: "url(#tfGradient-".concat(props.id, ")"),
|
|
643
692
|
d: areaPath
|
|
@@ -648,109 +697,210 @@ var TfEditor = function TfEditor(props) {
|
|
|
648
697
|
}), /*#__PURE__*/React.createElement("g", {
|
|
649
698
|
ref: yAxisRef,
|
|
650
699
|
className: "axis"
|
|
651
|
-
}), controlPointCircles, !props.useControlPoints && /*#__PURE__*/React.createElement("g", {
|
|
652
|
-
className: "ramp
|
|
653
|
-
},
|
|
654
|
-
transform: "translate(".concat(xScale(
|
|
700
|
+
}), controlPointCircles, props.volumeEnabled && !props.useControlPoints && /*#__PURE__*/React.createElement("g", {
|
|
701
|
+
className: "sliders sliders-ramp"
|
|
702
|
+
}, plotMin <= props.ramp[0] && props.ramp[0] <= plotMax && /*#__PURE__*/React.createElement("g", {
|
|
703
|
+
transform: "translate(".concat(xScale(props.ramp[0]), ")")
|
|
655
704
|
}, /*#__PURE__*/React.createElement("line", {
|
|
656
705
|
y1: innerHeight,
|
|
657
706
|
strokeDasharray: "5,5",
|
|
658
707
|
strokeWidth: 2
|
|
659
708
|
}), /*#__PURE__*/React.createElement("line", {
|
|
660
|
-
className: "
|
|
709
|
+
className: "slider-click-target",
|
|
661
710
|
y1: innerHeight,
|
|
662
711
|
strokeWidth: 6,
|
|
663
712
|
onPointerDown: function onPointerDown() {
|
|
664
|
-
return setDraggedPointIdx(
|
|
713
|
+
return setDraggedPointIdx(TfEditorSliderHandle.Min);
|
|
665
714
|
}
|
|
666
715
|
}), /*#__PURE__*/React.createElement("path", {
|
|
667
716
|
d: sliderHandlePath,
|
|
668
717
|
transform: "translate(0,".concat(innerHeight, ") rotate(180)"),
|
|
669
718
|
onPointerDown: function onPointerDown() {
|
|
670
|
-
return setDraggedPointIdx(
|
|
719
|
+
return setDraggedPointIdx(TfEditorSliderHandle.Min);
|
|
671
720
|
}
|
|
672
|
-
})),
|
|
673
|
-
transform: "translate(".concat(xScale(
|
|
721
|
+
})), plotMin <= props.ramp[1] && props.ramp[1] <= plotMax && /*#__PURE__*/React.createElement("g", {
|
|
722
|
+
transform: "translate(".concat(xScale(props.ramp[1]), ")")
|
|
674
723
|
}, /*#__PURE__*/React.createElement("line", {
|
|
675
724
|
y1: innerHeight,
|
|
676
725
|
strokeDasharray: "5,5",
|
|
677
726
|
strokeWidth: 2
|
|
678
727
|
}), /*#__PURE__*/React.createElement("line", {
|
|
679
|
-
className: "
|
|
728
|
+
className: "slider-click-target",
|
|
680
729
|
y1: innerHeight,
|
|
681
730
|
strokeWidth: 6,
|
|
682
731
|
onPointerDown: function onPointerDown() {
|
|
683
|
-
return setDraggedPointIdx(
|
|
732
|
+
return setDraggedPointIdx(TfEditorSliderHandle.Max);
|
|
684
733
|
}
|
|
685
734
|
}), /*#__PURE__*/React.createElement("path", {
|
|
686
735
|
d: sliderHandlePath,
|
|
687
736
|
onPointerDown: function onPointerDown() {
|
|
688
|
-
return setDraggedPointIdx(
|
|
737
|
+
return setDraggedPointIdx(TfEditorSliderHandle.Max);
|
|
689
738
|
}
|
|
690
|
-
})))
|
|
691
|
-
className: "
|
|
692
|
-
|
|
693
|
-
|
|
739
|
+
}))), props.isosurfaceEnabled && plotMin <= isovalue && isovalue <= plotMax && /*#__PURE__*/React.createElement("g", {
|
|
740
|
+
className: "sliders sliders-isovalue",
|
|
741
|
+
transform: "translate(".concat(xScale(isovalue), ")")
|
|
742
|
+
}, /*#__PURE__*/React.createElement("line", {
|
|
743
|
+
className: "slider-isosurface",
|
|
744
|
+
y1: innerHeight,
|
|
745
|
+
strokeDasharray: "4,4",
|
|
746
|
+
strokeWidth: 2
|
|
747
|
+
}), /*#__PURE__*/React.createElement("line", {
|
|
748
|
+
className: "slider-click-target",
|
|
749
|
+
y1: innerHeight,
|
|
750
|
+
strokeWidth: 6,
|
|
751
|
+
onPointerDown: function onPointerDown() {
|
|
752
|
+
setDraggedIsovalue(props.isovalue);
|
|
753
|
+
setDraggedPointIdx(TfEditorSliderHandle.Isosurface);
|
|
754
|
+
}
|
|
755
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
756
|
+
d: isovalueHandlePath,
|
|
757
|
+
onPointerDown: function onPointerDown() {
|
|
758
|
+
return setDraggedPointIdx(TfEditorSliderHandle.Isosurface);
|
|
759
|
+
}
|
|
760
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
761
|
+
d: isovalueHandlePath,
|
|
762
|
+
transform: "translate(0,".concat(innerHeight, ") rotate(180)"),
|
|
763
|
+
onPointerDown: function onPointerDown() {
|
|
764
|
+
return setDraggedPointIdx(TfEditorSliderHandle.Isosurface);
|
|
765
|
+
}
|
|
766
|
+
})))), props.volumeEnabled && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h4", null, "Volume settings"), /*#__PURE__*/React.createElement("div", {
|
|
767
|
+
className: "tf-editor-control-row"
|
|
768
|
+
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Dropdown, {
|
|
769
|
+
trigger: ["click"],
|
|
770
|
+
menu: {
|
|
771
|
+
items: [{
|
|
772
|
+
key: "auto98XF",
|
|
773
|
+
label: "Default (50% - 98%)"
|
|
774
|
+
}, {
|
|
775
|
+
key: "auto2XF",
|
|
776
|
+
label: "ImageJ Auto"
|
|
777
|
+
}, {
|
|
778
|
+
key: "resetXF",
|
|
779
|
+
label: "Auto 1 (0% - 100%)"
|
|
780
|
+
}, {
|
|
781
|
+
key: "bestFitXF",
|
|
782
|
+
label: "Auto 2 (10% - 90%)"
|
|
783
|
+
}],
|
|
784
|
+
onClick: function onClick(_ref5) {
|
|
785
|
+
var key = _ref5.key;
|
|
786
|
+
return applyTFGenerator(key);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
790
|
+
size: "small"
|
|
791
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
792
|
+
style: {
|
|
793
|
+
display: "flex",
|
|
794
|
+
flexDirection: "row",
|
|
795
|
+
alignItems: "center",
|
|
796
|
+
gap: "4px"
|
|
797
|
+
}
|
|
798
|
+
}, "Apply ramp", /*#__PURE__*/React.createElement(ViewerIcon, {
|
|
799
|
+
type: "dropdownArrow",
|
|
800
|
+
style: {
|
|
801
|
+
fontSize: "14px"
|
|
802
|
+
}
|
|
803
|
+
}))))), /*#__PURE__*/React.createElement("div", null, useRamp && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", null, "Levels min/max"), /*#__PURE__*/React.createElement(InputNumber, {
|
|
804
|
+
value: props.ramp[0],
|
|
694
805
|
onChange: function onChange(v) {
|
|
695
|
-
return v !== null &&
|
|
696
|
-
plotMin: v,
|
|
697
|
-
plotMax: Math.max(v + 1, plotMax)
|
|
698
|
-
});
|
|
806
|
+
return v !== null && setRamp([v, props.ramp[1]]);
|
|
699
807
|
},
|
|
700
808
|
formatter: numberFormatter,
|
|
701
809
|
min: typeRange.min,
|
|
702
|
-
max: typeRange.max
|
|
810
|
+
max: Math.min(props.ramp[1], typeRange.max),
|
|
703
811
|
size: "small",
|
|
704
812
|
controls: false
|
|
705
813
|
}), /*#__PURE__*/React.createElement(InputNumber, {
|
|
706
|
-
value:
|
|
814
|
+
value: props.ramp[1],
|
|
707
815
|
onChange: function onChange(v) {
|
|
708
|
-
return v !== null &&
|
|
709
|
-
plotMax: v,
|
|
710
|
-
plotMin: Math.min(v - 1, plotMin)
|
|
711
|
-
});
|
|
816
|
+
return v !== null && setRamp([props.ramp[0], v]);
|
|
712
817
|
},
|
|
713
818
|
formatter: numberFormatter,
|
|
714
|
-
min: typeRange.min
|
|
819
|
+
min: Math.max(typeRange.min, props.ramp[0]),
|
|
715
820
|
max: typeRange.max,
|
|
716
821
|
size: "small",
|
|
717
822
|
controls: false
|
|
718
|
-
}), /*#__PURE__*/React.createElement(
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
marginLeft: "12px"
|
|
722
|
-
},
|
|
723
|
-
onClick: function onClick() {
|
|
724
|
-
return changeChannelSetting({
|
|
725
|
-
plotMin: props.channelData.rawMin,
|
|
726
|
-
plotMax: props.channelData.rawMax
|
|
727
|
-
});
|
|
728
|
-
}
|
|
729
|
-
}, "Fit to data"), /*#__PURE__*/React.createElement(Button, {
|
|
730
|
-
size: "small",
|
|
823
|
+
}), /*#__PURE__*/React.createElement(Tooltip, {
|
|
824
|
+
title: "".concat(props.keepIntensityRange ? "Do not keep" : "Keep", " intensity threshold values when switching volumes.")
|
|
825
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
731
826
|
onClick: function onClick() {
|
|
732
|
-
return changeChannelSetting({
|
|
733
|
-
|
|
734
|
-
plotMax: typeRange.max
|
|
827
|
+
return props.changeChannelSetting({
|
|
828
|
+
keepIntensityRange: !props.keepIntensityRange
|
|
735
829
|
});
|
|
830
|
+
},
|
|
831
|
+
style: {
|
|
832
|
+
height: 24,
|
|
833
|
+
padding: "0 4px"
|
|
834
|
+
},
|
|
835
|
+
type: props.keepIntensityRange ? "default" : "text"
|
|
836
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
837
|
+
style: {
|
|
838
|
+
margin: 0
|
|
736
839
|
}
|
|
737
|
-
},
|
|
738
|
-
label: /*#__PURE__*/React.createElement(Checkbox, {
|
|
840
|
+
}, props.keepIntensityRange ? /*#__PURE__*/React.createElement(PushpinFilled, null) : /*#__PURE__*/React.createElement(PushpinOutlined, null))))))), /*#__PURE__*/React.createElement(SliderRow, {
|
|
841
|
+
label: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Checkbox, {
|
|
842
|
+
checked: props.useControlPoints,
|
|
843
|
+
onChange: function onChange(e) {
|
|
844
|
+
return changeChannelSetting({
|
|
845
|
+
useControlPoints: e.target.checked
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
}, "Advanced"), /*#__PURE__*/React.createElement(Checkbox, {
|
|
739
849
|
checked: props.colorizeEnabled,
|
|
740
850
|
onChange: function onChange(e) {
|
|
741
851
|
return changeChannelSetting({
|
|
742
852
|
colorizeEnabled: e.target.checked
|
|
743
853
|
});
|
|
854
|
+
},
|
|
855
|
+
style: {
|
|
856
|
+
marginLeft: "5px"
|
|
744
857
|
}
|
|
745
|
-
}, "Colorize"),
|
|
858
|
+
}, "Colorize")),
|
|
746
859
|
max: 1,
|
|
747
860
|
start: props.colorizeAlpha,
|
|
748
|
-
onUpdate: function onUpdate(
|
|
861
|
+
onUpdate: function onUpdate(_ref6) {
|
|
862
|
+
var _ref7 = _slicedToArray(_ref6, 1),
|
|
863
|
+
colorizeAlpha = _ref7[0];
|
|
749
864
|
return changeChannelSetting({
|
|
750
|
-
colorizeAlpha:
|
|
865
|
+
colorizeAlpha: colorizeAlpha
|
|
751
866
|
});
|
|
752
867
|
},
|
|
753
868
|
hideSlider: !props.colorizeEnabled
|
|
754
|
-
}))
|
|
869
|
+
})), props.isosurfaceEnabled && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h4", null, "Isosurface settings"), /*#__PURE__*/React.createElement("div", {
|
|
870
|
+
className: "tf-editor-control-row"
|
|
871
|
+
}, /*#__PURE__*/React.createElement("div", null, "Isovalue", /*#__PURE__*/React.createElement(InputNumber, {
|
|
872
|
+
value: props.isovalue,
|
|
873
|
+
onChange: function onChange(isovalue) {
|
|
874
|
+
return isovalue !== null && changeChannelSetting({
|
|
875
|
+
isovalue: isovalue
|
|
876
|
+
});
|
|
877
|
+
},
|
|
878
|
+
formatter: numberFormatter,
|
|
879
|
+
min: typeRange.min,
|
|
880
|
+
max: typeRange.max,
|
|
881
|
+
size: "small",
|
|
882
|
+
controls: false
|
|
883
|
+
})), /*#__PURE__*/React.createElement("div", null, "Export surface", /*#__PURE__*/React.createElement(Button, {
|
|
884
|
+
size: "small",
|
|
885
|
+
onClick: function onClick() {
|
|
886
|
+
return props.saveIsosurface("GLTF");
|
|
887
|
+
}
|
|
888
|
+
}, "GLTF"), /*#__PURE__*/React.createElement(Button, {
|
|
889
|
+
size: "small",
|
|
890
|
+
onClick: function onClick() {
|
|
891
|
+
return props.saveIsosurface("STL");
|
|
892
|
+
}
|
|
893
|
+
}, "STL"))), /*#__PURE__*/React.createElement(SliderRow, {
|
|
894
|
+
label: "Opacity",
|
|
895
|
+
max: 1.0,
|
|
896
|
+
start: props.opacity,
|
|
897
|
+
onUpdate: function onUpdate(_ref8) {
|
|
898
|
+
var _ref9 = _slicedToArray(_ref8, 1),
|
|
899
|
+
opacity = _ref9[0];
|
|
900
|
+
return changeChannelSetting({
|
|
901
|
+
opacity: opacity
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
})));
|
|
755
905
|
};
|
|
756
906
|
export default TfEditor;
|