@complat/react-spectra-editor 1.7.1 → 1.8.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.
Files changed (111) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -662
  3. package/README.md +5 -0
  4. package/dist/__tests__/fixtures/lc_ms_jcamp.js +2329 -0
  5. package/dist/__tests__/fixtures/lc_ms_jcamp_2.js +2874 -0
  6. package/dist/__tests__/fixtures/lc_ms_jcamp_mz_chemstation.js +3242 -0
  7. package/dist/__tests__/fixtures/lc_ms_jcamp_tic_chemstation.js +854 -0
  8. package/dist/__tests__/fixtures/lc_ms_jcamp_tic_neg.js +1233 -0
  9. package/dist/__tests__/fixtures/lc_ms_jcamp_tic_pos.js +1233 -0
  10. package/dist/__tests__/fixtures/lc_ms_jcamp_uvvis.js +48908 -0
  11. package/dist/__tests__/fixtures/lc_ms_jcamp_uvvis_chemstation.js +15424 -0
  12. package/dist/__tests__/units/components/cmd_bar/r05_submit_btn.test.js +158 -3
  13. package/dist/__tests__/units/components/d3_line_rect.test.js +85 -0
  14. package/dist/__tests__/units/components/d3_multi/multi_focus.test.js +43 -0
  15. package/dist/__tests__/units/components/hplc_viewer.test.js +123 -0
  16. package/dist/__tests__/units/components/panel/info.test.js +55 -15
  17. package/dist/__tests__/units/features/lc-ms/parsing/lcmsCategory.test.js +73 -0
  18. package/dist/__tests__/units/features/lc-ms/submit/peaks.test.js +310 -0
  19. package/dist/actions/curve.js +5 -2
  20. package/dist/actions/hplc_ms.js +66 -0
  21. package/dist/actions/integration.js +17 -2
  22. package/dist/actions/ui.js +39 -11
  23. package/dist/app.js +21 -8
  24. package/dist/components/cmd_bar/01_viewer.js +15 -11
  25. package/dist/components/cmd_bar/03_peak.js +25 -16
  26. package/dist/components/cmd_bar/04_integration.js +116 -17
  27. package/dist/components/cmd_bar/08_peak_group.js +83 -0
  28. package/dist/components/cmd_bar/collapsible_toolbar_group.js +101 -0
  29. package/dist/components/cmd_bar/common.js +4 -3
  30. package/dist/components/cmd_bar/index.js +76 -18
  31. package/dist/components/cmd_bar/r01_layout.js +6 -0
  32. package/dist/components/cmd_bar/r02_scan.js +15 -11
  33. package/dist/components/cmd_bar/r03_threshold.js +19 -3
  34. package/dist/components/cmd_bar/r04_submit.js +61 -6
  35. package/dist/components/cmd_bar/r05_submit_btn.js +60 -13
  36. package/dist/components/cmd_bar/r06_predict_btn.js +4 -4
  37. package/dist/components/cmd_bar/r07_wavelength_btn.js +10 -9
  38. package/dist/components/cmd_bar/r09_detector.js +2 -2
  39. package/dist/components/cmd_bar/tri_btn.js +4 -1
  40. package/dist/components/common/draw.js +6 -5
  41. package/dist/components/d3_line/index.js +70 -15
  42. package/dist/components/d3_line/line_focus.js +104 -67
  43. package/dist/components/d3_line_rect/index.js +836 -0
  44. package/dist/components/d3_line_rect/line_focus.js +526 -0
  45. package/dist/components/d3_line_rect/multi_focus.js +433 -0
  46. package/dist/components/d3_line_rect/rect_focus.js +247 -0
  47. package/dist/components/d3_multi/index.js +154 -163
  48. package/dist/components/d3_multi/multi_focus.js +117 -68
  49. package/dist/components/d3_rect/index.js +6 -0
  50. package/dist/components/d3_rect/rect_focus.js +17 -5
  51. package/dist/components/hplc_viewer.js +169 -0
  52. package/dist/components/lc_ms_uv_tools_bar.js +175 -0
  53. package/dist/components/multi_jcamps_viewer.js +17 -5
  54. package/dist/components/panel/compare.js +84 -62
  55. package/dist/components/panel/cyclic_voltamery_data.js +15 -14
  56. package/dist/components/panel/graph_selection.js +32 -30
  57. package/dist/components/panel/index.js +28 -22
  58. package/dist/components/panel/info.js +75 -26
  59. package/dist/constants/action_type.js +23 -2
  60. package/dist/constants/list_graph.js +16 -0
  61. package/dist/constants/list_layout.js +2 -1
  62. package/dist/constants/list_ui.js +5 -2
  63. package/dist/features/lc-ms/entities/extractEntityLCMS.js +187 -0
  64. package/dist/features/lc-ms/parsing/chemstation.js +108 -0
  65. package/dist/features/lc-ms/parsing/index.js +46 -0
  66. package/dist/features/lc-ms/parsing/lcmsCategory.js +44 -0
  67. package/dist/features/lc-ms/parsing/lcmsJcampInfo.js +18 -0
  68. package/dist/features/lc-ms/parsing/lcmsMsPage.js +241 -0
  69. package/dist/features/lc-ms/parsing/pageValue.js +27 -0
  70. package/dist/features/lc-ms/submit/index.js +24 -0
  71. package/dist/features/lc-ms/submit/peaks.js +66 -0
  72. package/dist/features/lc-ms/ui/wavelengthSelect.js +54 -0
  73. package/dist/fn.js +4 -1
  74. package/dist/helpers/brush.js +74 -19
  75. package/dist/helpers/calc.js +4 -2
  76. package/dist/helpers/cfg.js +5 -4
  77. package/dist/helpers/chem.js +449 -71
  78. package/dist/helpers/compass.js +181 -17
  79. package/dist/helpers/extractEntityLCMS.js +24 -0
  80. package/dist/helpers/extractParams.js +118 -33
  81. package/dist/helpers/extractPeaksEdit.js +29 -9
  82. package/dist/helpers/format.js +189 -4
  83. package/dist/helpers/init.js +25 -5
  84. package/dist/helpers/integration.js +130 -17
  85. package/dist/helpers/integration_draft.js +43 -0
  86. package/dist/helpers/integration_focus.js +155 -0
  87. package/dist/helpers/integration_jcamp.js +68 -0
  88. package/dist/helpers/integration_split.js +202 -0
  89. package/dist/helpers/mount.js +8 -1
  90. package/dist/helpers/sweep.js +39 -0
  91. package/dist/index.js +284 -26
  92. package/dist/layer_content.js +17 -3
  93. package/dist/layer_init.js +124 -14
  94. package/dist/layer_prism.js +31 -5
  95. package/dist/reducers/index.js +3 -1
  96. package/dist/reducers/reducer_curve.js +54 -36
  97. package/dist/reducers/reducer_hplc_ms/hydrate.js +289 -0
  98. package/dist/reducers/reducer_hplc_ms/index.js +122 -0
  99. package/dist/reducers/reducer_hplc_ms/persistence.js +74 -0
  100. package/dist/reducers/reducer_hplc_ms/tic.js +70 -0
  101. package/dist/reducers/reducer_hplc_ms/utils.js +70 -0
  102. package/dist/reducers/reducer_hplc_ms/uvvis.js +377 -0
  103. package/dist/reducers/reducer_integration.js +265 -7
  104. package/dist/reducers/reducer_layout.js +1 -1
  105. package/dist/reducers/reducer_submit.js +2 -1
  106. package/dist/reducers/reducer_ui.js +149 -13
  107. package/dist/reducers/undo_redo_config.js +2 -2
  108. package/dist/sagas/saga_lcms_ui.js +85 -0
  109. package/dist/sagas/saga_ui.js +177 -74
  110. package/dist/setupTests.js +5 -5
  111. package/package.json +10 -7
@@ -0,0 +1,836 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.isLcmsMsPageLoading = exports.default = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactRedux = require("react-redux");
10
+ var _redux = require("redux");
11
+ var _propTypes = _interopRequireDefault(require("prop-types"));
12
+ var _classnames = _interopRequireDefault(require("classnames"));
13
+ var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
14
+ var _material = require("@mui/material");
15
+ var _ZoomInOutlined = _interopRequireDefault(require("@mui/icons-material/ZoomInOutlined"));
16
+ var _FindReplaceOutlined = _interopRequireDefault(require("@mui/icons-material/FindReplaceOutlined"));
17
+ var _Undo = _interopRequireDefault(require("@mui/icons-material/Undo"));
18
+ var _Redo = _interopRequireDefault(require("@mui/icons-material/Redo"));
19
+ var _common = require("../cmd_bar/common");
20
+ var _chem = require("../../helpers/chem");
21
+ var _manager = require("../../actions/manager");
22
+ var _ui = require("../../actions/ui");
23
+ var _hplc_ms = require("../../actions/hplc_ms");
24
+ var _curve = require("../../actions/curve");
25
+ var _rect_focus = _interopRequireDefault(require("./rect_focus"));
26
+ var _multi_focus = _interopRequireDefault(require("./multi_focus"));
27
+ var _line_focus = _interopRequireDefault(require("./line_focus"));
28
+ var _extractParams = require("../../helpers/extractParams");
29
+ var _calc = require("../../helpers/calc");
30
+ var _draw = require("../common/draw");
31
+ var _list_ui = require("../../constants/list_ui");
32
+ var _wavelengthSelect = _interopRequireDefault(require("../../features/lc-ms/ui/wavelengthSelect"));
33
+ var _pageValue = require("../../features/lc-ms/parsing/pageValue");
34
+ var _list_graph = require("../../constants/list_graph");
35
+ var _peak_group = _interopRequireDefault(require("../cmd_bar/08_peak_group"));
36
+ var _r03_threshold = _interopRequireDefault(require("../cmd_bar/r03_threshold"));
37
+ var _integration = _interopRequireDefault(require("../cmd_bar/04_integration"));
38
+ var _peak = _interopRequireDefault(require("../cmd_bar/03_peak"));
39
+ var _extractEntityLCMS = require("../../helpers/extractEntityLCMS");
40
+ var _jsxRuntime = require("react/jsx-runtime");
41
+ /* eslint-disable no-mixed-operators, prefer-object-spread, react/function-component-definition */
42
+
43
+ const W = Math.round(window.innerWidth * 0.90 * 9 / 12); // ROI
44
+ const H = Math.round(window.innerHeight * 0.90 * 0.8 / 3); // ROI
45
+
46
+ const toSeed = (xValues = [], yValues = []) => {
47
+ const maxLength = Math.min(xValues.length, yValues.length);
48
+ const seed = new Array(maxLength);
49
+ for (let index = 0; index < maxLength; index += 1) {
50
+ seed[index] = {
51
+ x: xValues[index],
52
+ y: yValues[index]
53
+ };
54
+ }
55
+ return seed;
56
+ };
57
+ const isLcmsMsPageLoading = (mzEntities = [], hplcMsSt = {}) => {
58
+ const currentPageValue = hplcMsSt?.tic?.currentPageValue;
59
+ if (!Number.isFinite(currentPageValue)) return false;
60
+ const polarity = hplcMsSt?.tic?.polarity;
61
+ const pickEntity = mzEntities?.find(ent => (0, _extractEntityLCMS.getLcMsInfo)(ent).polarity === polarity) || mzEntities?.[0];
62
+ if (!pickEntity) return true;
63
+ const {
64
+ features
65
+ } = (0, _extractParams.extractParams)(pickEntity, null, null);
66
+ let featuresArr = [];
67
+ if (Array.isArray(features)) {
68
+ featuresArr = features;
69
+ } else if (features && typeof features === 'object') {
70
+ featuresArr = Object.values(features);
71
+ }
72
+ if (featuresArr.length === 0) return true;
73
+ const pageValues = featuresArr.map(feature => (0, _pageValue.parseFeaturePageValue)(feature)).filter(value => Number.isFinite(value));
74
+ if (pageValues.length === 0) return true;
75
+ return !pageValues.some(value => Math.abs(value - currentPageValue) < 1e-5);
76
+ };
77
+ exports.isLcmsMsPageLoading = isLcmsMsPageLoading;
78
+ const styles = () => Object.assign({}, {
79
+ lcMsStackRoot: {
80
+ margin: '0 0 5px 52px'
81
+ },
82
+ lcMsToolbarRow: {
83
+ display: 'flex',
84
+ flexWrap: 'wrap',
85
+ alignItems: 'center',
86
+ justifyContent: 'space-between',
87
+ columnGap: 8,
88
+ rowGap: 4
89
+ },
90
+ lcMsToolbarLeft: {
91
+ display: 'flex',
92
+ flexWrap: 'wrap',
93
+ alignItems: 'center',
94
+ columnGap: 4,
95
+ rowGap: 4,
96
+ flex: '1 1 auto',
97
+ minWidth: 0
98
+ },
99
+ lcMsToolbarRight: {
100
+ display: 'flex',
101
+ flexWrap: 'wrap',
102
+ alignItems: 'center',
103
+ justifyContent: 'flex-end',
104
+ columnGap: 8,
105
+ rowGap: 4,
106
+ flex: '0 1 auto'
107
+ },
108
+ lcMsGraphPanel: {
109
+ position: 'relative'
110
+ },
111
+ lcMsLoadingOverlay: {
112
+ position: 'absolute',
113
+ inset: 0,
114
+ display: 'flex',
115
+ alignItems: 'center',
116
+ justifyContent: 'center',
117
+ backgroundColor: 'rgba(255, 255, 255, 0.72)',
118
+ pointerEvents: 'none',
119
+ zIndex: 2
120
+ },
121
+ lcMsLoadingIndicator: {
122
+ display: 'inline-flex',
123
+ alignItems: 'center',
124
+ justifyContent: 'center',
125
+ padding: 10,
126
+ borderRadius: '50%',
127
+ backgroundColor: 'rgba(255, 255, 255, 0.92)',
128
+ boxShadow: '0 1px 4px rgba(0, 0, 0, 0.18)'
129
+ }
130
+ }, _common.commonStyle);
131
+ const zoomView = (classes, graphIndex, uiSt, zoomInAct) => {
132
+ const onSweepZoomIn = () => {
133
+ const payload = {
134
+ graphIndex,
135
+ sweepType: _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN
136
+ };
137
+ zoomInAct(payload);
138
+ };
139
+ const onSweepZoomReset = () => {
140
+ const resetPayload = {
141
+ graphIndex,
142
+ sweepType: _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET
143
+ };
144
+ zoomInAct(resetPayload);
145
+ // Re-enable zoom brush immediately after reset for LC/MS flow.
146
+ zoomInAct({
147
+ graphIndex,
148
+ sweepType: _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN
149
+ });
150
+ };
151
+ const {
152
+ zoom
153
+ } = uiSt;
154
+ const {
155
+ sweepTypes
156
+ } = zoom;
157
+ const isZoomFocus = sweepTypes[graphIndex] === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN;
158
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
159
+ className: classes.group,
160
+ "data-testid": "Zoom",
161
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
162
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
163
+ className: "txt-sv-tp",
164
+ children: "Zoom In"
165
+ }),
166
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
167
+ className: (0, _classnames.default)((0, _common.focusStyle)(isZoomFocus, classes), 'btn-sv-bar-zoomin'),
168
+ onClick: onSweepZoomIn,
169
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZoomInOutlined.default, {
170
+ className: (0, _classnames.default)(classes.icon, classes.iconWp)
171
+ })
172
+ })
173
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
174
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
175
+ className: "txt-sv-tp",
176
+ children: "Reset Zoom"
177
+ }),
178
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
179
+ className: (0, _classnames.default)('btn-sv-bar-zoomreset'),
180
+ onClick: onSweepZoomReset,
181
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_FindReplaceOutlined.default, {
182
+ className: classes.icon
183
+ })
184
+ })
185
+ })]
186
+ });
187
+ };
188
+ const wavelengthSelect = (classes, hplcMsSt, updateWavelengthAct) => (0, _wavelengthSelect.default)(classes, hplcMsSt, updateWavelengthAct);
189
+ const countAvailableTicPolarities = hplcMsSt => {
190
+ const a = hplcMsSt?.tic?.available;
191
+ if (!a || typeof a !== 'object') return 0;
192
+ return ['positive', 'negative', 'neutral'].filter(k => a[k]).length;
193
+ };
194
+ const ticSelect = (classes, hplcMsSt, handleTicChanged) => {
195
+ const {
196
+ tic = {}
197
+ } = hplcMsSt || {};
198
+ const {
199
+ polarity,
200
+ available
201
+ } = tic;
202
+ const listTIC = [{
203
+ name: 'PLUS',
204
+ value: 'positive',
205
+ enabled: available?.positive
206
+ }, {
207
+ name: 'MINUS',
208
+ value: 'negative',
209
+ enabled: available?.negative
210
+ }, {
211
+ name: 'NEUTRAL',
212
+ value: 'neutral',
213
+ enabled: available?.neutral
214
+ }];
215
+ const filtered = listTIC.filter(d => d.enabled);
216
+ if (filtered.length <= 1) {
217
+ return null;
218
+ }
219
+ const listOptions = filtered;
220
+ const options = listOptions.map(d => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
221
+ value: d.value,
222
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
223
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-decimal'),
224
+ children: d.name
225
+ })
226
+ }, d.value));
227
+ const onTicChange = event => {
228
+ handleTicChanged(event);
229
+ };
230
+ const optionValues = listOptions.map(d => d.value);
231
+ const resolvedPolarity = optionValues.includes(polarity) ? polarity : optionValues[0];
232
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
233
+ className: (0, _classnames.default)(classes.fieldDecimal),
234
+ variant: "outlined",
235
+ style: {
236
+ width: '110px'
237
+ },
238
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
239
+ id: "select-decimal-label",
240
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
241
+ children: "TIC"
242
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
243
+ labelId: "select-decimal-label",
244
+ label: "Decimal",
245
+ value: resolvedPolarity,
246
+ onChange: onTicChange,
247
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-decimal'),
248
+ children: options
249
+ })]
250
+ });
251
+ };
252
+ class ViewerLineRect extends _react.default.Component {
253
+ constructor(props) {
254
+ super(props);
255
+ const {
256
+ clickUiTargetAct,
257
+ selectUiSweepAct,
258
+ scrollUiWheelAct,
259
+ ticEntities,
260
+ uvvisEntities,
261
+ uiSt
262
+ } = props;
263
+ this.rootKlassLine = `.${_list_graph.LIST_ROOT_SVG_GRAPH.LINE}`;
264
+ this.lineFocus = new _line_focus.default({
265
+ W,
266
+ H,
267
+ uvvisEntities,
268
+ clickUiTargetAct,
269
+ selectUiSweepAct,
270
+ scrollUiWheelAct,
271
+ graphIndex: 0,
272
+ uiSt
273
+ });
274
+ this.rootKlassMulti = `.${_list_graph.LIST_ROOT_SVG_GRAPH.MULTI}`;
275
+ this.multiFocus = new _multi_focus.default({
276
+ W,
277
+ H,
278
+ ticEntities,
279
+ clickUiTargetAct,
280
+ selectUiSweepAct,
281
+ scrollUiWheelAct,
282
+ graphIndex: 1,
283
+ uiSt
284
+ });
285
+ this.rootKlassRect = `.${_list_graph.LIST_ROOT_SVG_GRAPH.RECT}`;
286
+ this.rectFocus = new _rect_focus.default({
287
+ W,
288
+ H,
289
+ clickUiTargetAct,
290
+ selectUiSweepAct,
291
+ scrollUiWheelAct,
292
+ graphIndex: 2,
293
+ uiSt
294
+ });
295
+ this.extractSubView = this.extractSubView.bind(this);
296
+ this.notifyHostOnSubViewerChange = this.notifyHostOnSubViewerChange.bind(this);
297
+ this.extractUvvisView = this.extractUvvisView.bind(this);
298
+ this.handleUvvisUndo = this.handleUvvisUndo.bind(this);
299
+ this.handleUvvisRedo = this.handleUvvisRedo.bind(this);
300
+ }
301
+ componentDidMount() {
302
+ const {
303
+ curveSt,
304
+ feature,
305
+ ticEntities,
306
+ hplcMsSt,
307
+ tTrEndPts,
308
+ layoutSt,
309
+ isUiAddIntgSt,
310
+ isUiNoBrushSt,
311
+ integrationSt,
312
+ isHidden,
313
+ resetAllAct,
314
+ uiSt,
315
+ editPeakSt
316
+ } = this.props;
317
+ (0, _draw.drawDestroy)(this.rootKlassMulti);
318
+ (0, _draw.drawDestroy)(this.rootKlassLine);
319
+ (0, _draw.drawDestroy)(this.rootKlassRect);
320
+ resetAllAct(feature);
321
+ const {
322
+ zoom
323
+ } = uiSt;
324
+ const {
325
+ sweepExtent
326
+ } = zoom;
327
+ const uvvisViewFeature = this.extractUvvisView();
328
+ let uvvisSeed = [];
329
+ if (uvvisViewFeature?.data?.[0]) {
330
+ const currentData = uvvisViewFeature.data[0];
331
+ const {
332
+ x,
333
+ y
334
+ } = currentData;
335
+ uvvisSeed = toSeed(x, y);
336
+ }
337
+ (0, _draw.drawMain)(this.rootKlassLine, W, H, _list_graph.LIST_BRUSH_SVG_GRAPH.LINE);
338
+ this.lineFocus.create({
339
+ filterSeed: uvvisSeed,
340
+ filterPeak: [],
341
+ tTrEndPts,
342
+ layoutSt,
343
+ isUiNoBrushSt: true,
344
+ sweepExtentSt: sweepExtent[0],
345
+ integrationSt,
346
+ isUiAddIntgSt,
347
+ editPeakSt,
348
+ hplcMsSt
349
+ });
350
+ (0, _draw.drawLabel)(this.rootKlassLine, null, 'Minutes', 'Intensity');
351
+ (0, _draw.drawDisplay)(this.rootKlassLine, false);
352
+ (0, _draw.drawMain)(this.rootKlassMulti, W, H, _list_graph.LIST_BRUSH_SVG_GRAPH.MULTI);
353
+ this.multiFocus.create({
354
+ ticEntities,
355
+ curveSt,
356
+ hplcMsSt,
357
+ tTrEndPts,
358
+ layoutSt,
359
+ sweepExtentSt: sweepExtent[1],
360
+ isUiAddIntgSt,
361
+ isUiNoBrushSt
362
+ });
363
+ (0, _draw.drawLabel)(this.rootKlassMulti, null, 'Minutes', 'Intensity');
364
+ (0, _draw.drawDisplay)(this.rootKlassMulti, isHidden);
365
+ (0, _draw.drawMain)(this.rootKlassRect, W, H, _list_graph.LIST_BRUSH_SVG_GRAPH.RECT);
366
+ this.rectFocus.create({
367
+ filterSeed: [],
368
+ filterPeak: [],
369
+ tTrEndPts,
370
+ layoutSt,
371
+ isUiNoBrushSt: true,
372
+ sweepExtentSt: sweepExtent[2]
373
+ });
374
+ (0, _draw.drawLabel)(this.rootKlassRect, null, 'm/z', 'Intensity');
375
+ (0, _draw.drawDisplay)(this.rootKlassRect, false);
376
+ }
377
+ componentDidUpdate(prevProps) {
378
+ const {
379
+ ticEntities,
380
+ curveSt,
381
+ tTrEndPts,
382
+ layoutSt,
383
+ isUiAddIntgSt,
384
+ isUiNoBrushSt,
385
+ isHidden,
386
+ uiSt,
387
+ hplcMsSt,
388
+ integrationSt,
389
+ editPeakSt
390
+ } = this.props;
391
+ const {
392
+ zoom
393
+ } = uiSt;
394
+ const {
395
+ sweepExtent
396
+ } = zoom || {};
397
+ if (!Array.isArray(sweepExtent)) return;
398
+ const uvvisViewFeature = this.extractUvvisView();
399
+ if (uvvisViewFeature?.data?.[0]) {
400
+ const hasLineSvg = !!document.querySelector(`${this.rootKlassLine} .${_list_graph.LIST_BRUSH_SVG_GRAPH.LINE}`);
401
+ if (!hasLineSvg) {
402
+ (0, _draw.drawMain)(this.rootKlassLine, W, H, _list_graph.LIST_BRUSH_SVG_GRAPH.LINE);
403
+ }
404
+ const currentData = uvvisViewFeature.data[0];
405
+ const {
406
+ x,
407
+ y
408
+ } = currentData;
409
+ const uvvisSeed = toSeed(x, y);
410
+ if (this.lineFocus) {
411
+ this.lineFocus.update({
412
+ filterSeed: uvvisSeed,
413
+ filterPeak: [],
414
+ tTrEndPts,
415
+ isUiNoBrushSt: true,
416
+ isUiAddIntgSt,
417
+ sweepExtentSt: sweepExtent[0],
418
+ uiSt,
419
+ layoutSt,
420
+ integrationSt,
421
+ hplcMsSt,
422
+ editPeakSt
423
+ });
424
+ }
425
+ (0, _draw.drawLabel)(this.rootKlassLine, null, 'Minutes', 'Intensity');
426
+ (0, _draw.drawDisplay)(this.rootKlassLine, false);
427
+ }
428
+ if (this.multiFocus) {
429
+ const hasMultiSvg = !!document.querySelector(`${this.rootKlassMulti} .${_list_graph.LIST_BRUSH_SVG_GRAPH.MULTI}`);
430
+ if (!hasMultiSvg) {
431
+ (0, _draw.drawMain)(this.rootKlassMulti, W, H, _list_graph.LIST_BRUSH_SVG_GRAPH.MULTI);
432
+ }
433
+ this.multiFocus.update({
434
+ curveSt,
435
+ ticEntities,
436
+ hplcMsSt,
437
+ tTrEndPts,
438
+ layoutSt,
439
+ sweepExtentSt: sweepExtent[1],
440
+ isUiAddIntgSt,
441
+ isUiNoBrushSt,
442
+ uiSt,
443
+ editPeakSt
444
+ });
445
+ }
446
+ const {
447
+ polarity
448
+ } = hplcMsSt.tic;
449
+ const ticPolarityCount = countAvailableTicPolarities(hplcMsSt);
450
+ let ticLabel = null;
451
+ if (ticPolarityCount > 1) {
452
+ ticLabel = 'NEUTRAL';
453
+ if (polarity === 'negative') {
454
+ ticLabel = 'MINUS';
455
+ } else if (polarity === 'positive') {
456
+ ticLabel = 'PLUS';
457
+ }
458
+ }
459
+ (0, _draw.drawLabel)(this.rootKlassMulti, ticLabel, 'Minutes', 'Intensity');
460
+ (0, _draw.drawDisplay)(this.rootKlassMulti, isHidden);
461
+ this.notifyHostOnSubViewerChange(prevProps);
462
+ const subViewFeature = this.extractSubView();
463
+ if (subViewFeature) {
464
+ const hasRectSvg = !!document.querySelector(`${this.rootKlassRect} .${_list_graph.LIST_BRUSH_SVG_GRAPH.RECT}`);
465
+ if (!hasRectSvg) {
466
+ (0, _draw.drawMain)(this.rootKlassRect, W, H, _list_graph.LIST_BRUSH_SVG_GRAPH.RECT);
467
+ }
468
+ const {
469
+ threshold
470
+ } = hplcMsSt;
471
+ const curTrEndPts = (0, _chem.convertThresEndPts)(subViewFeature, threshold.value);
472
+ const {
473
+ data
474
+ } = subViewFeature;
475
+ const pageValue = (0, _pageValue.parseFeaturePageValue)(subViewFeature);
476
+ const labelValue = Number.isFinite(pageValue) ? pageValue : subViewFeature?.pageValue ?? subViewFeature?.page ?? null;
477
+ const currentData = data[0];
478
+ const {
479
+ x,
480
+ y
481
+ } = currentData;
482
+ const subSeed = toSeed(x, y);
483
+ if (this.rectFocus) {
484
+ this.rectFocus.update({
485
+ filterSeed: subSeed,
486
+ filterPeak: [],
487
+ tTrEndPts: curTrEndPts,
488
+ layoutSt,
489
+ isUiNoBrushSt: true,
490
+ sweepExtentSt: sweepExtent[2],
491
+ uiSt
492
+ });
493
+ }
494
+ (0, _draw.drawLabel)(this.rootKlassRect, labelValue != null ? `${labelValue} min` : null, 'm/z', 'Intensity');
495
+ (0, _draw.drawDisplay)(this.rootKlassRect, false);
496
+ }
497
+ }
498
+ componentWillUnmount() {
499
+ (0, _draw.drawDestroy)(this.rootKlassLine);
500
+ (0, _draw.drawDestroy)(this.rootKlassMulti);
501
+ (0, _draw.drawDestroy)(this.rootKlassRect);
502
+ }
503
+ handleUvvisUndo() {
504
+ const {
505
+ uvvisUndoAct
506
+ } = this.props;
507
+ uvvisUndoAct();
508
+ }
509
+ handleUvvisRedo() {
510
+ const {
511
+ uvvisRedoAct
512
+ } = this.props;
513
+ uvvisRedoAct();
514
+ }
515
+ extractUvvisView() {
516
+ const {
517
+ uvvisEntities,
518
+ hplcMsSt
519
+ } = this.props;
520
+ if (!uvvisEntities || !uvvisEntities[0]) {
521
+ return null;
522
+ }
523
+ const {
524
+ features
525
+ } = (0, _extractParams.extractParams)(uvvisEntities[0], null, null);
526
+ let featuresArr = [];
527
+ if (Array.isArray(features)) {
528
+ featuresArr = features;
529
+ } else if (features && typeof features === 'object') {
530
+ featuresArr = Object.values(features);
531
+ }
532
+ if (featuresArr.length === 0) {
533
+ return null;
534
+ }
535
+ const {
536
+ uvvis
537
+ } = hplcMsSt;
538
+ const {
539
+ wavelengthIdx
540
+ } = uvvis;
541
+ if (wavelengthIdx < 0 || wavelengthIdx >= featuresArr.length) {
542
+ return null;
543
+ }
544
+ return featuresArr[wavelengthIdx];
545
+ }
546
+ extractSubView() {
547
+ const {
548
+ uiSt,
549
+ mzEntities,
550
+ hplcMsSt
551
+ } = this.props;
552
+ const {
553
+ polarity
554
+ } = hplcMsSt.tic;
555
+ const pickEntity = mzEntities?.find(ent => (0, _extractEntityLCMS.getLcMsInfo)(ent).polarity === polarity) || mzEntities?.[0];
556
+ if (!pickEntity || !pickEntity.layout) return null;
557
+ const {
558
+ features
559
+ } = (0, _extractParams.extractParams)(pickEntity, null, null);
560
+ let featuresArr = [];
561
+ if (Array.isArray(features)) featuresArr = features;else if (features && typeof features === 'object') featuresArr = Object.values(features);
562
+ if (featuresArr.length === 0) return null;
563
+ const {
564
+ subViewerAt
565
+ } = uiSt;
566
+ const pageValues = featuresArr.map(fe => (0, _pageValue.parseFeaturePageValue)(fe)).filter(val => Number.isFinite(val));
567
+ if (pageValues.length === 0) return featuresArr[0];
568
+ let requestedPageValue;
569
+ if (subViewerAt != null && Number.isFinite(subViewerAt.x)) {
570
+ requestedPageValue = subViewerAt.x;
571
+ } else if (Number.isFinite(hplcMsSt.tic.currentPageValue)) {
572
+ requestedPageValue = hplcMsSt.tic.currentPageValue;
573
+ } else {
574
+ requestedPageValue = pageValues[Math.floor(pageValues.length / 2)];
575
+ }
576
+ const closestPage = (0, _calc.findClosest)(pageValues, requestedPageValue);
577
+ const selectFeature = featuresArr.find(fe => {
578
+ const value = (0, _pageValue.parseFeaturePageValue)(fe);
579
+ return Number.isFinite(value) && Math.abs(value - closestPage) < 1e-9;
580
+ });
581
+ return selectFeature || featuresArr[0];
582
+ }
583
+ notifyHostOnSubViewerChange(prevProps) {
584
+ const {
585
+ uiSt,
586
+ hplcMsSt,
587
+ mzEntities,
588
+ onLcmsPageRequest,
589
+ updateCurrentPageValueAct
590
+ } = this.props;
591
+ const subViewerAt = uiSt?.subViewerAt;
592
+ if (!subViewerAt || !Number.isFinite(subViewerAt.x)) return;
593
+ const prevSubViewerAt = prevProps?.uiSt?.subViewerAt;
594
+ const sameClickAsBefore = prevSubViewerAt && Number.isFinite(prevSubViewerAt.x) && Math.abs(subViewerAt.x - prevSubViewerAt.x) < 1e-9 && Math.abs((subViewerAt.y ?? 0) - (prevSubViewerAt.y ?? 0)) < 1e-9;
595
+ if (sameClickAsBefore) return;
596
+ const {
597
+ polarity
598
+ } = hplcMsSt.tic;
599
+ const pickEntity = mzEntities?.find(ent => (0, _extractEntityLCMS.getLcMsInfo)(ent).polarity === polarity) || mzEntities?.[0];
600
+ if (!pickEntity || !pickEntity.layout) return;
601
+ const {
602
+ features
603
+ } = (0, _extractParams.extractParams)(pickEntity, null, null);
604
+ let featuresArr = [];
605
+ if (Array.isArray(features)) featuresArr = features;else if (features && typeof features === 'object') featuresArr = Object.values(features);
606
+ const pageValues = featuresArr.map(fe => (0, _pageValue.parseFeaturePageValue)(fe)).filter(val => Number.isFinite(val));
607
+ const requestedRt = subViewerAt.x;
608
+ const matchesLoadedScan = pageValues.some(pv => Math.abs(pv - requestedRt) < 1e-5);
609
+ const needsRemoteFetch = !matchesLoadedScan;
610
+ const exactFeature = featuresArr.find(fe => {
611
+ const value = (0, _pageValue.parseFeaturePageValue)(fe);
612
+ return Number.isFinite(value) && Math.abs(value - requestedRt) < 1e-9;
613
+ });
614
+ const requestRetentionTime = exactFeature?.pageSymbol ?? exactFeature?.page ?? exactFeature?.pageValue ?? requestedRt;
615
+ const persistedRt = needsRemoteFetch ? requestedRt : (0, _calc.findClosest)(pageValues, requestedRt);
616
+ const prevPersistedRt = hplcMsSt.tic.currentPageValue;
617
+ if (!Number.isFinite(prevPersistedRt) || Math.abs(persistedRt - prevPersistedRt) > 1e-5) {
618
+ updateCurrentPageValueAct(persistedRt);
619
+ }
620
+ if (needsRemoteFetch && typeof onLcmsPageRequest === 'function') {
621
+ onLcmsPageRequest({
622
+ retentionTime: requestRetentionTime,
623
+ polarity,
624
+ trigger: 'user_click'
625
+ });
626
+ }
627
+ }
628
+ render() {
629
+ const {
630
+ classes,
631
+ hplcMsSt,
632
+ selectWavelengthAct,
633
+ updateTicAct,
634
+ selectCurveAct,
635
+ feature,
636
+ zoomInAct,
637
+ uiSt,
638
+ ticEntities,
639
+ mzEntities,
640
+ omitUvvisToolbarRow,
641
+ onLcmsPageRequest
642
+ } = this.props;
643
+ const resolvedFeature = feature || {};
644
+ const hasEdit = !!resolvedFeature?.data?.[0]?.x?.length;
645
+ const isMsLoading = isLcmsMsPageLoading(mzEntities, hplcMsSt);
646
+ const handleTicChanged = event => {
647
+ const selectedPolarity = event.target.value;
648
+ updateTicAct({
649
+ polarity: selectedPolarity
650
+ });
651
+ const targetEntity = ticEntities?.find(ent => (0, _extractEntityLCMS.getLcMsInfo)(ent).polarity === selectedPolarity);
652
+ if (targetEntity?.curveIdx !== undefined) {
653
+ selectCurveAct(targetEntity.curveIdx);
654
+ }
655
+ const rt = hplcMsSt?.tic?.currentPageValue;
656
+ // Always notify the host on polarity change so it can fetch the mz page for the
657
+ // other trace. If RT is not set yet, pass undefined — ELN resolves initial RT.
658
+ if (typeof onLcmsPageRequest === 'function') {
659
+ onLcmsPageRequest({
660
+ retentionTime: Number.isFinite(rt) ? rt : undefined,
661
+ polarity: selectedPolarity,
662
+ trigger: 'tic_polarity'
663
+ });
664
+ }
665
+ };
666
+ const handleWavelengthChange = event => {
667
+ selectWavelengthAct(event);
668
+ };
669
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
670
+ className: classes.lcMsStackRoot,
671
+ children: [omitUvvisToolbarRow ? null : /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
672
+ className: classes.lcMsToolbarRow,
673
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
674
+ className: classes.lcMsToolbarLeft,
675
+ children: [zoomView(classes, 0, uiSt, zoomInAct), wavelengthSelect(classes, hplcMsSt, handleWavelengthChange), /*#__PURE__*/(0, _jsxRuntime.jsx)(_integration.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_peak.default, {
676
+ feature: resolvedFeature
677
+ }), (() => {
678
+ const hist = hplcMsSt?.uvvisEditHistory || {
679
+ past: [],
680
+ future: []
681
+ };
682
+ const canUndo = hist.past && hist.past.length > 0;
683
+ const canRedo = hist.future && hist.future.length > 0;
684
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
685
+ className: classes.group,
686
+ style: {
687
+ display: 'inline-flex',
688
+ alignItems: 'center'
689
+ },
690
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
691
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
692
+ className: "txt-sv-tp",
693
+ children: "Undo"
694
+ }),
695
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
696
+ className: "btn-sv-bar-uvvis-undo",
697
+ disabled: !canUndo,
698
+ onClick: this.handleUvvisUndo,
699
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Undo.default, {
700
+ className: classes.icon
701
+ })
702
+ })
703
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
704
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
705
+ className: "txt-sv-tp",
706
+ children: "Redo"
707
+ }),
708
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
709
+ className: "btn-sv-bar-uvvis-redo",
710
+ disabled: !canRedo,
711
+ onClick: this.handleUvvisRedo,
712
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Redo.default, {
713
+ className: classes.icon
714
+ })
715
+ })
716
+ })]
717
+ });
718
+ })()]
719
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
720
+ className: classes.lcMsToolbarRight
721
+ })]
722
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
723
+ className: _list_graph.LIST_ROOT_SVG_GRAPH.LINE
724
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
725
+ className: classes.lcMsToolbarRow,
726
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
727
+ className: classes.lcMsToolbarLeft,
728
+ children: [zoomView(classes, 1, uiSt, zoomInAct), ticSelect(classes, hplcMsSt, handleTicChanged), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
729
+ style: {
730
+ display: 'inline-flex'
731
+ },
732
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_peak_group.default, {
733
+ feature: resolvedFeature,
734
+ graphIndex: 1
735
+ })
736
+ })]
737
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
738
+ className: classes.lcMsToolbarRight
739
+ })]
740
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
741
+ className: _list_graph.LIST_ROOT_SVG_GRAPH.MULTI
742
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
743
+ className: classes.lcMsToolbarRow,
744
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
745
+ className: classes.lcMsToolbarLeft,
746
+ children: zoomView(classes, 2, uiSt, zoomInAct)
747
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
748
+ className: classes.lcMsToolbarRight,
749
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_r03_threshold.default, {
750
+ feature: resolvedFeature,
751
+ hasEdit: hasEdit
752
+ })
753
+ })]
754
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
755
+ className: classes.lcMsGraphPanel,
756
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
757
+ className: _list_graph.LIST_ROOT_SVG_GRAPH.RECT
758
+ }), isMsLoading ? /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
759
+ className: classes.lcMsLoadingOverlay,
760
+ "data-testid": "lcms-ms-loading",
761
+ "aria-label": "Loading MS spectrum",
762
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
763
+ className: classes.lcMsLoadingIndicator,
764
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.CircularProgress, {
765
+ size: 28
766
+ })
767
+ })
768
+ }) : null]
769
+ })]
770
+ });
771
+ }
772
+ }
773
+ const mapStateToProps = (state, props) => ({
774
+ curveSt: state.curve,
775
+ tTrEndPts: (0, _chem.ToThresEndPts)(state, props),
776
+ isUiAddIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
777
+ isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0,
778
+ uiSt: state.ui,
779
+ layoutSt: state.layout,
780
+ hplcMsSt: state.hplcMs,
781
+ editPeakSt: state.editPeak.present,
782
+ integrationSt: state.integration.present,
783
+ sweepExtentSt: state.ui.sweepExtent
784
+ });
785
+ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
786
+ resetAllAct: _manager.resetAll,
787
+ clickUiTargetAct: _ui.clickUiTarget,
788
+ selectUiSweepAct: _ui.selectUiSweep,
789
+ scrollUiWheelAct: _ui.scrollUiWheel,
790
+ selectWavelengthAct: _hplc_ms.selectWavelength,
791
+ updateTicAct: _hplc_ms.changeTic,
792
+ selectCurveAct: _curve.selectCurve,
793
+ zoomInAct: _ui.setUiSweepType,
794
+ updateCurrentPageValueAct: _hplc_ms.updateCurrentPageValue,
795
+ uvvisUndoAct: _hplc_ms.uvvisUndo,
796
+ uvvisRedoAct: _hplc_ms.uvvisRedo
797
+ }, dispatch);
798
+ ViewerLineRect.propTypes = {
799
+ classes: _propTypes.default.object.isRequired,
800
+ uiSt: _propTypes.default.object.isRequired,
801
+ curveSt: _propTypes.default.object.isRequired,
802
+ ticEntities: _propTypes.default.array.isRequired,
803
+ uvvisEntities: _propTypes.default.array.isRequired,
804
+ mzEntities: _propTypes.default.array.isRequired,
805
+ layoutSt: _propTypes.default.string.isRequired,
806
+ integrationSt: _propTypes.default.object.isRequired,
807
+ feature: _propTypes.default.object,
808
+ tTrEndPts: _propTypes.default.array.isRequired,
809
+ isUiAddIntgSt: _propTypes.default.bool.isRequired,
810
+ isUiNoBrushSt: _propTypes.default.bool.isRequired,
811
+ resetAllAct: _propTypes.default.func.isRequired,
812
+ clickUiTargetAct: _propTypes.default.func.isRequired,
813
+ selectUiSweepAct: _propTypes.default.func.isRequired,
814
+ scrollUiWheelAct: _propTypes.default.func.isRequired,
815
+ isHidden: _propTypes.default.bool,
816
+ hplcMsSt: _propTypes.default.object.isRequired,
817
+ selectWavelengthAct: _propTypes.default.func.isRequired,
818
+ updateTicAct: _propTypes.default.func.isRequired,
819
+ selectCurveAct: _propTypes.default.func.isRequired,
820
+ zoomInAct: _propTypes.default.func.isRequired,
821
+ editPeakSt: _propTypes.default.object.isRequired,
822
+ updateCurrentPageValueAct: _propTypes.default.func.isRequired,
823
+ uvvisUndoAct: _propTypes.default.func.isRequired,
824
+ uvvisRedoAct: _propTypes.default.func.isRequired,
825
+ omitUvvisToolbarRow: _propTypes.default.bool,
826
+ onLcmsPageRequest: _propTypes.default.func
827
+ };
828
+ ViewerLineRect.defaultProps = {
829
+ feature: {},
830
+ isHidden: false,
831
+ omitUvvisToolbarRow: false,
832
+ onLcmsPageRequest: null
833
+ };
834
+
835
+ // export default connect(mapStateToProps, mapDispatchToProps)(ViewerLineRect);
836
+ var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(ViewerLineRect);