@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
@@ -10,6 +10,8 @@ var _mount = require("../../helpers/mount");
10
10
  var _converter = require("../../helpers/converter");
11
11
  var _brush = _interopRequireDefault(require("../../helpers/brush"));
12
12
  var _compass = require("../../helpers/compass");
13
+ var _integration_focus = require("../../helpers/integration_focus");
14
+ var _integration_split = require("../../helpers/integration_split");
13
15
  var _list_layout = require("../../constants/list_layout");
14
16
  var _format = _interopRequireDefault(require("../../helpers/format"));
15
17
  var _chem = require("../../helpers/chem");
@@ -17,7 +19,6 @@ var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
17
19
  var _focus = require("../../helpers/focus");
18
20
  var _integration = require("../../helpers/integration");
19
21
  var _multiplicity_calc = require("../../helpers/multiplicity_calc");
20
- var _calc = require("../../helpers/calc");
21
22
  /* eslint-disable no-unused-vars, prefer-object-spread, no-mixed-operators,
22
23
  no-unneeded-ternary, arrow-body-style, max-len */
23
24
 
@@ -30,8 +31,14 @@ class MultiFocus {
30
31
  clickUiTargetAct,
31
32
  selectUiSweepAct,
32
33
  scrollUiWheelAct,
33
- entities
34
+ entities,
35
+ uiSt,
36
+ splitIntegrationAct,
37
+ addVisualSplitLineAct,
38
+ removeVisualSplitLineAct
34
39
  } = props;
40
+ this.uiSt = uiSt;
41
+ this.graphIndex = uiSt?.zoom?.graphIndex;
35
42
  this.entities = entities;
36
43
  this.jcampIdx = 0;
37
44
  this.isShowAllCurves = false;
@@ -47,6 +54,9 @@ class MultiFocus {
47
54
  this.clickUiTargetAct = clickUiTargetAct;
48
55
  this.selectUiSweepAct = selectUiSweepAct;
49
56
  this.scrollUiWheelAct = scrollUiWheelAct;
57
+ this.splitIntegrationAct = splitIntegrationAct;
58
+ this.addVisualSplitLineAct = addVisualSplitLineAct;
59
+ this.removeVisualSplitLineAct = removeVisualSplitLineAct;
50
60
  this.brush = d3.brush();
51
61
  this.brushX = d3.brushX();
52
62
  this.axis = null;
@@ -73,6 +83,11 @@ class MultiFocus {
73
83
  this.shouldUpdate = {};
74
84
  // this.freq = false;
75
85
  this.layout = _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY;
86
+ this.isUiAddIntgSt = false;
87
+ this.isUiSplitIntgSt = false;
88
+ this.isUiVisualSplitIntgSt = false;
89
+ this.integrationSplitTargets = null;
90
+ this.firstIntegrationPoint = null;
76
91
  this.getShouldUpdate = this.getShouldUpdate.bind(this);
77
92
  this.resetShouldUpdate = this.resetShouldUpdate.bind(this);
78
93
  this.setTip = this.setTip.bind(this);
@@ -90,6 +105,10 @@ class MultiFocus {
90
105
  this.drawMtply = this.drawMtply.bind(this);
91
106
  this.drawAUC = this.drawAUC.bind(this);
92
107
  this.onClickTarget = this.onClickTarget.bind(this);
108
+ this.onClickIntegrationTarget = this.onClickIntegrationTarget.bind(this);
109
+ this.onIntegrationMouseMove = this.onIntegrationMouseMove.bind(this);
110
+ this.clearSplitPreview = this.clearSplitPreview.bind(this);
111
+ this.drawVisualSplitLines = this.drawVisualSplitLines.bind(this);
93
112
  this.mergedPeaks = this.mergedPeaks.bind(this);
94
113
  this.setDataPecker = this.setDataPecker.bind(this);
95
114
  this.drawPeckers = this.drawPeckers.bind(this);
@@ -119,7 +138,7 @@ class MultiFocus {
119
138
  const sameLySt = prevLySt === this.layout;
120
139
  const sameTePt = prevTePt === this.tTrEndPts.length;
121
140
  const sameDtPk = prevDtPk === this.dataPks.length;
122
- const sameSfPk = JSON.stringify(prevSfPk) === JSON.stringify(this.tSfPeaks);
141
+ const sameSfPk = prevSfPk === this.tSfPeaks || Array.isArray(prevSfPk) && Array.isArray(this.tSfPeaks) && prevSfPk.length === this.tSfPeaks.length && prevSfPk.every((peak, idx) => peak === this.tSfPeaks[idx]);
123
142
  const sameData = prevData === this.data.length;
124
143
  const sameYFactor = prevYFactor === this.yTransformFactor;
125
144
  this.shouldUpdate = Object.assign({}, this.shouldUpdate, {
@@ -170,15 +189,13 @@ class MultiFocus {
170
189
  const rawArea = (cyclicvoltaSt.areaValue === '' ? 1.0 : cyclicvoltaSt.areaValue) || 1.0;
171
190
  const areaUnit = cyclicvoltaSt.areaUnit || 'cm²';
172
191
  const safeArea = rawArea > 0 ? rawArea : 1.0;
192
+ // areaInCm2 already converts mm² → cm², so factor is A/cm². Do NOT divide by 100 again.
173
193
  const areaInCm2 = areaUnit === 'mm²' ? safeArea / 100.0 : safeArea;
174
194
  factor = 1.0 / areaInCm2;
175
195
  const baseY = feature && feature.yUnit ? String(feature.yUnit) : 'A';
176
196
  if (/mA/i.test(baseY)) {
177
197
  factor *= 1000.0;
178
198
  }
179
- if (areaUnit === 'mm²') {
180
- factor /= 100.0;
181
- }
182
199
  }
183
200
  return factor;
184
201
  }
@@ -298,6 +315,8 @@ class MultiFocus {
298
315
  this.path.style('stroke', this.pathColor);
299
316
  if (this.layout === _list_layout.LIST_LAYOUT.AIF) {
300
317
  this.path.attr('marker-mid', 'url(#arrow-left)');
318
+ } else {
319
+ this.path.attr('marker-mid', null);
301
320
  }
302
321
  }
303
322
  drawThres() {
@@ -330,6 +349,8 @@ class MultiFocus {
330
349
  path.attr('d', this.pathCall(data));
331
350
  if (this.layout === _list_layout.LIST_LAYOUT.AIF && this.isShowAllCurves === true) {
332
351
  path.attr('marker-mid', 'url(#arrow-left)');
352
+ } else {
353
+ path.attr('marker-mid', null);
333
354
  }
334
355
  });
335
356
  return null;
@@ -358,6 +379,23 @@ class MultiFocus {
358
379
  this.clickUiTargetAct(data, onPeak, false, this.jcampIdx);
359
380
  }
360
381
  }
382
+ clearSplitPreview() {
383
+ (0, _integration_split.clearIntegrationSplitPreview)(this);
384
+ }
385
+ onIntegrationMouseMove(event, data, shift, ignoreRef) {
386
+ (0, _integration_focus.handleIntegrationMouseMove)(this, event, data, shift, ignoreRef);
387
+ }
388
+ onClickIntegrationTarget(event, data) {
389
+ (0, _integration_focus.handleIntegrationClick)(this, event, data, (clickEvent, clickData) => {
390
+ this.onClickTarget(clickEvent, clickData);
391
+ });
392
+ }
393
+ drawVisualSplitLines(stack, shift, ignoreRef) {
394
+ (0, _integration_focus.drawVisualSplitLinesForFocus)(this, stack, shift, ignoreRef);
395
+ }
396
+ drawAUC(stack, shift = 0) {
397
+ (0, _integration_focus.drawIntegrationAUC)(this, stack, shift);
398
+ }
361
399
  onClickPecker(event, data) {
362
400
  event.stopPropagation();
363
401
  event.preventDefault();
@@ -396,44 +434,6 @@ class MultiFocus {
396
434
  }
397
435
  return this.dataPeckers;
398
436
  }
399
- drawAUC(stack) {
400
- const {
401
- xt,
402
- yt
403
- } = (0, _compass.TfRescale)(this);
404
- const auc = this.tags.aucPath.selectAll('path').data(stack);
405
- auc.exit().attr('class', 'exit').remove();
406
- const integCurve = border => {
407
- const {
408
- xL,
409
- xU
410
- } = border;
411
- const ps = this.data.filter(d => d.x > xL && d.x < xU);
412
- if (!ps[0]) return null;
413
- const point1 = ps[0];
414
- const point2 = ps[ps.length - 1];
415
- const slope = (0, _calc.calcSlope)(point1.x, point1.y, point2.x, point2.y);
416
- let lastDY = point1.y;
417
- return d3.area().x(d => xt(d.x)).y0((d, index) => {
418
- if (index > 0) {
419
- const lastD = ps[index - 1];
420
- const y = slope * (d.x - lastD.x) + lastDY;
421
- lastDY = y;
422
- return yt(y);
423
- }
424
- return yt(0);
425
- }).y1(d => yt(d.y))(ps);
426
- };
427
- auc.enter().append('path').attr('class', 'auc').attr('fill', 'red').attr('stroke', 'none').attr('fill-opacity', 0.2).attr('stroke-width', 2).merge(auc).attr('d', d => integCurve(d)).attr('id', d => `auc${(0, _focus.itgIdTag)(d)}`).on('mouseover', (event, d) => {
428
- d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
429
- d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
430
- d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
431
- }).on('mouseout', (event, d) => {
432
- d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'none');
433
- d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill', 'red');
434
- d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill-opacity', 0.2);
435
- }).on('click', (event, d) => this.onClickTarget(event, d));
436
- }
437
437
  drawPeaks(editPeakSt) {
438
438
  const {
439
439
  sameXY,
@@ -589,7 +589,7 @@ class MultiFocus {
589
589
  this.tip.hide(tipParams, event.target);
590
590
  }).on('click', (event, d) => this.onClickPecker(event, d));
591
591
  }
592
- drawInteg(integationSt) {
592
+ drawInteg(integrationState) {
593
593
  const {
594
594
  sameXY,
595
595
  sameLySt,
@@ -599,9 +599,16 @@ class MultiFocus {
599
599
  if (sameXY && sameLySt && sameItSt && sameData) return;
600
600
  const {
601
601
  integrations
602
- } = integationSt;
602
+ } = integrationState;
603
603
  const selectedIntegration = integrations[this.jcampIdx];
604
604
  if (selectedIntegration === false || selectedIntegration === undefined) {
605
+ Object.assign(this, {
606
+ integrationSplitTargets: {
607
+ stack: [],
608
+ shift: 0,
609
+ ignoreRef: false
610
+ }
611
+ });
605
612
  const itgs = [];
606
613
  const igbp = this.tags.igbPath.selectAll('path').data(itgs);
607
614
  igbp.exit().attr('class', 'exit').remove();
@@ -609,6 +616,7 @@ class MultiFocus {
609
616
  igcp.exit().attr('class', 'exit').remove();
610
617
  const igtp = this.tags.igtPath.selectAll('text').data(itgs);
611
618
  igtp.exit().attr('class', 'exit').remove();
619
+ this.drawVisualSplitLines([], 0, false);
612
620
  return;
613
621
  }
614
622
  const {
@@ -620,9 +628,20 @@ class MultiFocus {
620
628
  const isDisable = _cfg.default.btnCmdIntg(this.layout);
621
629
  const ignoreRef = _format.default.isHplcUvVisLayout(this.layout);
622
630
  const itgs = isDisable ? [] : stack;
623
- const igbp = this.tags.igbPath.selectAll('path').data(itgs);
631
+ const {
632
+ showIntegSplit,
633
+ igBarData
634
+ } = (0, _integration_focus.buildIntegrationBarData)(this.layout, itgs);
635
+ Object.assign(this, {
636
+ integrationSplitTargets: {
637
+ stack: itgs,
638
+ shift,
639
+ ignoreRef
640
+ }
641
+ });
642
+ const igbp = this.tags.igbPath.selectAll('path').data(igBarData);
624
643
  igbp.exit().attr('class', 'exit').remove();
625
- const igcp = this.tags.igcPath.selectAll('path').data(itgs);
644
+ const igcp = this.tags.igcPath.selectAll('path').data(igBarData);
626
645
  igcp.exit().attr('class', 'exit').remove();
627
646
  const igtp = this.tags.igtPath.selectAll('text').data(itgs);
628
647
  igtp.exit().attr('class', 'exit').remove();
@@ -631,10 +650,11 @@ class MultiFocus {
631
650
  const auc = this.tags.aucPath.selectAll('path').data(stack);
632
651
  auc.exit().attr('class', 'exit').remove();
633
652
  auc.merge(auc);
653
+ this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef);
634
654
  return;
635
655
  }
636
656
  if (ignoreRef) {
637
- this.drawAUC(stack);
657
+ this.drawAUC(stack, shift);
638
658
  } else {
639
659
  // rescale for zoom
640
660
  const {
@@ -650,7 +670,8 @@ class MultiFocus {
650
670
  d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
651
671
  d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
652
672
  d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
653
- }).on('click', (event, d) => this.onClickTarget(event, d));
673
+ if (showIntegSplit) this.clearSplitPreview();
674
+ }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
654
675
  const integCurve = border => {
655
676
  const {
656
677
  xL,
@@ -674,7 +695,8 @@ class MultiFocus {
674
695
  d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
675
696
  d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
676
697
  d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
677
- }).on('click', (event, d) => this.onClickTarget(event, d));
698
+ if (showIntegSplit) this.clearSplitPreview();
699
+ }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
678
700
  igtp.enter().append('text').attr('class', 'igtp').attr('font-family', 'Helvetica').style('font-size', '12px').attr('fill', '#228B22').style('text-anchor', 'middle').merge(igtp).attr('id', d => `igtp${(0, _focus.itgIdTag)(d)}`).text(d => (0, _integration.calcArea)(d, refArea, refFactor, ignoreRef)).attr('transform', d => `translate(${xt((d.xL + d.xU) / 2 - shift)}, ${dh - 12})`).on('mouseover', (event, d) => {
679
701
  d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
680
702
  d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
@@ -683,8 +705,10 @@ class MultiFocus {
683
705
  d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
684
706
  d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
685
707
  d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
686
- }).on('click', (event, d) => this.onClickTarget(event, d));
708
+ if (showIntegSplit) this.clearSplitPreview();
709
+ }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
687
710
  }
711
+ this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef);
688
712
  }
689
713
  drawMtply(mtplySt) {
690
714
  const {
@@ -720,13 +744,15 @@ class MultiFocus {
720
744
  return;
721
745
  }
722
746
  const {
723
- stack,
724
- smExtext,
725
- shift
726
- } = selectedMulti;
727
- const mpys = stack;
747
+ stack = [],
748
+ smExtext = false,
749
+ shift = 0
750
+ } = selectedMulti || {};
751
+ const hasValidExtent = extent => extent && Number.isFinite(extent.xL) && Number.isFinite(extent.xU);
752
+ const mpys = stack.filter(m => hasValidExtent(m?.xExtent));
728
753
  const isDisable = _cfg.default.btnCmdMpy(this.layout);
729
- if (mpys === 0 || isDisable) return;
754
+ if (mpys.length === 0 || isDisable) return;
755
+ const activeExtent = hasValidExtent(smExtext) ? smExtext : mpys[0].xExtent;
730
756
  // rescale for zoom
731
757
  const {
732
758
  xt
@@ -742,7 +768,8 @@ class MultiFocus {
742
768
  peaks,
743
769
  xExtent
744
770
  } = m;
745
- return peaks.map(p => Object.assign({}, p, {
771
+ const safePeaks = Array.isArray(peaks) ? peaks : [];
772
+ return safePeaks.filter(p => Number.isFinite(p?.x) && Number.isFinite(p?.y)).map(p => Object.assign({}, p, {
746
773
  xExtent
747
774
  }));
748
775
  });
@@ -757,7 +784,7 @@ class MultiFocus {
757
784
  xL,
758
785
  xU
759
786
  } = d.xExtent;
760
- return smExtext.xL === xL && smExtext.xU === xU ? 'purple' : '#DA70D6';
787
+ return activeExtent.xL === xL && activeExtent.xU === xU ? 'purple' : '#DA70D6';
761
788
  };
762
789
  mpyb.enter().append('path').attr('class', 'mpyb').attr('fill', 'none').attr('stroke-width', 2).merge(mpyb).attr('stroke', d => mpyColor(d)).attr('id', d => `mpyb${(0, _focus.mpyIdTag)(d)}`).attr('d', d => mpyBar(d)).on('mouseover', (event, d) => {
763
790
  d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
@@ -861,11 +888,17 @@ class MultiFocus {
861
888
  editPeakSt,
862
889
  layoutSt,
863
890
  sweepExtentSt,
891
+ isUiAddIntgSt,
892
+ isUiSplitIntgSt,
893
+ isUiVisualSplitIntgSt,
864
894
  isUiNoBrushSt,
865
895
  cyclicvoltaSt,
866
- integationSt,
867
- mtplySt
896
+ integrationSt,
897
+ mtplySt,
898
+ uiSt
868
899
  }) {
900
+ this.uiSt = uiSt;
901
+ this.graphIndex = uiSt?.zoom?.graphIndex;
869
902
  this.svg = d3.select(this.rootKlass).select('.d3Svg');
870
903
  (0, _mount.MountMainFrame)(this, 'focus');
871
904
  (0, _mount.MountClip)(this);
@@ -879,6 +912,11 @@ class MultiFocus {
879
912
  this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt));
880
913
  this.setTip();
881
914
  this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx);
915
+ Object.assign(this, {
916
+ isUiSplitIntgSt,
917
+ isUiVisualSplitIntgSt
918
+ });
919
+ if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview();
882
920
  (0, _compass.MountCompass)(this);
883
921
  this.axis = (0, _mount.MountAxis)(this);
884
922
  this.path = (0, _mount.MountPath)(this, this.pathColor);
@@ -897,10 +935,10 @@ class MultiFocus {
897
935
  this.drawPeaks(editPeakSt);
898
936
  this.drawRef();
899
937
  this.drawPeckers();
900
- this.drawInteg(integationSt);
938
+ this.drawInteg(integrationSt);
901
939
  this.drawMtply(mtplySt);
902
940
  }
903
- (0, _brush.default)(this, false, isUiNoBrushSt);
941
+ (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt);
904
942
  this.resetShouldUpdate(editPeakSt);
905
943
  }
906
944
  update({
@@ -913,13 +951,19 @@ class MultiFocus {
913
951
  editPeakSt,
914
952
  layoutSt,
915
953
  sweepExtentSt,
954
+ isUiAddIntgSt,
955
+ isUiSplitIntgSt,
956
+ isUiVisualSplitIntgSt,
916
957
  isUiNoBrushSt,
917
958
  cyclicvoltaSt,
918
- integationSt,
919
- mtplySt
959
+ integrationSt,
960
+ mtplySt,
961
+ uiSt
920
962
  }) {
963
+ this.uiSt = uiSt;
921
964
  this.root = d3.select(this.rootKlass).selectAll('.focus-main');
922
965
  this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt));
966
+ this.graphIndex = uiSt?.zoom?.graphIndex;
923
967
  const {
924
968
  curveIdx,
925
969
  isShowAllCurve
@@ -928,6 +972,11 @@ class MultiFocus {
928
972
  this.isShowAllCurves = isShowAllCurve;
929
973
  this.entities = entities;
930
974
  this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx);
975
+ Object.assign(this, {
976
+ isUiSplitIntgSt,
977
+ isUiVisualSplitIntgSt
978
+ });
979
+ if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview();
931
980
  if (this.data && this.data.length > 0) {
932
981
  this.setConfig(sweepExtentSt);
933
982
  this.getShouldUpdate(editPeakSt);
@@ -938,10 +987,10 @@ class MultiFocus {
938
987
  this.drawPeaks(editPeakSt);
939
988
  this.drawRef();
940
989
  this.drawPeckers();
941
- this.drawInteg(integationSt);
990
+ this.drawInteg(integrationSt);
942
991
  this.drawMtply(mtplySt);
943
992
  }
944
- (0, _brush.default)(this, false, isUiNoBrushSt);
993
+ (0, _brush.default)(this, false, isUiNoBrushSt, this.uiSt, this.graphIndex);
945
994
  this.resetShouldUpdate(editPeakSt);
946
995
  }
947
996
  }
@@ -50,6 +50,7 @@ class ViewerRect extends _react.default.Component {
50
50
  tTrEndPts,
51
51
  tSfPeaks,
52
52
  isHidden,
53
+ decimalSt,
53
54
  sweepExtentSt,
54
55
  isUiAddIntgSt,
55
56
  isUiNoBrushSt,
@@ -65,6 +66,7 @@ class ViewerRect extends _react.default.Component {
65
66
  filterPeak,
66
67
  tTrEndPts,
67
68
  tSfPeaks,
69
+ decimal: decimalSt,
68
70
  sweepExtentSt,
69
71
  isUiAddIntgSt,
70
72
  isUiNoBrushSt
@@ -79,6 +81,7 @@ class ViewerRect extends _react.default.Component {
79
81
  tTrEndPts,
80
82
  tSfPeaks,
81
83
  isHidden,
84
+ decimalSt,
82
85
  sweepExtentSt,
83
86
  isUiAddIntgSt,
84
87
  isUiNoBrushSt
@@ -91,6 +94,7 @@ class ViewerRect extends _react.default.Component {
91
94
  filterPeak,
92
95
  tTrEndPts,
93
96
  tSfPeaks,
97
+ decimal: decimalSt,
94
98
  sweepExtentSt,
95
99
  isUiAddIntgSt,
96
100
  isUiNoBrushSt
@@ -119,6 +123,7 @@ class ViewerRect extends _react.default.Component {
119
123
  const mapStateToProps = (state, props) => ({
120
124
  seed: (0, _chem.Topic2Seed)(state, props),
121
125
  peak: (0, _chem.Feature2Peak)(state, props),
126
+ decimalSt: state.submit.decimal,
122
127
  tTrEndPts: (0, _chem.ToThresEndPts)(state, props),
123
128
  tSfPeaks: (0, _chem.ToShiftPeaks)(state, props),
124
129
  sweepExtentSt: state.ui.sweepExtent,
@@ -134,6 +139,7 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
134
139
  ViewerRect.propTypes = {
135
140
  seed: _propTypes.default.array.isRequired,
136
141
  peak: _propTypes.default.array.isRequired,
142
+ decimalSt: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
137
143
  cLabel: _propTypes.default.string.isRequired,
138
144
  xLabel: _propTypes.default.string.isRequired,
139
145
  yLabel: _propTypes.default.string.isRequired,
@@ -11,6 +11,7 @@ var _mount = require("../../helpers/mount");
11
11
  var _compass = require("../../helpers/compass");
12
12
  var _converter = require("../../helpers/converter");
13
13
  var _list_layout = require("../../constants/list_layout");
14
+ var _format = _interopRequireDefault(require("../../helpers/format"));
14
15
  const d3 = require('d3');
15
16
  class RectFocus {
16
17
  constructor(props) {
@@ -53,6 +54,7 @@ class RectFocus {
53
54
  this.factor = 0.125;
54
55
  this.currentExtent = null;
55
56
  this.layout = _list_layout.LIST_LAYOUT.MS;
57
+ this.decimal = 3;
56
58
  this.setTip = this.setTip.bind(this);
57
59
  this.setDataParams = this.setDataParams.bind(this);
58
60
  this.create = this.create.bind(this);
@@ -68,11 +70,14 @@ class RectFocus {
68
70
  this.tip = (0, _init.InitTip)();
69
71
  this.root.call(this.tip);
70
72
  }
71
- setDataParams(data, peaks, tTrEndPts, tSfPeaks) {
73
+ setDataParams(data, peaks, tTrEndPts, tSfPeaks, decimal) {
72
74
  this.data = [...data];
73
75
  this.dataPks = [...peaks];
74
76
  this.tTrEndPts = tTrEndPts;
75
77
  this.tSfPeaks = tSfPeaks;
78
+ if (decimal !== undefined) {
79
+ this.decimal = _format.default.clampDecimalPlaces(decimal);
80
+ }
76
81
  }
77
82
  updatePathCall(xt, yt) {
78
83
  this.pathCall = d3.line().x(d => xt(d.x)).y(d => yt(d.y));
@@ -131,6 +136,7 @@ class RectFocus {
131
136
  } = (0, _compass.TfRescale)(this);
132
137
  this.updatePathCall(xt, yt);
133
138
  const yRef = this.tTrEndPts[0].y;
139
+ const msMaxY = d3.max(this.data, row => row.y) || 0;
134
140
  const bars = this.bars.selectAll('rect').data(this.data);
135
141
  bars.exit().attr('class', 'exit').remove();
136
142
  const gnd = yt(0);
@@ -139,7 +145,9 @@ class RectFocus {
139
145
  d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'blue');
140
146
  const tipParams = {
141
147
  d,
142
- layout: this.layout
148
+ layout: this.layout,
149
+ msMaxY,
150
+ xDigits: this.decimal
143
151
  };
144
152
  this.tip.show(tipParams, event.target);
145
153
  }).on('mouseout', (event, d) => {
@@ -147,7 +155,9 @@ class RectFocus {
147
155
  d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'red');
148
156
  const tipParams = {
149
157
  d,
150
- layout: this.layout
158
+ layout: this.layout,
159
+ msMaxY,
160
+ xDigits: this.decimal
151
161
  };
152
162
  this.tip.hide(tipParams, event.target);
153
163
  });
@@ -174,6 +184,7 @@ class RectFocus {
174
184
  filterPeak,
175
185
  tTrEndPts,
176
186
  tSfPeaks,
187
+ decimal,
177
188
  sweepExtentSt,
178
189
  isUiAddIntgSt,
179
190
  isUiNoBrushSt
@@ -183,7 +194,7 @@ class RectFocus {
183
194
  (0, _mount.MountClip)(this);
184
195
  this.root = d3.select(this.rootKlass).selectAll('.focus-main');
185
196
  this.setTip();
186
- this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks);
197
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, decimal);
187
198
  (0, _compass.MountCompass)(this);
188
199
  this.axis = (0, _mount.MountAxis)(this);
189
200
  [this.thresLine] = (0, _mount.MountThresLine)(this, 'green');
@@ -205,12 +216,13 @@ class RectFocus {
205
216
  filterPeak,
206
217
  tTrEndPts,
207
218
  tSfPeaks,
219
+ decimal,
208
220
  sweepExtentSt,
209
221
  isUiAddIntgSt,
210
222
  isUiNoBrushSt
211
223
  }) {
212
224
  this.root = d3.select(this.rootKlass).selectAll('.focus-main');
213
- this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks);
225
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, decimal);
214
226
  if (this.data && this.data.length > 0) {
215
227
  this.setConfig(sweepExtentSt);
216
228
  this.drawBar();