diff --git a/dist/actions/axes.js b/dist/actions/axes.js
new file mode 100644
index 00000000..3cde6370
--- /dev/null
+++ b/dist/actions/axes.js
@@ -0,0 +1,19 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateYAxis = exports.updateXAxis = void 0;
+var _action_type = require("../constants/action_type");
+const updateXAxis = payload => ({
+ type: _action_type.AXES.UPDATE_X_AXIS,
+ payload
+});
+exports.updateXAxis = updateXAxis;
+const updateYAxis = payload => ({
+ type: _action_type.AXES.UPDATE_Y_AXIS,
+ payload
+});
+
+// eslint-disable-line
+exports.updateYAxis = updateYAxis;
\ No newline at end of file
diff --git a/dist/actions/curve.js b/dist/actions/curve.js
new file mode 100644
index 00000000..85bd0062
--- /dev/null
+++ b/dist/actions/curve.js
@@ -0,0 +1,22 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.toggleShowAllCurves = exports.setAllCurves = exports.selectCurve = void 0;
+var _action_type = require("../constants/action_type");
+const selectCurve = payload => ({
+ type: _action_type.CURVE.SELECT_WORKING_CURVE,
+ payload
+});
+exports.selectCurve = selectCurve;
+const setAllCurves = payload => ({
+ type: _action_type.CURVE.SET_ALL_CURVES,
+ payload
+});
+exports.setAllCurves = setAllCurves;
+const toggleShowAllCurves = payload => ({
+ type: _action_type.CURVE.SET_SHOULD_SHOW_ALL_CURVES,
+ payload
+});
+exports.toggleShowAllCurves = toggleShowAllCurves;
\ No newline at end of file
diff --git a/dist/actions/cyclic_voltammetry.js b/dist/actions/cyclic_voltammetry.js
new file mode 100644
index 00000000..a6e14b76
--- /dev/null
+++ b/dist/actions/cyclic_voltammetry.js
@@ -0,0 +1,91 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.toggleCyclicVoltaDensity = exports.setWorkWithMaxPeak = exports.setCylicVoltaRefFactor = exports.setCylicVoltaRef = exports.setCyclicVoltaAreaValue = exports.setCyclicVoltaAreaUnit = exports.selectRefPeaks = exports.selectPairPeak = exports.removeCylicVoltaPecker = exports.removeCylicVoltaPairPeak = exports.removeCylicVoltaMinPeak = exports.removeCylicVoltaMaxPeak = exports.addNewCylicVoltaPairPeak = exports.addCylicVoltaPecker = exports.addCylicVoltaMinPeak = exports.addCylicVoltaMaxPeak = void 0;
+var _action_type = require("../constants/action_type");
+const addNewCylicVoltaPairPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_PAIR_PEAKS,
+ payload
+});
+exports.addNewCylicVoltaPairPeak = addNewCylicVoltaPairPeak;
+const removeCylicVoltaPairPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_PAIR_PEAKS,
+ payload
+});
+exports.removeCylicVoltaPairPeak = removeCylicVoltaPairPeak;
+const addCylicVoltaMaxPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_MAX_PEAK,
+ payload
+});
+exports.addCylicVoltaMaxPeak = addCylicVoltaMaxPeak;
+const removeCylicVoltaMaxPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_MAX_PEAK,
+ payload
+});
+exports.removeCylicVoltaMaxPeak = removeCylicVoltaMaxPeak;
+const addCylicVoltaMinPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_MIN_PEAK,
+ payload
+});
+exports.addCylicVoltaMinPeak = addCylicVoltaMinPeak;
+const removeCylicVoltaMinPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_MIN_PEAK,
+ payload
+});
+exports.removeCylicVoltaMinPeak = removeCylicVoltaMinPeak;
+const setWorkWithMaxPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.WORK_WITH_MAX_PEAK,
+ payload
+});
+exports.setWorkWithMaxPeak = setWorkWithMaxPeak;
+const selectPairPeak = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.SELECT_PAIR_PEAK,
+ payload
+});
+exports.selectPairPeak = selectPairPeak;
+const addCylicVoltaPecker = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_PECKER,
+ payload
+});
+exports.addCylicVoltaPecker = addCylicVoltaPecker;
+const removeCylicVoltaPecker = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_PECKER,
+ payload
+});
+exports.removeCylicVoltaPecker = removeCylicVoltaPecker;
+const selectRefPeaks = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.SELECT_REF_PEAK,
+ payload
+});
+exports.selectRefPeaks = selectRefPeaks;
+const setCylicVoltaRefFactor = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_FACTOR,
+ payload
+});
+exports.setCylicVoltaRefFactor = setCylicVoltaRefFactor;
+const setCylicVoltaRef = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_REF,
+ payload
+});
+exports.setCylicVoltaRef = setCylicVoltaRef;
+const setCyclicVoltaAreaValue = value => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_AREA_VALUE,
+ payload: {
+ value
+ }
+});
+exports.setCyclicVoltaAreaValue = setCyclicVoltaAreaValue;
+const setCyclicVoltaAreaUnit = unit => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_AREA_UNIT,
+ payload: {
+ unit
+ }
+});
+exports.setCyclicVoltaAreaUnit = setCyclicVoltaAreaUnit;
+const toggleCyclicVoltaDensity = payload => ({
+ type: _action_type.CYCLIC_VOLTA_METRY.TOGGLE_DENSITY,
+ payload
+});
+exports.toggleCyclicVoltaDensity = toggleCyclicVoltaDensity;
\ No newline at end of file
diff --git a/dist/actions/detector.js b/dist/actions/detector.js
new file mode 100644
index 00000000..4736ec21
--- /dev/null
+++ b/dist/actions/detector.js
@@ -0,0 +1,14 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateDetector = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable import/prefer-default-export */
+
+const updateDetector = payload => ({
+ type: _action_type.SEC.UPDATE_DETECTOR,
+ payload
+});
+exports.updateDetector = updateDetector;
\ No newline at end of file
diff --git a/dist/actions/edit_peak.js b/dist/actions/edit_peak.js
new file mode 100644
index 00000000..cbb80814
--- /dev/null
+++ b/dist/actions/edit_peak.js
@@ -0,0 +1,22 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.rmFromPosList = exports.rmFromNegList = exports.clearAllPeaks = void 0;
+var _action_type = require("../constants/action_type");
+const rmFromPosList = payload => ({
+ type: _action_type.EDITPEAK.RM_POSITIVE,
+ payload
+});
+exports.rmFromPosList = rmFromPosList;
+const rmFromNegList = payload => ({
+ type: _action_type.EDITPEAK.RM_NEGATIVE,
+ payload
+});
+exports.rmFromNegList = rmFromNegList;
+const clearAllPeaks = payload => ({
+ type: _action_type.EDITPEAK.CLEAR_ALL,
+ payload
+});
+exports.clearAllPeaks = clearAllPeaks;
\ No newline at end of file
diff --git a/dist/actions/forecast.js b/dist/actions/forecast.js
new file mode 100644
index 00000000..6ef4cae6
--- /dev/null
+++ b/dist/actions/forecast.js
@@ -0,0 +1,27 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.setNmrStatus = exports.setIrStatus = exports.initForecastStatus = exports.clearForecastStatus = void 0;
+var _action_type = require("../constants/action_type");
+const initForecastStatus = payload => ({
+ type: _action_type.FORECAST.INIT_STATUS,
+ payload
+});
+exports.initForecastStatus = initForecastStatus;
+const setIrStatus = payload => ({
+ type: _action_type.FORECAST.SET_IR_STATUS,
+ payload
+});
+exports.setIrStatus = setIrStatus;
+const setNmrStatus = payload => ({
+ type: _action_type.FORECAST.SET_NMR_STATUS,
+ payload
+});
+exports.setNmrStatus = setNmrStatus;
+const clearForecastStatus = payload => ({
+ type: _action_type.FORECAST.CLEAR_STATUS,
+ payload
+});
+exports.clearForecastStatus = clearForecastStatus;
\ No newline at end of file
diff --git a/dist/actions/integration.js b/dist/actions/integration.js
new file mode 100644
index 00000000..1366a30e
--- /dev/null
+++ b/dist/actions/integration.js
@@ -0,0 +1,29 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.sweepIntegration = exports.splitIntegration = exports.setIntegrationFkr = exports.clearIntegrationAll = void 0;
+var _action_type = require("../constants/action_type");
+const sweepIntegration = payload => ({
+ type: _action_type.INTEGRATION.SWEEP,
+ payload
+});
+exports.sweepIntegration = sweepIntegration;
+const setIntegrationFkr = payload => ({
+ type: _action_type.INTEGRATION.SET_FKR,
+ payload
+});
+exports.setIntegrationFkr = setIntegrationFkr;
+const clearIntegrationAll = payload => ({
+ type: _action_type.INTEGRATION.CLEAR_ALL,
+ payload
+});
+exports.clearIntegrationAll = clearIntegrationAll;
+const splitIntegration = payload => ({
+ type: _action_type.INTEGRATION.SPLIT,
+ payload
+});
+
+// eslint-disable-line
+exports.splitIntegration = splitIntegration;
\ No newline at end of file
diff --git a/dist/actions/jcamp.js b/dist/actions/jcamp.js
new file mode 100644
index 00000000..302fb464
--- /dev/null
+++ b/dist/actions/jcamp.js
@@ -0,0 +1,27 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.toggleShow = exports.rmOthersOne = exports.clearAll = exports.addOthers = void 0;
+var _action_type = require("../constants/action_type");
+const addOthers = payload => ({
+ type: _action_type.JCAMP.ADD_OTHERS,
+ payload
+});
+exports.addOthers = addOthers;
+const rmOthersOne = payload => ({
+ type: _action_type.JCAMP.RM_OTHERS_ONE,
+ payload
+});
+exports.rmOthersOne = rmOthersOne;
+const toggleShow = payload => ({
+ type: _action_type.JCAMP.TOGGLE_SHOW,
+ payload
+});
+exports.toggleShow = toggleShow;
+const clearAll = payload => ({
+ type: _action_type.JCAMP.CLEAR_ALL,
+ payload
+});
+exports.clearAll = clearAll;
\ No newline at end of file
diff --git a/dist/actions/layout.js b/dist/actions/layout.js
new file mode 100644
index 00000000..7651a640
--- /dev/null
+++ b/dist/actions/layout.js
@@ -0,0 +1,14 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateLayout = void 0;
+var _action_type = require("../constants/action_type");
+const updateLayout = payload => ({
+ type: _action_type.LAYOUT.UPDATE,
+ payload
+});
+
+// eslint-disable-line
+exports.updateLayout = updateLayout;
\ No newline at end of file
diff --git a/dist/actions/manager.js b/dist/actions/manager.js
new file mode 100644
index 00000000..f2effe9c
--- /dev/null
+++ b/dist/actions/manager.js
@@ -0,0 +1,42 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.resetMultiplicity = exports.resetInitNmr = exports.resetInitMs = exports.resetInitCommonWithIntergation = exports.resetInitCommon = exports.resetDetector = exports.resetAll = void 0;
+var _action_type = require("../constants/action_type");
+const resetAll = payload => ({
+ type: _action_type.MANAGER.RESETALL,
+ payload
+});
+exports.resetAll = resetAll;
+const resetInitCommon = payload => ({
+ type: _action_type.MANAGER.RESET_INIT_COMMON,
+ payload
+});
+exports.resetInitCommon = resetInitCommon;
+const resetInitNmr = payload => ({
+ type: _action_type.MANAGER.RESET_INIT_NMR,
+ payload
+});
+exports.resetInitNmr = resetInitNmr;
+const resetInitMs = payload => ({
+ type: _action_type.MANAGER.RESET_INIT_MS,
+ payload
+});
+exports.resetInitMs = resetInitMs;
+const resetInitCommonWithIntergation = payload => ({
+ type: _action_type.MANAGER.RESET_INIT_COMMON_WITH_INTERGATION,
+ payload
+});
+exports.resetInitCommonWithIntergation = resetInitCommonWithIntergation;
+const resetDetector = () => ({
+ type: _action_type.MANAGER.RESET_DETECTOR
+});
+exports.resetDetector = resetDetector;
+const resetMultiplicity = () => ({
+ type: _action_type.MANAGER.RESET_MULTIPLICITY
+});
+
+// eslint-disable-line
+exports.resetMultiplicity = resetMultiplicity;
\ No newline at end of file
diff --git a/dist/actions/meta.js b/dist/actions/meta.js
new file mode 100644
index 00000000..dce5acf9
--- /dev/null
+++ b/dist/actions/meta.js
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateMetaPeaks = exports.updateDSCMetaData = void 0;
+var _action_type = require("../constants/action_type");
+const updateMetaPeaks = payload => ({
+ type: _action_type.META.UPDATE_PEAKS,
+ payload
+});
+exports.updateMetaPeaks = updateMetaPeaks;
+const updateDSCMetaData = payload => ({
+ type: _action_type.META.UPDATE_META_DATA,
+ payload
+});
+exports.updateDSCMetaData = updateDSCMetaData;
\ No newline at end of file
diff --git a/dist/actions/multiplicity.js b/dist/actions/multiplicity.js
new file mode 100644
index 00000000..d057f481
--- /dev/null
+++ b/dist/actions/multiplicity.js
@@ -0,0 +1,39 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateMpyJ = exports.selectMpyType = exports.rmMpyPeakByPanel = exports.resetMpyOne = exports.clickMpyOne = exports.clearMpyAll = void 0;
+var _action_type = require("../constants/action_type");
+const clickMpyOne = payload => ({
+ type: _action_type.MULTIPLICITY.ONE_CLICK,
+ payload
+});
+exports.clickMpyOne = clickMpyOne;
+const rmMpyPeakByPanel = payload => ({
+ type: _action_type.MULTIPLICITY.PEAK_RM_BY_PANEL,
+ payload
+});
+exports.rmMpyPeakByPanel = rmMpyPeakByPanel;
+const selectMpyType = payload => ({
+ type: _action_type.MULTIPLICITY.TYPE_SELECT,
+ payload
+});
+exports.selectMpyType = selectMpyType;
+const clearMpyAll = payload => ({
+ type: _action_type.MULTIPLICITY.CLEAR_ALL,
+ payload
+});
+exports.clearMpyAll = clearMpyAll;
+const resetMpyOne = payload => ({
+ type: _action_type.MULTIPLICITY.RESET_ONE,
+ payload
+});
+exports.resetMpyOne = resetMpyOne;
+const updateMpyJ = payload => ({
+ type: _action_type.MULTIPLICITY.UPDATE_J,
+ payload
+});
+
+// eslint-disable-line
+exports.updateMpyJ = updateMpyJ;
\ No newline at end of file
diff --git a/dist/actions/scan.js b/dist/actions/scan.js
new file mode 100644
index 00000000..c8069390
--- /dev/null
+++ b/dist/actions/scan.js
@@ -0,0 +1,22 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.toggleScanIsAuto = exports.setScanTarget = exports.resetScanTarget = void 0;
+var _action_type = require("../constants/action_type");
+const setScanTarget = payload => ({
+ type: _action_type.SCAN.SET_TARGET,
+ payload
+});
+exports.setScanTarget = setScanTarget;
+const resetScanTarget = () => ({
+ type: _action_type.SCAN.SET_TARGET,
+ payload: false
+});
+exports.resetScanTarget = resetScanTarget;
+const toggleScanIsAuto = payload => ({
+ type: _action_type.SCAN.TOGGLE_ISAUTO,
+ payload
+});
+exports.toggleScanIsAuto = toggleScanIsAuto;
\ No newline at end of file
diff --git a/dist/actions/shift.js b/dist/actions/shift.js
new file mode 100644
index 00000000..62adf12a
--- /dev/null
+++ b/dist/actions/shift.js
@@ -0,0 +1,19 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.setShiftRef = exports.rmShiftPeak = void 0;
+var _action_type = require("../constants/action_type");
+const setShiftRef = payload => ({
+ type: _action_type.SHIFT.SET_REF,
+ payload
+});
+exports.setShiftRef = setShiftRef;
+const rmShiftPeak = () => ({
+ type: _action_type.SHIFT.RM_PEAK,
+ payload: null
+});
+
+// eslint-disable-line
+exports.rmShiftPeak = rmShiftPeak;
\ No newline at end of file
diff --git a/dist/actions/status.js b/dist/actions/status.js
new file mode 100644
index 00000000..d7efff6f
--- /dev/null
+++ b/dist/actions/status.js
@@ -0,0 +1,22 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.toggleSubmitBtn = exports.toggleAllBtn = exports.enableAllBtn = void 0;
+var _action_type = require("../constants/action_type");
+const toggleSubmitBtn = () => ({
+ type: _action_type.STATUS.TOGGLEBTNSUBMIT,
+ payload: []
+});
+exports.toggleSubmitBtn = toggleSubmitBtn;
+const toggleAllBtn = () => ({
+ type: _action_type.STATUS.TOGGLEBTNALL,
+ payload: []
+});
+exports.toggleAllBtn = toggleAllBtn;
+const enableAllBtn = () => ({
+ type: _action_type.STATUS.ENABLEBTNALL,
+ payload: []
+});
+exports.enableAllBtn = enableAllBtn;
\ No newline at end of file
diff --git a/dist/actions/submit.js b/dist/actions/submit.js
new file mode 100644
index 00000000..66611588
--- /dev/null
+++ b/dist/actions/submit.js
@@ -0,0 +1,27 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateOperation = exports.updateDecimal = exports.toggleIsIntensity = exports.toggleIsAscend = void 0;
+var _action_type = require("../constants/action_type");
+const toggleIsAscend = () => ({
+ type: _action_type.SUBMIT.TOGGLE_IS_ASCEND,
+ payload: false
+});
+exports.toggleIsAscend = toggleIsAscend;
+const toggleIsIntensity = () => ({
+ type: _action_type.SUBMIT.TOGGLE_IS_INTENSITY,
+ payload: false
+});
+exports.toggleIsIntensity = toggleIsIntensity;
+const updateOperation = payload => ({
+ type: _action_type.SUBMIT.UPDATE_OPERATION,
+ payload
+});
+exports.updateOperation = updateOperation;
+const updateDecimal = payload => ({
+ type: _action_type.SUBMIT.UPDATE_DECIMAL,
+ payload
+});
+exports.updateDecimal = updateDecimal;
\ No newline at end of file
diff --git a/dist/actions/threshold.js b/dist/actions/threshold.js
new file mode 100644
index 00000000..3feeeee2
--- /dev/null
+++ b/dist/actions/threshold.js
@@ -0,0 +1,32 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateUpperThresholdValue = exports.updateThresholdValue = exports.updateLowerThresholdValue = exports.toggleThresholdIsEdit = exports.resetThresholdValue = void 0;
+var _action_type = require("../constants/action_type");
+const updateThresholdValue = payload => ({
+ type: _action_type.THRESHOLD.UPDATE_VALUE,
+ payload
+});
+exports.updateThresholdValue = updateThresholdValue;
+const resetThresholdValue = () => ({
+ type: _action_type.THRESHOLD.RESET_VALUE,
+ payload: false
+});
+exports.resetThresholdValue = resetThresholdValue;
+const toggleThresholdIsEdit = payload => ({
+ type: _action_type.THRESHOLD.TOGGLE_ISEDIT,
+ payload
+});
+exports.toggleThresholdIsEdit = toggleThresholdIsEdit;
+const updateUpperThresholdValue = payload => ({
+ type: _action_type.THRESHOLD.UPDATE_UPPER_VALUE,
+ payload
+});
+exports.updateUpperThresholdValue = updateUpperThresholdValue;
+const updateLowerThresholdValue = payload => ({
+ type: _action_type.THRESHOLD.UPDATE_LOWER_VALUE,
+ payload
+});
+exports.updateLowerThresholdValue = updateLowerThresholdValue;
\ No newline at end of file
diff --git a/dist/actions/ui.js b/dist/actions/ui.js
new file mode 100644
index 00000000..da219839
--- /dev/null
+++ b/dist/actions/ui.js
@@ -0,0 +1,56 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.setUiViewerType = exports.setUiSweepType = exports.selectUiSweep = exports.scrollUiWheel = exports.clickUiTarget = void 0;
+var _action_type = require("../constants/action_type");
+var _list_ui = require("../constants/list_ui");
+var _integration_draft = require("../helpers/integration_draft.js");
+// eslint-disable-line import/extensions
+
+const keepIntegrationMode = (jcampIdx = 0) => ({
+ type: _action_type.UI.SWEEP.SET_TYPE,
+ payload: _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ jcampIdx
+});
+const setUiViewerType = payload => {
+ if (!(0, _integration_draft.confirmCancelPendingIntegration)()) {
+ return keepIntegrationMode();
+ }
+ return {
+ type: _action_type.UI.VIEWER.SET_TYPE,
+ payload
+ };
+};
+exports.setUiViewerType = setUiViewerType;
+const setUiSweepType = (payload, jcampIdx = 0) => {
+ if (payload !== _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD && !(0, _integration_draft.confirmCancelPendingIntegration)()) {
+ return keepIntegrationMode(jcampIdx);
+ }
+ return {
+ type: _action_type.UI.SWEEP.SET_TYPE,
+ payload,
+ jcampIdx
+ };
+};
+exports.setUiSweepType = setUiSweepType;
+const selectUiSweep = payload => ({
+ type: _action_type.UI.SWEEP.SELECT,
+ payload
+});
+exports.selectUiSweep = selectUiSweep;
+const scrollUiWheel = payload => ({
+ type: _action_type.UI.WHEEL.SCROLL,
+ payload
+});
+exports.scrollUiWheel = scrollUiWheel;
+const clickUiTarget = (payload, onPeak, voltammetryPeakIdx = 0, jcampIdx = 0, onPecker = false) => ({
+ type: _action_type.UI.CLICK_TARGET,
+ payload,
+ onPeak,
+ voltammetryPeakIdx,
+ jcampIdx,
+ onPecker
+});
+exports.clickUiTarget = clickUiTarget;
\ No newline at end of file
diff --git a/dist/actions/wavelength.js b/dist/actions/wavelength.js
new file mode 100644
index 00000000..e8008550
--- /dev/null
+++ b/dist/actions/wavelength.js
@@ -0,0 +1,14 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.updateWaveLength = void 0;
+var _action_type = require("../constants/action_type");
+const updateWaveLength = payload => ({
+ type: _action_type.XRD.UPDATE_WAVE_LENGTH,
+ payload
+});
+
+// eslint-disable-line
+exports.updateWaveLength = updateWaveLength;
\ No newline at end of file
diff --git a/dist/app.js b/dist/app.js
new file mode 100644
index 00000000..a6bd495c
--- /dev/null
+++ b/dist/app.js
@@ -0,0 +1,130 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+Object.defineProperty(exports, "FN", {
+ enumerable: true,
+ get: function get() {
+ return _fn.default;
+ }
+});
+exports.SpectraEditor = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _material = require("@mui/material");
+require("regenerator-runtime/runtime");
+var _reduxSaga = _interopRequireDefault(require("redux-saga"));
+var _index = _interopRequireDefault(require("./reducers/index"));
+var _index2 = _interopRequireDefault(require("./sagas/index"));
+var _layer_init = _interopRequireDefault(require("./layer_init"));
+var _fn = _interopRequireDefault(require("./fn"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/function-component-definition, react/require-default-props */
+
+// eslint-disable-line
+
+// import { logger } from 'redux-logger';
+
+// - - - store & middleware - - -
+const sagaMiddleware = (0, _reduxSaga.default)();
+const middlewares = [sagaMiddleware]; // logger
+
+const store = (0, _redux.compose)((0, _redux.applyMiddleware)(...middlewares))(_redux.createStore)(_index.default);
+sagaMiddleware.run(_index2.default);
+
+// - - - helper - - -
+const ensureQuillDelta = descs => {
+ const isArr = Array.isArray(descs);
+ return isArr ? descs : [{
+ insert: descs
+ }];
+};
+
+// - - - React - - -
+const SpectraEditor = ({
+ entity,
+ others,
+ cLabel,
+ xLabel,
+ yLabel,
+ operations,
+ forecast,
+ molSvg,
+ editorOnly,
+ descriptions,
+ exactMass,
+ canChangeDescription,
+ onDescriptionChanged,
+ multiEntities,
+ multiMolSvgs,
+ entityFileNames,
+ userManualLink
+}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactRedux.Provider, {
+ store: store,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.StyledEngineProvider, {
+ injectFirst: true,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_init.default, {
+ entity: entity,
+ multiEntities: multiEntities,
+ entityFileNames: entityFileNames,
+ userManualLink: userManualLink,
+ others: others,
+ cLabel: cLabel,
+ xLabel: xLabel,
+ yLabel: yLabel,
+ forecast: forecast,
+ operations: operations,
+ descriptions: ensureQuillDelta(descriptions),
+ molSvg: molSvg,
+ multiMolSvgs: multiMolSvgs,
+ editorOnly: editorOnly,
+ exactMass: exactMass,
+ canChangeDescription: canChangeDescription,
+ onDescriptionChanged: onDescriptionChanged
+ })
+ })
+});
+exports.SpectraEditor = SpectraEditor;
+SpectraEditor.propTypes = {
+ entity: _propTypes.default.object.isRequired,
+ multiEntities: _propTypes.default.array,
+ entityFileNames: _propTypes.default.array,
+ others: _propTypes.default.object,
+ cLabel: _propTypes.default.string,
+ xLabel: _propTypes.default.string,
+ yLabel: _propTypes.default.string,
+ forecast: _propTypes.default.object,
+ operations: _propTypes.default.array,
+ descriptions: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.array]),
+ molSvg: _propTypes.default.string,
+ multiMolSvgs: _propTypes.default.array,
+ editorOnly: _propTypes.default.bool,
+ canChangeDescription: _propTypes.default.bool,
+ onDescriptionChanged: _propTypes.default.func,
+ userManualLink: _propTypes.default.object,
+ exactMass: _propTypes.default.string
+};
+SpectraEditor.defaultProps = {
+ others: {
+ others: [],
+ addOthersCb: false
+ },
+ multiEntities: false,
+ entityFileNames: false,
+ cLabel: '',
+ xLabel: '',
+ yLabel: '',
+ forecast: {},
+ operations: [],
+ descriptions: [],
+ molSvg: '',
+ exactMass: '',
+ multiMolSvgs: [],
+ editorOnly: false,
+ canChangeDescription: false,
+ userManualLink: {}
+};
\ No newline at end of file
diff --git a/dist/components/cmd_bar/01_viewer.js b/dist/components/cmd_bar/01_viewer.js
new file mode 100644
index 00000000..637df919
--- /dev/null
+++ b/dist/components/cmd_bar/01_viewer.js
@@ -0,0 +1,85 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _SpellcheckOutlined = _interopRequireDefault(require("@mui/icons-material/SpellcheckOutlined"));
+var _TimelineOutlined = _interopRequireDefault(require("@mui/icons-material/TimelineOutlined"));
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _ui = require("../../actions/ui");
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _common = require("./common");
+var _list_ui = require("../../constants/list_ui");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, react/function-component-definition */
+
+const styles = () => Object.assign({}, _common.commonStyle);
+const Viewer = ({
+ classes,
+ isfocusSpectrumSt,
+ isfocusAnalysisSt,
+ hideCmdAnaViewerSt,
+ disableCmdAnaViewerSt,
+ setUiViewerTypeAct
+}) => {
+ const onViewSpectrum = () => setUiViewerTypeAct(_list_ui.LIST_UI_VIEWER_TYPE.SPECTRUM);
+ const onViewAnalysis = () => setUiViewerTypeAct(_list_ui.LIST_UI_VIEWER_TYPE.ANALYSIS);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.group,
+ "data-testid": "Viewer",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Spectrum Viewer"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isfocusSpectrumSt, classes), 'btn-sv-bar-spctrum'),
+ onClick: onViewSpectrum,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_TimelineOutlined.default, {
+ className: classes.icon
+ })
+ })
+ }), hideCmdAnaViewerSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Analysis Viewer"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isfocusAnalysisSt, classes), 'btn-sv-bar-analysis'),
+ disabled: disableCmdAnaViewerSt,
+ onClick: onViewAnalysis,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_SpellcheckOutlined.default, {
+ className: classes.icon
+ })
+ })
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ isfocusSpectrumSt: state.ui.viewer === _list_ui.LIST_UI_VIEWER_TYPE.SPECTRUM,
+ isfocusAnalysisSt: state.ui.viewer === _list_ui.LIST_UI_VIEWER_TYPE.ANALYSIS,
+ hideCmdAnaViewerSt: _cfg.default.hideCmdAnaViewer(state.layout) || props.editorOnly,
+ disableCmdAnaViewerSt: _cfg.default.btnCmdAnaViewer(state.layout)
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setUiViewerTypeAct: _ui.setUiViewerType
+}, dispatch);
+Viewer.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ isfocusSpectrumSt: _propTypes.default.bool.isRequired,
+ isfocusAnalysisSt: _propTypes.default.bool.isRequired,
+ hideCmdAnaViewerSt: _propTypes.default.bool.isRequired,
+ disableCmdAnaViewerSt: _propTypes.default.bool.isRequired,
+ setUiViewerTypeAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(Viewer);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/02_zoom.js b/dist/components/cmd_bar/02_zoom.js
new file mode 100644
index 00000000..beed42c9
--- /dev/null
+++ b/dist/components/cmd_bar/02_zoom.js
@@ -0,0 +1,78 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _ZoomInOutlined = _interopRequireDefault(require("@mui/icons-material/ZoomInOutlined"));
+var _FindReplaceOutlined = _interopRequireDefault(require("@mui/icons-material/FindReplaceOutlined"));
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _ui = require("../../actions/ui");
+var _common = require("./common");
+var _list_ui = require("../../constants/list_ui");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, react/function-component-definition */
+
+const styles = () => Object.assign({}, _common.commonStyle);
+const Zoom = ({
+ classes,
+ isfocusZoomSt,
+ setUiSweepTypeAct
+}) => {
+ const onSweepZoomIn = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN);
+ const onSweepZoomReset = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.group,
+ "data-testid": "Zoom",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Zoom In"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isfocusZoomSt, classes), 'btn-sv-bar-zoomin'),
+ onClick: onSweepZoomIn,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZoomInOutlined.default, {
+ className: (0, _classnames.default)(classes.icon, classes.iconWp)
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Reset Zoom"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-zoomreset'),
+ onClick: onSweepZoomReset,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_FindReplaceOutlined.default, {
+ className: classes.icon
+ })
+ })
+ })
+ })]
+ });
+};
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ isfocusZoomSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setUiSweepTypeAct: _ui.setUiSweepType
+}, dispatch);
+Zoom.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ isfocusZoomSt: _propTypes.default.bool.isRequired,
+ setUiSweepTypeAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(Zoom);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/03_peak.js b/dist/components/cmd_bar/03_peak.js
new file mode 100644
index 00000000..ea2777d2
--- /dev/null
+++ b/dist/components/cmd_bar/03_peak.js
@@ -0,0 +1,186 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _AddLocationOutlined = _interopRequireDefault(require("@mui/icons-material/AddLocationOutlined"));
+var _ui = require("../../actions/ui");
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _common = require("./common");
+var _list_ui = require("../../constants/list_ui");
+var _tri_btn = _interopRequireDefault(require("./tri_btn"));
+var _edit_peak = require("../../actions/edit_peak");
+var _extractPeaksEdit = require("../../helpers/extractPeaksEdit");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline, no-unused-vars,
+react/function-component-definition, react/require-default-props, max-len,
+react/no-unused-prop-types */
+
+const styles = () => Object.assign({}, _common.commonStyle);
+const Peak = ({
+ classes,
+ setUiSweepTypeAct,
+ isFocusAddPeakSt,
+ disableAddPeakSt,
+ isFocusRmPeakSt,
+ disableRmPeakSt,
+ isFocusSetRefSt,
+ disableSetRefSt,
+ isHandleMaxAndMinPeaksSt,
+ cyclicVotaSt,
+ curveSt,
+ clearAllPeaksAct,
+ feature,
+ editPeakSt,
+ thresSt,
+ shiftSt,
+ layoutSt
+}) => {
+ let onSweepPeakAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD);
+ let onSweepPeakDELETE = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.PEAK_DELETE);
+ let onSweepAnchorShift = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT);
+ const {
+ curveIdx
+ } = curveSt;
+ const onClearAll = () => {
+ const dataPeaks = (0, _extractPeaksEdit.extractAutoPeaks)(feature, thresSt, shiftSt, layoutSt);
+ clearAllPeaksAct({
+ curveIdx,
+ dataPeaks
+ });
+ };
+ if (isHandleMaxAndMinPeaksSt) {
+ const {
+ spectraList
+ } = cyclicVotaSt;
+ const spectra = spectraList[curveIdx];
+ if (spectra) {
+ const {
+ isWorkMaxPeak
+ } = spectra;
+ if (isWorkMaxPeak) {
+ onSweepPeakAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MAX_PEAK, curveIdx);
+ onSweepPeakDELETE = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK, curveIdx);
+ } else {
+ onSweepPeakAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK, curveIdx);
+ onSweepPeakDELETE = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK, curveIdx);
+ }
+ onSweepAnchorShift = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_SET_REF, curveIdx);
+ }
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.group,
+ "data-testid": "Peak",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Add Peak"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusAddPeakSt, classes), 'btn-sv-bar-addpeak'),
+ disabled: disableAddPeakSt,
+ onClick: onSweepPeakAdd,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-addpeak'),
+ children: "P+"
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Remove Peak"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusRmPeakSt, classes), 'btn-sv-bar-rmpeak'),
+ disabled: disableRmPeakSt,
+ onClick: onSweepPeakDELETE,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmpeak'),
+ children: "P-"
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, {
+ content: {
+ tp: 'Clear All Peaks'
+ },
+ cb: onClearAll,
+ isClearAllDisabled: disableRmPeakSt,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmallpeaks'),
+ children: "P"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-rmallpeaks'),
+ children: "x"
+ })]
+ }), !disableSetRefSt ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Set Reference"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusSetRefSt, classes), 'btn-sv-bar-setref'),
+ disabled: disableSetRefSt,
+ onClick: onSweepAnchorShift,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_AddLocationOutlined.default, {
+ className: classes.icon
+ })
+ })
+ })
+ }) : null]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ isFocusAddPeakSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD || state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MAX_PEAK || state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK,
+ disableAddPeakSt: _cfg.default.btnCmdAddPeak(state.layout),
+ isFocusRmPeakSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_DELETE || state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK || state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK,
+ disableRmPeakSt: _cfg.default.btnCmdRmPeak(state.layout),
+ isFocusSetRefSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT || state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_SET_REF,
+ disableSetRefSt: _cfg.default.btnCmdSetRef(state.layout),
+ isHandleMaxAndMinPeaksSt: !_cfg.default.hidePanelCyclicVolta(state.layout),
+ cyclicVotaSt: state.cyclicvolta,
+ curveSt: state.curve,
+ editPeakSt: state.editPeak.present,
+ thresSt: state.threshold.list[state.curve.curveIdx],
+ layoutSt: state.layout,
+ shiftSt: state.shift
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setUiSweepTypeAct: _ui.setUiSweepType,
+ clearAllPeaksAct: _edit_peak.clearAllPeaks
+}, dispatch);
+Peak.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ isFocusAddPeakSt: _propTypes.default.bool.isRequired,
+ disableAddPeakSt: _propTypes.default.bool.isRequired,
+ isFocusRmPeakSt: _propTypes.default.bool.isRequired,
+ disableRmPeakSt: _propTypes.default.bool.isRequired,
+ isFocusSetRefSt: _propTypes.default.bool.isRequired,
+ disableSetRefSt: _propTypes.default.bool.isRequired,
+ setUiSweepTypeAct: _propTypes.default.func.isRequired,
+ isHandleMaxAndMinPeaksSt: _propTypes.default.bool.isRequired,
+ cyclicVotaSt: _propTypes.default.object.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ clearAllPeaksAct: _propTypes.default.func.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ editPeakSt: _propTypes.default.object.isRequired,
+ thresSt: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ shiftSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(Peak);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/04_integration.js b/dist/components/cmd_bar/04_integration.js
new file mode 100644
index 00000000..e065928d
--- /dev/null
+++ b/dist/components/cmd_bar/04_integration.js
@@ -0,0 +1,261 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _TextField = _interopRequireDefault(require("@mui/material/TextField"));
+var _react2 = _interopRequireDefault(require("@mdi/react"));
+var _js = require("@mdi/js");
+var _integration = require("../../actions/integration");
+var _ui = require("../../actions/ui");
+var _list_ui = require("../../constants/list_ui");
+var _integration_draft = require("../../helpers/integration_draft.js");
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _tri_btn = _interopRequireDefault(require("./tri_btn"));
+var _common = require("./common");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition, react/require-default-props, max-len,
+react/no-unused-prop-types */
+
+// eslint-disable-line import/extensions
+
+const styles = () => Object.assign({
+ field: {
+ width: 80
+ },
+ txtIcon: {},
+ cancelBtn: {
+ borderColor: '#d32f2f',
+ color: '#d32f2f',
+ '&:hover': {
+ backgroundColor: '#ffebee'
+ }
+ }
+}, _common.commonStyle);
+const iconSize = '16px';
+const setFactor = (classes, isDisable, integrationSt, setIntegrationFkrAct, curveIdx) => {
+ const onFactorChanged = e => {
+ e.target.blur();
+ setIntegrationFkrAct({
+ factor: e.target.value,
+ curveIdx
+ });
+ };
+ const onEnterPress = e => {
+ if (e.key === 'Enter') {
+ setIntegrationFkrAct({
+ factor: e.target.value,
+ curveIdx
+ });
+ }
+ };
+ let refFactor = 1.00;
+ const {
+ integrations
+ } = integrationSt;
+ if (integrations && curveIdx < integrations.length) {
+ const selectedIntegration = integrations[curveIdx];
+ refFactor = selectedIntegration.refFactor || 1.00;
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
+ className: classes.field,
+ disabled: isDisable,
+ id: "intg-factor-name",
+ type: "number",
+ value: refFactor,
+ margin: "none",
+ InputProps: {
+ className: (0, _classnames.default)(classes.txtInput, 'txtfield-sv-bar-input')
+ },
+ label: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtLabel, 'txtfield-sv-bar-label'),
+ children: "Ref Area"
+ }),
+ onChange: onFactorChanged,
+ onBlur: onFactorChanged,
+ onKeyUp: onEnterPress,
+ variant: "outlined"
+ });
+};
+const iconColor = criteria => criteria ? '#fff' : '#000';
+const Integration = ({
+ classes,
+ ignoreRef,
+ isDisableSt,
+ isFocusAddIntgSt,
+ isFocusRmIntgSt,
+ isFocusSetRefSt,
+ isFocusSplitIntgSt,
+ setUiSweepTypeAct,
+ setIntegrationFkrAct,
+ clearIntegrationAllAct,
+ curveSt,
+ integrationSt
+}) => {
+ const {
+ curveIdx
+ } = curveSt;
+ const onCancelTool = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN, curveIdx);
+ const onSweepIntegtAdd = () => {
+ if (isFocusAddIntgSt) {
+ (0, _integration_draft.clearPendingIntegrationDraft)();
+ onCancelTool();
+ return;
+ }
+ setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD, curveIdx);
+ };
+ const onSweepIntegtRm = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_RM);
+ const onSweepIntegtSR = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF);
+ const onSweepIntegtSplit = () => {
+ if (isFocusSplitIntgSt) {
+ onCancelTool();
+ return;
+ }
+ setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, curveIdx);
+ };
+ const onClearAll = () => clearIntegrationAllAct({
+ curveIdx
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.group,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Add Integration"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_common.MuButton, {
+ className: (0, _classnames.default)(isFocusAddIntgSt ? classes.cancelBtn : (0, _common.focusStyle)(false, classes), 'btn-add-inter'),
+ disabled: isDisableSt,
+ onClick: onSweepIntegtAdd,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, {
+ path: isFocusAddIntgSt ? _js.mdiClose : _js.mdiMathIntegral,
+ size: iconSize,
+ color: isFocusAddIntgSt ? '#d32f2f' : iconColor(isDisableSt),
+ className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-addint')
+ }), isFocusAddIntgSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-addint'),
+ children: "+"
+ })]
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Remove Integration"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusRmIntgSt, classes), 'btn-remove-inter'),
+ disabled: isDisableSt,
+ onClick: onSweepIntegtRm,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, {
+ path: _js.mdiMathIntegral,
+ size: iconSize,
+ color: iconColor(isFocusRmIntgSt || isDisableSt),
+ className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-rmint')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-rmint'),
+ children: "-"
+ })]
+ })
+ })
+ }), ignoreRef ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Set Integration Reference"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusSetRefSt, classes), 'btn-set-inter-ref'),
+ disabled: isDisableSt,
+ onClick: onSweepIntegtSR,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, {
+ path: _js.mdiReflectVertical,
+ size: iconSize,
+ color: iconColor(isFocusSetRefSt || isDisableSt),
+ className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-refint')
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Split Integration"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_common.MuButton, {
+ className: (0, _classnames.default)(isFocusSplitIntgSt ? classes.cancelBtn : (0, _common.focusStyle)(false, classes), 'btn-split-inter'),
+ disabled: isDisableSt,
+ onClick: onSweepIntegtSplit,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, {
+ path: isFocusSplitIntgSt ? _js.mdiClose : _js.mdiMathIntegral,
+ size: iconSize,
+ color: isFocusSplitIntgSt ? '#d32f2f' : iconColor(isDisableSt),
+ className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-splitint')
+ }), isFocusSplitIntgSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-splitint'),
+ children: "/"
+ })]
+ })
+ })
+ }), !ignoreRef ? setFactor(classes, isDisableSt, integrationSt, setIntegrationFkrAct, curveIdx) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, {
+ content: {
+ tp: 'Clear All Integration'
+ },
+ cb: onClearAll,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, {
+ path: _js.mdiMathIntegral,
+ size: iconSize,
+ color: iconColor(isDisableSt),
+ className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-rmallint')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-rmallint'),
+ children: "x"
+ })]
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ isDisableSt: _cfg.default.btnCmdIntg(state.layout),
+ isFocusAddIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ isFocusRmIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_RM,
+ isFocusSetRefSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF,
+ isFocusSplitIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT,
+ ignoreRef: _format.default.isHplcUvVisLayout(state.layout),
+ curveSt: state.curve,
+ integrationSt: state.integration.present
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setUiSweepTypeAct: _ui.setUiSweepType,
+ setIntegrationFkrAct: _integration.setIntegrationFkr,
+ clearIntegrationAllAct: _integration.clearIntegrationAll
+}, dispatch);
+Integration.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ isDisableSt: _propTypes.default.bool.isRequired,
+ isFocusAddIntgSt: _propTypes.default.bool.isRequired,
+ isFocusRmIntgSt: _propTypes.default.bool.isRequired,
+ isFocusSetRefSt: _propTypes.default.bool.isRequired,
+ isFocusSplitIntgSt: _propTypes.default.bool.isRequired,
+ ignoreRef: _propTypes.default.bool.isRequired,
+ setUiSweepTypeAct: _propTypes.default.func.isRequired,
+ setIntegrationFkrAct: _propTypes.default.func.isRequired,
+ clearIntegrationAllAct: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ integrationSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(Integration));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/05_multiplicity.js b/dist/components/cmd_bar/05_multiplicity.js
new file mode 100644
index 00000000..c725320e
--- /dev/null
+++ b/dist/components/cmd_bar/05_multiplicity.js
@@ -0,0 +1,160 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _ui = require("../../actions/ui");
+var _multiplicity = require("../../actions/multiplicity");
+var _list_ui = require("../../constants/list_ui");
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _tri_btn = _interopRequireDefault(require("./tri_btn"));
+var _common = require("./common");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition, react/require-default-props, max-len,
+react/no-unused-prop-types */
+
+const styles = () => Object.assign({}, _common.commonStyle);
+const Multiplicity = ({
+ classes,
+ isFocusAddMpySt,
+ disableAddMpySt,
+ isFocusRmMpySt,
+ disableRmMpySt,
+ isFocusAddPeakSt,
+ isFocusRmPeakSt,
+ disableMpyPeakSt,
+ setUiSweepTypeAct,
+ clearMpyAllAct,
+ curveSt
+}) => {
+ const onSweepMutAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_SWEEP_ADD);
+ const onOneMutAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_RM);
+ const onPeakMutAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_ADD);
+ const onPeakMutRm = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_RM);
+ const {
+ curveIdx
+ } = curveSt;
+ const onClearAll = () => clearMpyAllAct({
+ curveIdx
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.group,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Add Multiplicity"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusAddMpySt, classes), 'btn-sv-bar-addmpy'),
+ disabled: disableAddMpySt,
+ onClick: onSweepMutAdd,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-addmpy'),
+ children: "J+"
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Remove Multiplicity"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusRmMpySt, classes), 'btn-sv-bar-rmmpy'),
+ disabled: disableRmMpySt,
+ onClick: onOneMutAdd,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmmpy'),
+ children: "J-"
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Add Peak for Multiplicity"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusAddPeakSt, classes), 'btn-sv-bar-addpeakmpy'),
+ disabled: disableMpyPeakSt,
+ onClick: onPeakMutAdd,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-addpeakmpy'),
+ children: "JP+"
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Remove Peak for Multiplicity"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusRmPeakSt, classes), 'btn-sv-bar-rmpeakmpy'),
+ disabled: disableMpyPeakSt,
+ onClick: onPeakMutRm,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmpeakmpy'),
+ children: "JP-"
+ })
+ })
+ })
+ }), disableAddMpySt ? null :
+ /*#__PURE__*/
+ // eslint-disable-line
+ (0, _jsxRuntime.jsx)(_tri_btn.default, {
+ content: {
+ tp: 'Clear All Multiplicity'
+ },
+ cb: onClearAll,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmallmpy'),
+ children: "Jx"
+ })
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ isFocusAddMpySt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_SWEEP_ADD,
+ disableAddMpySt: _cfg.default.btnCmdMpy(state.layout),
+ isFocusRmMpySt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_RM,
+ disableRmMpySt: _cfg.default.btnCmdMpy(state.layout),
+ isFocusAddPeakSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_ADD,
+ isFocusRmPeakSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_RM,
+ disableMpyPeakSt: _cfg.default.btnCmdMpyPeak(state.layout, state.multiplicity.present, state.curve.curveIdx),
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setUiSweepTypeAct: _ui.setUiSweepType,
+ clearMpyAllAct: _multiplicity.clearMpyAll
+}, dispatch);
+Multiplicity.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ isFocusAddMpySt: _propTypes.default.bool.isRequired,
+ disableAddMpySt: _propTypes.default.bool.isRequired,
+ isFocusRmMpySt: _propTypes.default.bool.isRequired,
+ disableRmMpySt: _propTypes.default.bool.isRequired,
+ isFocusAddPeakSt: _propTypes.default.bool.isRequired,
+ isFocusRmPeakSt: _propTypes.default.bool.isRequired,
+ disableMpyPeakSt: _propTypes.default.bool.isRequired,
+ setUiSweepTypeAct: _propTypes.default.func.isRequired,
+ clearMpyAllAct: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(Multiplicity));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/06_undo_redo.js b/dist/components/cmd_bar/06_undo_redo.js
new file mode 100644
index 00000000..24a8bae7
--- /dev/null
+++ b/dist/components/cmd_bar/06_undo_redo.js
@@ -0,0 +1,84 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reduxUndo = require("redux-undo");
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _RedoOutlined = _interopRequireDefault(require("@mui/icons-material/RedoOutlined"));
+var _UndoOutlined = _interopRequireDefault(require("@mui/icons-material/UndoOutlined"));
+var _common = require("./common");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition, react/require-default-props, max-len,
+react/no-unused-prop-types */
+
+const styles = () => Object.assign({}, _common.commonStyle);
+const UndoRedo = ({
+ classes,
+ canUndo,
+ canRedo,
+ onUndoAct,
+ onRedoAct
+}) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.group,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Undo"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-undo'),
+ disabled: !canUndo,
+ onClick: onUndoAct,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_UndoOutlined.default, {
+ className: classes.icon
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Redo"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-redo'),
+ disabled: !canRedo,
+ onClick: onRedoAct,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RedoOutlined.default, {
+ className: classes.icon
+ })
+ })
+ })
+ })]
+});
+const canUndoFunc = state => state.editPeak.past.length > 0 || state.integration.past.length > 0 || state.multiplicity.past.length > 0;
+const canRedoFunc = state => state.editPeak.future.length > 0 || state.integration.future.length > 0 || state.multiplicity.future.length > 0;
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ canUndo: canUndoFunc(state),
+ canRedo: canRedoFunc(state)
+});
+const mapDispatchToProps = dispatch => ({
+ onUndoAct: () => dispatch(_reduxUndo.ActionCreators.undo()),
+ onRedoAct: () => dispatch(_reduxUndo.ActionCreators.redo())
+});
+UndoRedo.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ canUndo: _propTypes.default.bool.isRequired,
+ canRedo: _propTypes.default.bool.isRequired,
+ onUndoAct: _propTypes.default.func.isRequired,
+ onRedoAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(UndoRedo);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/07_pecker.js b/dist/components/cmd_bar/07_pecker.js
new file mode 100644
index 00000000..d8fbf678
--- /dev/null
+++ b/dist/components/cmd_bar/07_pecker.js
@@ -0,0 +1,193 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _material = require("@mui/material");
+var _AddLocationOutlined = _interopRequireDefault(require("@mui/icons-material/AddLocationOutlined"));
+var _ui = require("../../actions/ui");
+var _common = require("./common");
+var _list_ui = require("../../constants/list_ui");
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition, react/require-default-props, max-len,
+react/no-unused-prop-types */
+
+const styles = () => Object.assign({
+ field: {
+ width: 80
+ },
+ txtIcon: {}
+}, _common.commonStyle);
+const setRef = (classes, cyclicVotaSt, curveIdx, setCylicVoltaRefFactorAct) => {
+ const {
+ spectraList
+ } = cyclicVotaSt;
+ const spectra = spectraList[curveIdx];
+ let refFactor = 0.0;
+ let hasRefPeaks = false;
+ if (spectra) {
+ const {
+ shift,
+ hasRefPeak
+ } = spectra;
+ const {
+ val
+ } = shift;
+ refFactor = val;
+ hasRefPeaks = hasRefPeak;
+ }
+ const onFactorChanged = e => setCylicVoltaRefFactorAct({
+ factor: e.target.value,
+ curveIdx
+ });
+ const onEnterPress = e => {
+ if (e.key === 'Enter') {
+ setCylicVoltaRefFactorAct({
+ factor: e.target.value,
+ curveIdx
+ });
+ }
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TextField, {
+ className: classes.field,
+ id: "intg-factor-name",
+ type: "number",
+ value: refFactor,
+ margin: "none",
+ InputProps: {
+ className: (0, _classnames.default)(classes.txtInput, 'txtfield-sv-bar-input')
+ },
+ label: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtLabel, 'txtfield-sv-bar-label'),
+ children: hasRefPeaks ? 'Ref Value (V)' : 'Shift'
+ }),
+ variant: "outlined",
+ onChange: onFactorChanged,
+ onBlur: onFactorChanged,
+ onKeyUp: onEnterPress
+ });
+};
+const Pecker = ({
+ classes,
+ layoutSt,
+ isFocusAddPeckerSt,
+ isFocusRmPeckerSt,
+ setUiSweepTypeAct,
+ curveSt,
+ cyclicVotaSt,
+ setCylicVoltaRefFactorAct,
+ isFocusSetRefSt,
+ setCylicVoltaRefAct
+}) => {
+ const {
+ curveIdx
+ } = curveSt;
+ const onSweepPeckerAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_PECKER, curveIdx);
+ const onSweepPeckerDELETE = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_PECKER, curveIdx);
+ const onConfirmSetRef = () => setCylicVoltaRefAct({
+ jcampIdx: curveIdx
+ });
+ const {
+ spectraList
+ } = cyclicVotaSt;
+ const spectra = spectraList[curveIdx];
+ let hasRefPeaks = false;
+ if (spectra) {
+ const {
+ hasRefPeak
+ } = spectra;
+ hasRefPeaks = hasRefPeak;
+ }
+ return !_cfg.default.hidePanelCyclicVolta(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ "data-testid": "Pecker",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Add Pecker"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusAddPeckerSt, classes), 'btn-sv-bar-addpecker'),
+ onClick: onSweepPeckerAdd,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-addpeak'),
+ children: ["I", /*#__PURE__*/(0, _jsxRuntime.jsx)("sub", {
+ children: "\u03BB0"
+ }), "+"]
+ })
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Remove Pecker"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusRmPeckerSt, classes), 'btn-sv-bar-rmpecker'),
+ onClick: onSweepPeckerDELETE,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmpeak'),
+ children: ["I", /*#__PURE__*/(0, _jsxRuntime.jsx)("sub", {
+ children: "\u03BB0"
+ }), "-"]
+ })
+ })
+ })
+ }), setRef(classes, cyclicVotaSt, curveIdx, setCylicVoltaRefFactorAct), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: hasRefPeaks ? 'Set Reference' : 'Set Shift'
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)((0, _common.focusStyle)(isFocusSetRefSt, classes), 'btn-sv-bar-setref'),
+ onClick: onConfirmSetRef,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_AddLocationOutlined.default, {
+ className: classes.icon
+ })
+ })
+ })
+ })]
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {});
+};
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ isFocusAddPeckerSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_PECKER,
+ isFocusRmPeckerSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_PECKER,
+ isFocusSetRefSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT || state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_SET_REF,
+ cyclicVotaSt: state.cyclicvolta,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setUiSweepTypeAct: _ui.setUiSweepType,
+ setCylicVoltaRefFactorAct: _cyclic_voltammetry.setCylicVoltaRefFactor,
+ setCylicVoltaRefAct: _cyclic_voltammetry.setCylicVoltaRef
+}, dispatch);
+Pecker.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ isFocusAddPeckerSt: _propTypes.default.bool.isRequired,
+ isFocusRmPeckerSt: _propTypes.default.bool.isRequired,
+ setUiSweepTypeAct: _propTypes.default.func.isRequired,
+ isFocusSetRefSt: _propTypes.default.bool.isRequired,
+ cyclicVotaSt: _propTypes.default.object.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ setCylicVoltaRefFactorAct: _propTypes.default.func.isRequired,
+ setCylicVoltaRefAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(Pecker);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/common.js b/dist/components/cmd_bar/common.js
new file mode 100644
index 00000000..f99639f0
--- /dev/null
+++ b/dist/components/cmd_bar/common.js
@@ -0,0 +1,127 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.focusStyle = exports.commonStyle = exports.MuButton = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _styles = require("@mui/styles");
+var _Button = _interopRequireDefault(require("@mui/material/Button"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable no-unused-vars, max-len, indent, react/function-component-definition, react/self-closing-comp, react/prop-types, react/jsx-props-no-spreading */
+
+const useStyles = (0, _styles.makeStyles)(theme => ({
+ muiBtn: {
+ border: '1px solid #ccc',
+ borderRadius: 4,
+ fontFamily: 'Helvetica',
+ fontSize: 20,
+ height: 30,
+ lineHeight: '20px',
+ minWidth: 30,
+ padding: 0,
+ width: 30,
+ color: 'black'
+ }
+}));
+const MuButton = props => {
+ const classes = useStyles();
+ const {
+ className,
+ ...other
+ } = props;
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
+ className: (0, _classnames.default)(classes.muiBtn, className),
+ ...other
+ });
+};
+exports.MuButton = MuButton;
+const commonStyle = exports.commonStyle = {
+ card: {
+ margin: '0 0 5px 52px',
+ border: '1px solid white',
+ borderRadius: 4
+ },
+ group: {
+ display: 'inline-block',
+ margin: '0px 0px 0px 10px',
+ verticalAlign: 'middle'
+ },
+ groupRightMost: {
+ display: 'inline-block',
+ float: 'right',
+ margin: '0px 0px 0px 10px',
+ verticalAlign: 'middle'
+ },
+ groupRight: {
+ display: 'inline-block',
+ float: 'right',
+ margin: '0px 0px 0px 10px',
+ verticalAlign: 'middle'
+ },
+ btnHt: {
+ backgroundColor: '#2196f3',
+ color: '#fff',
+ '&:hover': {
+ backgroundColor: '#51c6f3'
+ }
+ },
+ iconWp: {
+ border: '1px dashed',
+ borderRadius: '4px'
+ },
+ icon: {
+ fontSize: 20
+ },
+ iconMdi: {
+ fontSize: 20
+ },
+ txt: {
+ fontFamily: 'Helvetica',
+ fontSize: 12,
+ fontStyle: 'italic',
+ fontWeight: 'bold'
+ },
+ txtLabel: {
+ fontFamily: 'Helvetica',
+ fontSize: 12
+ },
+ txtInput: {
+ fontFamily: 'Helvetica',
+ fontSize: 12,
+ height: 30
+ },
+ txtOpt: {
+ fontFamily: 'Helvetica',
+ fontSize: 12
+ },
+ selectLabel: {
+ fontFamily: 'Helvetica',
+ fontSize: 12
+ },
+ selectInput: {
+ height: 30
+ },
+ txtLabelBottomInput: {
+ fontFamily: 'Helvetica',
+ backgroundColor: 'white',
+ fontSize: 12,
+ margin: '22% 0 0 7px',
+ padding: '0 10px 0 10px',
+ transform: 'scale(0.75)'
+ },
+ txtLabelTopInput: {
+ fontFamily: 'Helvetica',
+ backgroundColor: 'white',
+ fontSize: 12,
+ margin: '-8% 0 0 7px',
+ padding: '0 10px 0 10px',
+ transform: 'scale(0.75)'
+ }
+};
+const focusStyle = (criteria, cls) => criteria ? [cls.btnHt] : [];
+
+// eslint-disable-line
+exports.focusStyle = focusStyle;
\ No newline at end of file
diff --git a/dist/components/cmd_bar/index.js b/dist/components/cmd_bar/index.js
new file mode 100644
index 00000000..5b000116
--- /dev/null
+++ b/dist/components/cmd_bar/index.js
@@ -0,0 +1,88 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _common = require("./common");
+var _viewer = _interopRequireDefault(require("./01_viewer"));
+var _zoom = _interopRequireDefault(require("./02_zoom"));
+var _peak = _interopRequireDefault(require("./03_peak"));
+var _integration = _interopRequireDefault(require("./04_integration"));
+var _multiplicity = _interopRequireDefault(require("./05_multiplicity"));
+var _undo_redo = _interopRequireDefault(require("./06_undo_redo"));
+var _r01_layout = _interopRequireDefault(require("./r01_layout"));
+var _r03_threshold = _interopRequireDefault(require("./r03_threshold"));
+var _r04_submit = _interopRequireDefault(require("./r04_submit"));
+var _r07_wavelength_btn = _interopRequireDefault(require("./r07_wavelength_btn"));
+var _pecker = _interopRequireDefault(require("./07_pecker"));
+var _r08_change_axes = _interopRequireDefault(require("./r08_change_axes"));
+var _r09_detector = _interopRequireDefault(require("./r09_detector"));
+var _r10_cv_density = _interopRequireDefault(require("./r10_cv_density"));
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition, react/require-default-props */
+
+const styles = () => Object.assign({}, {}, _common.commonStyle);
+const CmdBar = ({
+ classes,
+ feature,
+ hasEdit,
+ forecast,
+ operations,
+ editorOnly,
+ jcampIdx,
+ hideThreshold,
+ layoutSt
+}) => {
+ const isCvLayout = _format.default.isCyclicVoltaLayout(layoutSt);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.card,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_viewer.default, {
+ editorOnly: editorOnly
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_zoom.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_peak.default, {
+ jcampIdx: jcampIdx,
+ feature: feature
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_pecker.default, {
+ jcampIdx: jcampIdx
+ }), isCvLayout ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_integration.default, {}), isCvLayout ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_undo_redo.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r04_submit.default, {
+ operations: operations,
+ feature: feature,
+ forecast: forecast,
+ editorOnly: editorOnly,
+ hideSwitch: false,
+ disabled: false
+ }), hideThreshold ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_r03_threshold.default, {
+ feature: feature,
+ hasEdit: hasEdit
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r01_layout.default, {
+ feature: feature,
+ hasEdit: hasEdit
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r07_wavelength_btn.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r10_cv_density.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r08_change_axes.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r09_detector.default, {})]
+ });
+};
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+CmdBar.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ forecast: _propTypes.default.object.isRequired,
+ hasEdit: _propTypes.default.bool.isRequired,
+ operations: _propTypes.default.array.isRequired,
+ editorOnly: _propTypes.default.bool.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ jcampIdx: _propTypes.default.any,
+ hideThreshold: _propTypes.default.bool
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(CmdBar);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r01_layout.js b/dist/components/cmd_bar/r01_layout.js
new file mode 100644
index 00000000..9c52d9b7
--- /dev/null
+++ b/dist/components/cmd_bar/r01_layout.js
@@ -0,0 +1,381 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireWildcard(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _r02_scan = _interopRequireDefault(require("./r02_scan"));
+var _layout = require("../../actions/layout");
+var _shift = require("../../actions/shift");
+var _list_layout = require("../../constants/list_layout");
+var _list_shift = require("../../constants/list_shift");
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _common = require("./common");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition */
+
+const styles = () => Object.assign({
+ fieldShift: {
+ width: 160
+ },
+ fieldLayout: {
+ width: 100
+ }
+}, _common.commonStyle);
+const chemSubStyle = {
+ fontSize: '0.85em',
+ position: 'relative',
+ top: '0.24em',
+ lineHeight: 1
+};
+const renderReadableSubscript = (txt = '') => {
+ if (typeof txt !== 'string') return txt;
+ const regex = /([A-Za-z])(\d+)/g;
+ if (!regex.test(txt)) return txt;
+ regex.lastIndex = 0;
+ const parts = [];
+ let cursor = 0;
+ let match = regex.exec(txt);
+ while (match) {
+ const [raw, prefix, digits] = match;
+ const at = match.index;
+ if (at > cursor) parts.push(txt.slice(cursor, at));
+ parts.push(prefix);
+ parts.push(/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ style: chemSubStyle,
+ children: digits
+ }, `${at}-${digits}`));
+ cursor = at + raw.length;
+ match = regex.exec(txt);
+ }
+ if (cursor < txt.length) parts.push(txt.slice(cursor));
+ return parts;
+};
+const shiftSelect = (classes, layoutSt, setShiftRefAct, shiftSt, curveSt) => {
+ if (_cfg.default.hideSolvent(layoutSt)) {
+ return null;
+ }
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ shifts
+ } = shiftSt;
+ const selectedShift = shifts[curveIdx] || {};
+ const listShift = (0, _list_shift.getListShift)(layoutSt) || [];
+ const shiftRefName = selectedShift?.ref?.name || '';
+ const isInList = listShift.some(r => r.name === shiftRefName);
+ const selectValue = isInList ? shiftRefName : '';
+ const onChange = e => {
+ const name = e.target.value;
+ const refObj = listShift.find(r => r.name === name);
+ if (refObj) {
+ setShiftRefAct({
+ dataToSet: refObj,
+ curveIdx
+ });
+ }
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldShift),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-solvent-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Reference"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ value: selectValue,
+ labelId: "select-solvent-label",
+ label: "Solvent",
+ onChange: onChange,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-shift'),
+ children: listShift.map(ref => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: ref.name,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-shift'),
+ children: [renderReadableSubscript(ref.name), `: ${_format.default.strNumberFixedDecimal(ref.value, 2)} ppm`]
+ })
+ }, ref.name))
+ })]
+ });
+};
+const layoutSelect = (classes, layoutSt, updateLayoutAct) => {
+ const onChange = e => updateLayoutAct(e.target.value);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldLayout),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-layout-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Layout"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, {
+ labelId: "select-layout-label",
+ label: "Layout",
+ value: layoutSt,
+ onChange: onChange,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.PLAIN,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "plain"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.IR,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "IR"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.RAMAN,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "RAMAN"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.UVVIS,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "UV/VIS"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.HPLC_UVVIS,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "HPLC UV/VIS"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.TGA,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "TGA (THERMOGRAVIMETRIC ANALYSIS)"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.DSC,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "DSC (DIFFERENTIAL SCANNING CALORIMETRY)"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.XRD,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "XRD (X-RAY DIFFRACTION)"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.H1,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "1"
+ }), "H"]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.C13,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "13"
+ }), "C"]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.F19,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "19"
+ }), "F"]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.P31,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "31"
+ }), "P"]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.N15,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "15"
+ }), "N"]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.Si29,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "29"
+ }), "Si"]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.MS,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "MS"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "CV (CYCLIC VOLTAMMETRY)"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.CDS,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "CDS (CIRCULAR DICHROISM SPECTROSCOPY)"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.SEC,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "SEC"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.GC,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "GC (GAS CHROMATOGRAPHY)"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.AIF,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "SORPTION-DESORPTION"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.EMISSIONS,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "EMISSIONS"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.DLS_ACF,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "DLS ACF"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: _list_layout.LIST_LAYOUT.DLS_INTENSITY,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: "DLS INTENSITY"
+ })
+ })]
+ })]
+ });
+};
+const PLACEHOLDER = '- - -';
+const norm = s => (s || '').toString().toLowerCase().normalize('NFKD').replace(/[^a-z0-9]+/g, '');
+function solventKeyOf(feature) {
+ const r = feature?.metadata?.solventName ?? feature?.metadata?.solvent ?? feature?.meta?.solventName ?? feature?.meta?.solvent ?? feature?.solventName ?? feature?.solvent ?? null;
+ const a = feature?.metadata?.solvent_label ?? feature?.metadata?.solventLabel ?? null;
+ const raw = r && r !== PLACEHOLDER ? r : null;
+ const alt = a && a !== PLACEHOLDER ? a : null;
+ return norm(raw || alt || '');
+}
+function pickBestRef(list, key) {
+ if (!key || !list?.length) return null;
+ const scored = [];
+ list.forEach(r => {
+ const nLabel = norm(r.label);
+ const nName = norm(r.name);
+ const nNsdb = norm(r.nsdb);
+ let s = 0;
+ if (nLabel && nLabel === key) s += 3;
+ if (nNsdb && nNsdb.includes(key)) s += 2;
+ if (nName && nName.includes(key)) s += 1;
+ if (s > 0) scored.push({
+ r,
+ s
+ });
+ });
+ if (!scored.length) return null;
+ let max = 0;
+ scored.forEach(x => {
+ if (x.s > max) max = x.s;
+ });
+ let cand = scored.filter(x => x.s === max).map(x => x.r);
+ if (cand.length > 1) {
+ const vals = cand.map(c => typeof c.value === 'number' ? c.value : null).filter(v => v != null).sort((a, b) => a - b);
+ if (vals.length) {
+ const m = vals[Math.floor(vals.length / 2)];
+ cand = cand.slice().sort((a, b) => Math.abs((a.value ?? m) - m) - Math.abs((b.value ?? m) - m));
+ }
+ if (cand.length > 1) {
+ cand.sort((a, b) => (a.name?.length || 0) - (b.name?.length || 0));
+ }
+ }
+ return cand[0] || null;
+}
+function isRefUnset(shiftSt, curveIdx, list) {
+ const name = shiftSt?.shifts?.[curveIdx]?.ref?.name || '';
+ if (!name || name === PLACEHOLDER) return true;
+ return !(list || []).some(r => r.name === name);
+}
+const Layout = ({
+ classes,
+ feature,
+ hasEdit,
+ layoutSt,
+ setShiftRefAct,
+ updateLayoutAct,
+ curveSt,
+ shiftSt
+}) => {
+ const {
+ curveIdx
+ } = curveSt;
+ const list = (0, _list_shift.getListShift)(layoutSt) || [];
+ const unset = isRefUnset(shiftSt, curveIdx, list);
+ const key = solventKeyOf(feature);
+ const best = pickBestRef(list, key);
+ (0, _react.useEffect)(() => {
+ if (unset && best) setShiftRefAct({
+ dataToSet: best,
+ curveIdx
+ });
+ }, [unset, best, curveIdx, setShiftRefAct]);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.groupRight,
+ children: [layoutSelect(classes, layoutSt, updateLayoutAct), shiftSelect(classes, layoutSt, setShiftRefAct, shiftSt, curveSt), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r02_scan.default, {
+ feature: feature,
+ hasEdit: hasEdit
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ curveSt: state.curve,
+ shiftSt: state.shift
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setShiftRefAct: _shift.setShiftRef,
+ updateLayoutAct: _layout.updateLayout
+}, dispatch);
+Layout.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ hasEdit: _propTypes.default.bool.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ setShiftRefAct: _propTypes.default.func.isRequired,
+ updateLayoutAct: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ shiftSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(Layout));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r02_scan.js b/dist/components/cmd_bar/r02_scan.js
new file mode 100644
index 00000000..89c5b7a3
--- /dev/null
+++ b/dist/components/cmd_bar/r02_scan.js
@@ -0,0 +1,132 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _styles = require("@mui/styles");
+var _CloudDoneOutlined = _interopRequireDefault(require("@mui/icons-material/CloudDoneOutlined"));
+var _HowToRegOutlined = _interopRequireDefault(require("@mui/icons-material/HowToRegOutlined"));
+var _RefreshOutlined = _interopRequireDefault(require("@mui/icons-material/RefreshOutlined"));
+var _scan = require("../../actions/scan");
+var _common = require("./common");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition */
+
+const styles = () => Object.assign({
+ fieldScan: {
+ width: 90
+ }
+}, _common.commonStyle);
+const restoreIcon = (classes, hasEdit, isEdit) => hasEdit && isEdit ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_HowToRegOutlined.default, {
+ className: classes.icon
+}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_CloudDoneOutlined.default, {
+ className: classes.icon
+});
+const restoreTp = (hasEdit, isEdit) => hasEdit && isEdit ? 'User Defined Scan' : 'Auto Picked Scan';
+const btnRestore = (classes, hasEdit, isEdit, toggleEditAct) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: restoreTp(hasEdit, isEdit)
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-scanrst'),
+ disabled: !hasEdit,
+ onClick: toggleEditAct,
+ children: restoreIcon(classes, hasEdit, isEdit)
+ })
+});
+const btnRrfresh = (classes, disabled, refreshAct) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Refresh Scan"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-scanrfs'),
+ disabled: disabled,
+ onClick: refreshAct,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RefreshOutlined.default, {
+ className: classes.icon
+ })
+ })
+});
+const scanSelect = (classes, feature, layoutSt, scanSt, onChange) => {
+ const {
+ target,
+ count
+ } = scanSt;
+ if (!count) return null;
+ const range = [...Array(count + 1).keys()].slice(1);
+ const content = range.map(num => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: num,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-scan'),
+ children: `scan ${num}`
+ })
+ }, num));
+ const defaultValue = scanSt.isAuto || !feature.scanEditTarget ? feature.scanAutoTarget : feature.scanEditTarget;
+ const selValue = target || defaultValue || 1;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldScan),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-scan-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Current Scan"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ labelId: "select-scan-label",
+ label: "Current Scan",
+ value: selValue,
+ onChange: onChange,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-scan'),
+ children: content
+ })]
+ });
+};
+const Scan = ({
+ classes,
+ feature,
+ hasEdit,
+ layoutSt,
+ scanSt,
+ setScanTargetAct,
+ resetScanTargetAct,
+ toggleScanIsAutoAct
+}) => {
+ const isMs = ['MS'].indexOf(layoutSt) >= 0;
+ if (!isMs) return null;
+ const onChange = e => setScanTargetAct(e.target.value);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ children: [scanSelect(classes, feature, layoutSt, scanSt, onChange), btnRrfresh(classes, false, resetScanTargetAct), btnRestore(classes, hasEdit, !scanSt.isAuto, toggleScanIsAutoAct)]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ scanSt: state.scan
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setScanTargetAct: _scan.setScanTarget,
+ resetScanTargetAct: _scan.resetScanTarget,
+ toggleScanIsAutoAct: _scan.toggleScanIsAuto
+}, dispatch);
+Scan.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ hasEdit: _propTypes.default.bool.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ scanSt: _propTypes.default.object.isRequired,
+ setScanTargetAct: _propTypes.default.func.isRequired,
+ resetScanTargetAct: _propTypes.default.func.isRequired,
+ toggleScanIsAutoAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(styles))(Scan);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r03_threshold.js b/dist/components/cmd_bar/r03_threshold.js
new file mode 100644
index 00000000..4e2e6b38
--- /dev/null
+++ b/dist/components/cmd_bar/r03_threshold.js
@@ -0,0 +1,161 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _styles = require("@mui/styles");
+var _CloudDoneOutlined = _interopRequireDefault(require("@mui/icons-material/CloudDoneOutlined"));
+var _HowToRegOutlined = _interopRequireDefault(require("@mui/icons-material/HowToRegOutlined"));
+var _RefreshOutlined = _interopRequireDefault(require("@mui/icons-material/RefreshOutlined"));
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _threshold = require("../../actions/threshold");
+var _common = require("./common");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition */
+
+const styles = () => Object.assign({
+ field: {
+ width: 110
+ },
+ txtIcon: {}
+}, _common.commonStyle);
+const txtPercent = () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputAdornment, {
+ position: "end",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-percent",
+ children: "%"
+ })
+});
+const setThreshold = (classes, thresVal, updateThresholdValueAct, curveSt) => {
+ const {
+ curveIdx
+ } = curveSt;
+ const onBlur = e => updateThresholdValueAct({
+ value: e.target.value,
+ curveIdx
+ });
+ const onChange = e => updateThresholdValueAct({
+ value: e.target.value,
+ curveIdx
+ });
+ const onEnterPress = e => {
+ if (e.key === 'Enter') {
+ updateThresholdValueAct({
+ value: e.target.value,
+ curveIdx
+ });
+ }
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TextField, {
+ className: classes.field,
+ id: "outlined-name",
+ placeholder: "N.A.",
+ type: "number",
+ value: thresVal || 0.01,
+ margin: "none",
+ InputProps: {
+ endAdornment: txtPercent(),
+ className: (0, _classnames.default)(classes.txtInput, 'txtfield-sv-bar-input'),
+ inputProps: {
+ min: 0.01
+ }
+ },
+ onChange: onChange,
+ onBlur: onBlur,
+ onKeyPress: onEnterPress,
+ variant: "outlined"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ className: (0, _classnames.default)(classes.txtLabelBottomInput),
+ children: "Threshold"
+ })]
+ });
+};
+const restoreIcon = (classes, hasEdit, isEdit) => hasEdit && isEdit ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_HowToRegOutlined.default, {
+ className: classes.icon
+}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_CloudDoneOutlined.default, {
+ className: classes.icon
+});
+const restoreTp = (hasEdit, isEdit) => hasEdit && isEdit ? 'User Defined Threshold' : 'Auto Picked Threshold';
+const Threshold = ({
+ classes,
+ feature,
+ hasEdit,
+ hideThresSt,
+ thresValSt,
+ isEditSt,
+ curveSt,
+ updateThresholdValueAct,
+ resetThresholdValueAct,
+ toggleThresholdIsEditAct
+}) => {
+ const thresVal = thresValSt || feature.thresRef;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.groupRight,
+ children: [setThreshold(classes, thresVal, updateThresholdValueAct, curveSt), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Restore Threshold"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-thresref'),
+ disabled: _cfg.default.btnCmdThres(thresVal),
+ onClick: resetThresholdValueAct,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RefreshOutlined.default, {
+ className: classes.icon
+ })
+ })
+ })
+ }), hideThresSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: restoreTp(hasEdit, isEditSt)
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-thresrst'),
+ disabled: _cfg.default.btnCmdThres(thresVal),
+ onClick: toggleThresholdIsEditAct,
+ children: restoreIcon(classes, hasEdit, isEditSt)
+ })
+ })
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ hideThresSt: _cfg.default.hideCmdThres(state.layout),
+ isEditSt: state.threshold.list[state.curve.curveIdx].isEdit,
+ thresValSt: parseFloat(state.threshold.list[state.curve.curveIdx].value) || 0,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ updateThresholdValueAct: _threshold.updateThresholdValue,
+ resetThresholdValueAct: _threshold.resetThresholdValue,
+ toggleThresholdIsEditAct: _threshold.toggleThresholdIsEdit
+}, dispatch);
+Threshold.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ hasEdit: _propTypes.default.bool.isRequired,
+ hideThresSt: _propTypes.default.bool.isRequired,
+ isEditSt: _propTypes.default.bool.isRequired,
+ thresValSt: _propTypes.default.number.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ updateThresholdValueAct: _propTypes.default.func.isRequired,
+ resetThresholdValueAct: _propTypes.default.func.isRequired,
+ toggleThresholdIsEditAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(Threshold));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r04_submit.js b/dist/components/cmd_bar/r04_submit.js
new file mode 100644
index 00000000..3a9431f9
--- /dev/null
+++ b/dist/components/cmd_bar/r04_submit.js
@@ -0,0 +1,256 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _styles = require("@mui/styles");
+var _submit = require("../../actions/submit");
+var _r05_submit_btn = _interopRequireDefault(require("./r05_submit_btn"));
+var _r06_predict_btn = _interopRequireDefault(require("./r06_predict_btn"));
+var _common = require("./common");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition */
+
+const styles = () => Object.assign({
+ fieldOrder: {
+ width: 90
+ },
+ fieldIntensity: {
+ width: 90
+ },
+ fieldDecimal: {
+ width: 80
+ },
+ fieldOpertaion: {
+ width: 120
+ }
+}, _common.commonStyle);
+const ascendSelect = (classes, hideSwitch, isAscendSt, toggleIsAscendAct) => {
+ if (hideSwitch) return null;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldOrder),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-sort-peaks-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Write Peaks"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, {
+ labelId: "select-sort-peaks-label",
+ label: "Write Peaks",
+ value: isAscendSt,
+ onChange: toggleIsAscendAct,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-order'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: true,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-ascend'),
+ children: "Ascend"
+ })
+ }, "ascend"), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: false,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-descend'),
+ children: "Descend"
+ })
+ }, "descend")]
+ })]
+ });
+};
+const intensitySelect = (classes, hideSwitch, isIntensitySt, toggleIsIntensityAct) => {
+ if (hideSwitch) return null;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldIntensity),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-intensity-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Write Intensity"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, {
+ labelId: "select-intensity-label",
+ label: "Write Intensity",
+ value: isIntensitySt,
+ onChange: toggleIsIntensityAct,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-intensity')
+ // input={
+ // (
+ //
+ // )
+ // }
+ ,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: true,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-show'),
+ children: "Show"
+ })
+ }, "ascend"), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: false,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-hide'),
+ children: "Hide"
+ })
+ }, "descend")]
+ })]
+ });
+};
+const decimalSelect = (classes, hideSwitch, decimalSt, updateDecimalAct) => {
+ if (hideSwitch) return null;
+ const decimals = [0, 1, 2, 3, 4];
+ const options = decimals.map(d => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: d,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-decimal'),
+ children: d
+ })
+ }, d));
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldDecimal),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-decimal-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Decimal"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ labelId: "select-decimal-label",
+ label: "Decimal",
+ value: decimalSt,
+ onChange: updateDecimalAct,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-decimal')
+ // input={
+ // (
+ //
+ // )
+ // }
+ ,
+ children: options
+ })]
+ });
+};
+const operationSelect = (classes, operations, operation, onChangeSelect) => {
+ const options = operations.map(o => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: o.name,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-operation'),
+ children: o.name
+ })
+ }, o.name));
+ const selectedValue = operation.name || operations[0].name;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldOpertaion),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-submit-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Submit"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ labelId: "select-submit-label",
+ label: "Submit",
+ value: selectedValue,
+ onChange: onChangeSelect,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-operation')
+ // input={
+ // (
+ //
+ // )
+ // }
+ ,
+ children: options
+ })]
+ });
+};
+const selectOperation = (name, operations, updateOperationAct) => {
+ let operation = false;
+ operations.forEach(o => {
+ if (o.name === name) {
+ operation = o;
+ }
+ });
+ updateOperationAct(operation);
+};
+const Submit = ({
+ operations,
+ classes,
+ feature,
+ forecast,
+ editorOnly,
+ hideSwitch,
+ disabled,
+ isAscendSt,
+ isIntensitySt,
+ operationSt,
+ decimalSt,
+ isEmWaveSt,
+ toggleIsAscendAct,
+ toggleIsIntensityAct,
+ updateOperationAct,
+ updateDecimalAct
+}) => {
+ const onChangeSelect = e => selectOperation(e.target.value, operations, updateOperationAct);
+ if (!operations || operations.length === 0) return null;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.groupRightMost,
+ children: [ascendSelect(classes, hideSwitch, isAscendSt, toggleIsAscendAct), intensitySelect(classes, hideSwitch || !isEmWaveSt, isIntensitySt, toggleIsIntensityAct), decimalSelect(classes, hideSwitch, decimalSt, updateDecimalAct), editorOnly ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_r06_predict_btn.default, {
+ feature: feature,
+ forecast: forecast
+ }), operationSelect(classes, operations, operationSt, onChangeSelect), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r05_submit_btn.default, {
+ feature: feature,
+ isAscend: isAscendSt,
+ isIntensity: isIntensitySt,
+ operation: operationSt,
+ disabled: disabled
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ isEmWaveSt: _format.default.isEmWaveLayout(state.layout),
+ isAscendSt: state.submit.isAscend,
+ isIntensitySt: state.submit.isIntensity,
+ decimalSt: state.submit.decimal,
+ operationSt: state.submit.operation
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ toggleIsAscendAct: _submit.toggleIsAscend,
+ toggleIsIntensityAct: _submit.toggleIsIntensity,
+ updateOperationAct: _submit.updateOperation,
+ updateDecimalAct: _submit.updateDecimal
+}, dispatch);
+Submit.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ forecast: _propTypes.default.object.isRequired,
+ editorOnly: _propTypes.default.bool.isRequired,
+ operations: _propTypes.default.array.isRequired,
+ operationSt: _propTypes.default.object.isRequired,
+ hideSwitch: _propTypes.default.bool.isRequired,
+ disabled: _propTypes.default.bool.isRequired,
+ isAscendSt: _propTypes.default.bool.isRequired,
+ isIntensitySt: _propTypes.default.bool.isRequired,
+ isEmWaveSt: _propTypes.default.bool.isRequired,
+ decimalSt: _propTypes.default.number.isRequired,
+ toggleIsAscendAct: _propTypes.default.func.isRequired,
+ toggleIsIntensityAct: _propTypes.default.func.isRequired,
+ updateOperationAct: _propTypes.default.func.isRequired,
+ updateDecimalAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(styles))(Submit);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r05_submit_btn.js b/dist/components/cmd_bar/r05_submit_btn.js
new file mode 100644
index 00000000..78747a3d
--- /dev/null
+++ b/dist/components/cmd_bar/r05_submit_btn.js
@@ -0,0 +1,306 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _redux = require("redux");
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _PlayCircleOutline = _interopRequireDefault(require("@mui/icons-material/PlayCircleOutline"));
+var _styles = require("@mui/styles");
+var _chem = require("../../helpers/chem");
+var _common = require("./common");
+var _extractPeaksEdit = require("../../helpers/extractPeaksEdit");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+react/function-component-definition, function-call-argument-newline,
+react/require-default-props */
+
+const styles = () => Object.assign({}, _common.commonStyle);
+const getAxesSelection = (axesUnitsSt, curveIdx) => {
+ const axes = axesUnitsSt?.axes;
+ if (!Array.isArray(axes) || axes.length === 0) return {
+ xUnit: '',
+ yUnit: ''
+ };
+ const idx = Number.isFinite(curveIdx) ? curveIdx : 0;
+ return axes[idx] || axes[0] || {
+ xUnit: '',
+ yUnit: ''
+ };
+};
+const resolveAxisLabels = (xLabel, yLabel, axesUnitsSt, curveIdx) => {
+ const {
+ xUnit,
+ yUnit
+ } = getAxesSelection(axesUnitsSt, curveIdx);
+ return {
+ xLabel: xUnit === '' ? xLabel : xUnit,
+ yLabel: yUnit === '' ? yLabel : yUnit
+ };
+};
+const getBaseCurrentUnit = label => /mA/i.test(String(label)) ? 'mA' : 'A';
+const buildCvAxisYLabel = (yLabel, cyclicvoltaSt) => {
+ const baseUnit = getBaseCurrentUnit(yLabel);
+ const areaUnit = cyclicvoltaSt?.areaUnit || 'cm²';
+ if (cyclicvoltaSt?.useCurrentDensity) {
+ return `Current density in ${baseUnit}/${areaUnit}`;
+ }
+ return `Current in ${baseUnit}`;
+};
+const computeCvYScaleFactor = (feature, cyclicvoltaSt) => {
+ if (!cyclicvoltaSt?.useCurrentDensity) return 1.0;
+ const rawArea = (cyclicvoltaSt.areaValue === '' ? 1.0 : cyclicvoltaSt.areaValue) || 1.0;
+ const areaUnit = cyclicvoltaSt.areaUnit || 'cm²';
+ const safeArea = rawArea > 0 ? rawArea : 1.0;
+ const areaInCm2 = areaUnit === 'mm²' ? safeArea / 100.0 : safeArea;
+ let factor = 1.0 / areaInCm2;
+ const baseY = feature && feature.yUnit ? String(feature.yUnit) : 'A';
+ if (/mA/i.test(baseY)) {
+ factor *= 1000.0;
+ }
+ if (areaUnit === 'mm²') {
+ factor /= 100.0;
+ }
+ return factor;
+};
+const defaultThreshold = {
+ isEdit: true,
+ value: false,
+ upper: false,
+ lower: false
+};
+const pickFromList = (list, index, fallback = null) => Array.isArray(list) && list[index] !== undefined ? list[index] : fallback;
+const hasBoolean = value => typeof value === 'boolean';
+const resolveOptionalBooleanFlags = analysis => {
+ const flags = {};
+ if (hasBoolean(analysis?.keepPred)) flags.keepPred = analysis.keepPred;
+ if (hasBoolean(analysis?.simulatenmr)) flags.simulatenmr = analysis.simulatenmr;
+ return flags;
+};
+const buildSpectrumPayload = ({
+ feature,
+ curveIdx,
+ editPeakSt,
+ thresList,
+ shiftSt,
+ layoutSt,
+ scanSt,
+ integrationSt,
+ multiplicitySt,
+ waveLengthSt,
+ cyclicvoltaSt,
+ axesUnitsSt,
+ detectorSt,
+ dscMetaData,
+ isAscend,
+ isIntensity,
+ analysis,
+ decimalSt
+}) => {
+ const threshold = thresList?.[curveIdx] || thresList?.[0] || defaultThreshold;
+ const editPeakAtIndex = Object.assign({}, editPeakSt, {
+ selectedIdx: curveIdx
+ });
+ const peaksEdit = (0, _extractPeaksEdit.extractPeaksEdit)(feature, editPeakAtIndex, threshold, shiftSt, layoutSt, curveIdx);
+ const scan = (0, _chem.Convert2Scan)(feature, scanSt);
+ const thres = (0, _chem.Convert2Thres)(feature, threshold);
+ const shift = pickFromList(shiftSt?.shifts, curveIdx, shiftSt);
+ const integration = pickFromList(integrationSt?.integrations, curveIdx, integrationSt);
+ const multiplicity = pickFromList(multiplicitySt?.multiplicities, curveIdx, multiplicitySt);
+ const {
+ xLabel,
+ yLabel
+ } = resolveAxisLabels(feature?.xUnit, feature?.yUnit, axesUnitsSt, curveIdx);
+ const axisYLabel = _format.default.isCyclicVoltaLayout(layoutSt) ? buildCvAxisYLabel(yLabel, cyclicvoltaSt) : yLabel;
+ const axisDisplay = {
+ xLabel,
+ yLabel: axisYLabel
+ };
+ const cvDisplay = _format.default.isCyclicVoltaLayout(layoutSt) ? {
+ mode: cyclicvoltaSt?.useCurrentDensity ? 'density' : 'current',
+ yScaleFactor: computeCvYScaleFactor(feature, cyclicvoltaSt)
+ } : null;
+ const cyclicvoltaPayload = {
+ ...cyclicvoltaSt,
+ axisDisplay,
+ cvDisplay
+ };
+ const optionalBooleanFlags = resolveOptionalBooleanFlags(analysis);
+ return {
+ peaks: peaksEdit,
+ layout: layoutSt,
+ shift,
+ scan,
+ thres,
+ isAscend,
+ isIntensity,
+ analysis,
+ decimal: decimalSt,
+ integration,
+ multiplicity,
+ waveLength: waveLengthSt,
+ cyclicvoltaSt: cyclicvoltaPayload,
+ curveSt: {
+ curveIdx
+ },
+ axesUnitsSt,
+ detectorSt,
+ dscMetaData,
+ ...optionalBooleanFlags
+ };
+};
+const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, analysis, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaSt, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature) => () => {
+ const defaultCurves = feature ? [{
+ feature
+ }] : [];
+ const curves = Array.isArray(curveList) && curveList.length > 0 ? curveList : defaultCurves;
+ const fallbackIdx = Number.isFinite(curveSt?.curveIdx) ? curveSt.curveIdx : 0;
+ const indicesToSend = curves.length > 0 ? curves.map((_, index) => index) : [fallbackIdx];
+ const spectraList = indicesToSend.map(curveIdx => {
+ const curve = curves[curveIdx] || {};
+ const curveFeature = curve.feature || feature;
+ return buildSpectrumPayload({
+ feature: curveFeature,
+ curveIdx,
+ editPeakSt,
+ thresList,
+ shiftSt,
+ layoutSt,
+ scanSt,
+ integrationSt,
+ multiplicitySt,
+ waveLengthSt,
+ cyclicvoltaSt,
+ axesUnitsSt,
+ detectorSt,
+ dscMetaData,
+ isAscend,
+ isIntensity,
+ analysis,
+ decimalSt
+ });
+ });
+ const payload = {
+ spectra_list: spectraList
+ };
+ if (Number.isFinite(curveSt?.curveIdx)) {
+ payload.curveSt = {
+ curveIdx: curveSt.curveIdx
+ };
+ }
+ operationValue(payload);
+};
+const BtnSubmit = ({
+ classes,
+ operation,
+ feature,
+ isAscend,
+ isIntensity,
+ editPeakSt,
+ thresList,
+ layoutSt,
+ shiftSt,
+ scanSt,
+ forecastSt,
+ decimalSt,
+ integrationSt,
+ multiplicitySt,
+ waveLengthSt,
+ cyclicvoltaSt,
+ curveSt,
+ curveList,
+ axesUnitsSt,
+ detectorSt,
+ metaSt
+}) => {
+ // const disBtn = peaksEdit.length === 0 || statusSt.btnSubmit || disabled;
+ const {
+ dscMetaData
+ } = metaSt;
+ const isCvLayout = _format.default.isCyclicVoltaLayout(layoutSt);
+ const {
+ xLabel,
+ yLabel
+ } = resolveAxisLabels(feature?.xUnit, feature?.yUnit, axesUnitsSt, curveSt?.curveIdx);
+ const axisYLabel = isCvLayout ? buildCvAxisYLabel(yLabel, cyclicvoltaSt) : yLabel;
+ const axisDisplay = {
+ xLabel,
+ yLabel: axisYLabel
+ };
+ const cvDisplay = isCvLayout ? {
+ mode: cyclicvoltaSt?.useCurrentDensity ? 'density' : 'current',
+ yScaleFactor: computeCvYScaleFactor(feature, cyclicvoltaSt)
+ } : null;
+ const cyclicvoltaPayload = {
+ ...cyclicvoltaSt,
+ axisDisplay,
+ cvDisplay
+ };
+ if (!operation) return null;
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Submit"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-submit'),
+ color: "primary",
+ onClick: onClickCb(operation.value, isAscend, isIntensity, layoutSt, shiftSt, forecastSt.predictions, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaPayload, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_PlayCircleOutline.default, {
+ className: classes.icon
+ })
+ })
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ editPeakSt: state.editPeak.present,
+ thresList: state.threshold.list,
+ layoutSt: state.layout,
+ shiftSt: state.shift,
+ scanSt: state.scan,
+ forecastSt: state.forecast,
+ decimalSt: state.submit.decimal,
+ integrationSt: state.integration.present,
+ multiplicitySt: state.multiplicity.present,
+ waveLengthSt: state.wavelength,
+ cyclicvoltaSt: state.cyclicvolta,
+ curveSt: state.curve,
+ curveList: state.curve.listCurves,
+ axesUnitsSt: state.axesUnits,
+ detectorSt: state.detector,
+ metaSt: state.meta
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+BtnSubmit.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ isAscend: _propTypes.default.bool.isRequired,
+ isIntensity: _propTypes.default.bool.isRequired,
+ operation: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.bool]).isRequired,
+ editPeakSt: _propTypes.default.object.isRequired,
+ thresList: _propTypes.default.array.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ shiftSt: _propTypes.default.object.isRequired,
+ scanSt: _propTypes.default.object.isRequired,
+ forecastSt: _propTypes.default.object.isRequired,
+ decimalSt: _propTypes.default.number.isRequired,
+ integrationSt: _propTypes.default.object.isRequired,
+ multiplicitySt: _propTypes.default.object.isRequired,
+ waveLengthSt: _propTypes.default.object.isRequired,
+ cyclicvoltaSt: _propTypes.default.object.isRequired,
+ curveSt: _propTypes.default.object,
+ curveList: _propTypes.default.array.isRequired,
+ axesUnitsSt: _propTypes.default.object.isRequired,
+ detectorSt: _propTypes.default.object.isRequired,
+ metaSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(styles))(BtnSubmit);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r06_predict_btn.js b/dist/components/cmd_bar/r06_predict_btn.js
new file mode 100644
index 00000000..0a6b1163
--- /dev/null
+++ b/dist/components/cmd_bar/r06_predict_btn.js
@@ -0,0 +1,234 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _GpsFixedOutlined = _interopRequireDefault(require("@mui/icons-material/GpsFixedOutlined"));
+var _HelpOutlineOutlined = _interopRequireDefault(require("@mui/icons-material/HelpOutlineOutlined"));
+var _styles = require("@mui/styles");
+var _common = require("./common");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _carbonFeatures = require("../../helpers/carbonFeatures");
+var _extractPeaksEdit = require("../../helpers/extractPeaksEdit");
+var _ui = require("../../actions/ui");
+var _list_ui = require("../../constants/list_ui");
+var _chem = require("../../helpers/chem");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, function-paren-newline,
+max-len, react/function-component-definition,
+function-call-argument-newline, react/require-default-props */
+
+const styles = () => Object.assign({}, _common.commonStyle, {
+ tTxt: {
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica',
+ marginRight: 5
+ },
+ btnWidthUnknown: {
+ minWidth: 30,
+ width: 30
+ },
+ btnWidthIr: {
+ minWidth: 30,
+ width: 30
+ },
+ btnWidthNmr: {
+ minWidth: 80,
+ width: 80
+ }
+});
+const MuPredictButton = (0, _styles.withStyles)({
+ root: {
+ border: '1px solid #ccc',
+ borderRadius: 4,
+ fontFamily: 'Helvetica',
+ fontSize: 20,
+ height: 30,
+ lineHeight: '20px',
+ padding: 0
+ }
+})(_material.Button);
+const onClickFail = (layoutSt, simuCount, realCount) => {
+ const feature = _format.default.is13CLayout(layoutSt) ? 'peak' : 'multiplet';
+ return () => alert(`Selected ${feature} count (${realCount}) must be larger than 0, and must be eqal or less than simulated count (${simuCount}).`); // eslint-disable-line
+};
+const onClickReady = (forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analysis, integrationSt, multiplicitySt, setUiViewerTypeAct, curveSt) => {
+ const {
+ btnCb
+ } = forecast;
+ if (!btnCb) {
+ return () => alert('[Developer Warning] You need to implement btnCb in forecast!'); // eslint-disable-line
+ }
+ return () => {
+ setUiViewerTypeAct(_list_ui.LIST_UI_VIEWER_TYPE.ANALYSIS);
+ return btnCb({
+ peaks: peaksEdit,
+ layout: layoutSt,
+ scan,
+ thres,
+ analysis,
+ integration: integrationSt,
+ multiplicity: multiplicitySt,
+ shift: shiftSt,
+ curveSt
+ });
+ };
+};
+const onClicUnknown = (feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analysis, integrationSt, multiplicitySt, curveSt) => {
+ const {
+ refreshCb
+ } = forecast;
+ if (!refreshCb) {
+ return () => alert('[Developer Warning] You need to implement refreshCb in forecast!'); // eslint-disable-line
+ }
+ return () => refreshCb({
+ peaks: peaksEdit,
+ layout: layoutSt,
+ scan,
+ shift: shiftSt,
+ thres,
+ analysis,
+ integration: integrationSt,
+ multiplicity: multiplicitySt,
+ curveSt
+ });
+};
+const counterText = (classes, isIr, realCount, uniqCount, simuCount) => isIr ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: `${realCount}/${uniqCount}/${simuCount}`
+});
+const renderBtnPredict = (classes, isIr, realCount, uniqCount, simuCount, color, btnWidthCls, onClick) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Predict"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "- Selected features must be eqal or less than simulated features."
+ })]
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(MuPredictButton, {
+ className: (0, _classnames.default)('btn-sv-bar-submit', btnWidthCls),
+ style: {
+ color
+ },
+ onClick: onClick,
+ children: [counterText(classes, isIr, realCount, uniqCount, simuCount), /*#__PURE__*/(0, _jsxRuntime.jsx)(_GpsFixedOutlined.default, {
+ className: classes.icon
+ })]
+ })
+});
+const renderBtnUnknown = (classes, onClick) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Refresh Simulation"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "- Simulation must be refreshed before making a prediction."
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "- If you continue to see this button after clicking it, the server is not ready. Please wait for a while."
+ })]
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(MuPredictButton, {
+ className: (0, _classnames.default)('btn-sv-bar-submit', classes.btnWidthUnknown),
+ style: {
+ color: 'orange'
+ },
+ onClick: onClick,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_HelpOutlineOutlined.default, {
+ className: classes.icon
+ })
+ })
+});
+const BtnPredict = ({
+ classes,
+ feature,
+ forecast,
+ layoutSt,
+ simulationSt,
+ editPeakSt,
+ scanSt,
+ shiftSt,
+ thresSt,
+ integrationSt,
+ multiplicitySt,
+ setUiViewerTypeAct,
+ curveSt
+}) => {
+ const is13Cor1H = _format.default.is13CLayout(layoutSt) || _format.default.is1HLayout(layoutSt);
+ const isIr = _format.default.isIrLayout(layoutSt);
+ if (!(is13Cor1H || isIr)) return null;
+ const oriPeaksEdit = (0, _extractPeaksEdit.extractPeaksEdit)(feature, editPeakSt, thresSt, shiftSt, layoutSt);
+ const peaksEdit = _format.default.rmShiftFromPeaks(oriPeaksEdit, shiftSt);
+ const scan = (0, _chem.Convert2Scan)(feature, scanSt);
+ const thres = (0, _chem.Convert2Thres)(feature, thresSt);
+ const simuCount = simulationSt.nmrSimPeaks.length;
+ const uniqCount = [...new Set(simulationSt.nmrSimPeaks)].length;
+ let realCount = 0;
+ if (_format.default.is13CLayout(layoutSt)) {
+ realCount = (0, _carbonFeatures.carbonFeatures)(peaksEdit, multiplicitySt).length;
+ } else {
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = multiplicitySt;
+ const selectedMultiplicity = multiplicities[curveIdx];
+ const {
+ stack
+ } = selectedMultiplicity;
+ realCount = stack.length;
+ }
+ if (is13Cor1H && simuCount === 0) {
+ const onClickUnknownCb = onClicUnknown(feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, forecast.predictions, integrationSt, multiplicitySt, curveSt);
+ return renderBtnUnknown(classes, onClickUnknownCb);
+ }
+ const predictable = isIr || simuCount >= realCount && realCount > 0;
+ const color = predictable ? 'green' : 'red';
+ const onClick = predictable ? onClickReady(forecast, peaksEdit, layoutSt, scan, shiftSt, thres, forecast.predictions, integrationSt, multiplicitySt, setUiViewerTypeAct, curveSt) : onClickFail(layoutSt, simuCount, realCount);
+ const btnWidthCls = isIr ? classes.btnWidthIr : classes.btnWidthNmr;
+ return renderBtnPredict(classes, isIr, realCount, uniqCount, simuCount, color, btnWidthCls, onClick);
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ simulationSt: state.simulation,
+ editPeakSt: state.editPeak.present,
+ scanSt: state.scan,
+ shiftSt: state.shift,
+ thresSt: state.threshold.list[state.curve.curveIdx],
+ integrationSt: state.integration.present,
+ multiplicitySt: state.multiplicity.present,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setUiViewerTypeAct: _ui.setUiViewerType
+}, dispatch);
+BtnPredict.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ forecast: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ simulationSt: _propTypes.default.array.isRequired,
+ editPeakSt: _propTypes.default.object.isRequired,
+ scanSt: _propTypes.default.object.isRequired,
+ shiftSt: _propTypes.default.object.isRequired,
+ thresSt: _propTypes.default.object.isRequired,
+ integrationSt: _propTypes.default.object.isRequired,
+ multiplicitySt: _propTypes.default.object.isRequired,
+ setUiViewerTypeAct: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(styles))(BtnPredict);
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r07_wavelength_btn.js b/dist/components/cmd_bar/r07_wavelength_btn.js
new file mode 100644
index 00000000..326026e6
--- /dev/null
+++ b/dist/components/cmd_bar/r07_wavelength_btn.js
@@ -0,0 +1,86 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _wavelength = require("../../actions/wavelength");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _common = require("./common");
+var _list_wavelength = require("../../constants/list_wavelength");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, react/jsx-one-expression-per-line,
+react/function-component-definition */
+
+const styles = () => Object.assign({
+ fieldShift: {
+ width: 160
+ },
+ fieldLayout: {
+ width: 100
+ }
+}, _common.commonStyle);
+const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWaveLengthAct) => {
+ if (!_format.default.isXRDLayout(layoutSt)) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {});
+ }
+ const onChange = e => updateWaveLengthAct(e.target.value);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldLayout),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-wavelength-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Wavelength"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ labelId: "select-wavelength-label",
+ label: "Wavelength",
+ value: waveLengthSt,
+ onChange: onChange,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-layout'),
+ children: _list_wavelength.LIST_WAVE_LENGTH.map(item => {
+ // eslint-disable-line
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: item,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: [item.label, " (", item.value, " ", item.unit, ")"]
+ })
+ });
+ })
+ })]
+ });
+};
+const Wavelength = ({
+ classes,
+ waveLengthSt,
+ layoutSt,
+ updateWaveLengthAct
+}) => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: classes.groupRight,
+ children: wavelengthSelect(classes, waveLengthSt, layoutSt, updateWaveLengthAct)
+});
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ waveLengthSt: state.wavelength,
+ layoutSt: state.layout
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ updateWaveLengthAct: _wavelength.updateWaveLength
+}, dispatch);
+Wavelength.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ waveLengthSt: _propTypes.default.object.isRequired,
+ updateWaveLengthAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(Wavelength));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r08_change_axes.js b/dist/components/cmd_bar/r08_change_axes.js
new file mode 100644
index 00000000..b8d3ee75
--- /dev/null
+++ b/dist/components/cmd_bar/r08_change_axes.js
@@ -0,0 +1,189 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireWildcard(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _common = require("./common");
+var _list_layout = require("../../constants/list_layout");
+var _list_axes = require("../../constants/list_axes");
+var _axes = require("../../actions/axes");
+var _jsxRuntime = require("react/jsx-runtime");
+function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
+/* eslint-disable prefer-object-spread, react/jsx-one-expression-per-line,
+react/function-component-definition,
+max-len, no-unused-vars, no-multiple-empty-lines */
+
+const listLayoutToShow = [_list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY];
+const styles = () => Object.assign({
+ fieldShift: {
+ width: 160
+ },
+ fieldLayout: {
+ width: 100
+ }
+}, _common.commonStyle);
+const axisX = (classes, layoutSt, axesUnitsSt, updateXAxisAct, curveSt) => {
+ const optionsAxisX = _list_axes.LIST_AXES.x;
+ const options = optionsAxisX[layoutSt];
+ const {
+ curveIdx
+ } = curveSt;
+ const onChange = e => updateXAxisAct({
+ value: e.target.value,
+ curveIndex: curveIdx
+ });
+ const {
+ axes
+ } = axesUnitsSt;
+ let selectedAxes = axes[curveIdx];
+ if (!selectedAxes) {
+ selectedAxes = {
+ xUnit: '',
+ yUnit: ''
+ };
+ }
+ const {
+ xUnit
+ } = selectedAxes;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldLayout),
+ variant: "outlined",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ labelId: "select-x-axis-label",
+ label: "x-Axis",
+ value: xUnit,
+ onChange: onChange,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-layout'),
+ children: options.map(item => {
+ // eslint-disable-line
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: item,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: item === '' ? 'Default' : item
+ })
+ }, item);
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-x-axis-label",
+ className: (0, _classnames.default)(classes.txtLabelTopInput),
+ children: "x-Axis"
+ })]
+ });
+};
+const axisY = (classes, layoutSt, axesUnitsSt, updateYAxisAct, curveSt) => {
+ const optionsAxisX = _list_axes.LIST_AXES.y;
+ const options = optionsAxisX[layoutSt];
+ const {
+ curveIdx
+ } = curveSt;
+ const onChange = e => updateYAxisAct({
+ value: e.target.value,
+ curveIndex: curveIdx
+ });
+ const {
+ axes
+ } = axesUnitsSt;
+ let selectedAxes = axes[curveIdx];
+ if (!selectedAxes) {
+ selectedAxes = {
+ xUnit: '',
+ yUnit: ''
+ };
+ }
+ const yUnit = '';
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldLayout),
+ variant: "outlined",
+ disabled: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ labelId: "select-y-axis-label",
+ label: "y-Axis",
+ value: yUnit,
+ onChange: onChange,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-layout'),
+ disabled: true,
+ children: options.map(item => {
+ // eslint-disable-line
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: item,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: item === '' ? 'Default' : item
+ })
+ }, item);
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-y-axis-label",
+ className: (0, _classnames.default)(classes.txtLabelTopInput),
+ children: "y-Axis"
+ })]
+ });
+};
+const showSelect = (classes, layoutSt, curveSt, axesUnitsSt, updateXAxisAct, updateYAxisAct) => {
+ if (!listLayoutToShow.includes(layoutSt)) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {});
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ children: [axisX(classes, layoutSt, axesUnitsSt, updateXAxisAct, curveSt), axisY(classes, layoutSt, axesUnitsSt, updateYAxisAct, curveSt)]
+ });
+};
+const ChangeAxes = ({
+ classes,
+ layoutSt,
+ curveSt,
+ axesUnitsSt,
+ updateXAxisAct,
+ updateYAxisAct
+}) => {
+ const {
+ curveIdx
+ } = curveSt;
+ const axes = axesUnitsSt?.axes || [];
+ (0, _react.useEffect)(() => {
+ if (layoutSt !== _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) return;
+ const selectedAxes = axes[curveIdx] || {
+ yUnit: ''
+ };
+ if (selectedAxes.yUnit !== '') {
+ updateYAxisAct({
+ value: '',
+ curveIndex: curveIdx
+ });
+ }
+ }, [layoutSt, axes, curveIdx, updateYAxisAct]);
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: classes.groupRight,
+ "data-testid": "ChangeAxes",
+ children: showSelect(classes, layoutSt, curveSt, axesUnitsSt, updateXAxisAct, updateYAxisAct)
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ curveSt: state.curve,
+ axesUnitsSt: state.axesUnits
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ updateXAxisAct: _axes.updateXAxis,
+ updateYAxisAct: _axes.updateYAxis
+}, dispatch);
+ChangeAxes.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ axesUnitsSt: _propTypes.default.object.isRequired,
+ updateXAxisAct: _propTypes.default.func.isRequired,
+ updateYAxisAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(ChangeAxes));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r09_detector.js b/dist/components/cmd_bar/r09_detector.js
new file mode 100644
index 00000000..3efdcf7c
--- /dev/null
+++ b/dist/components/cmd_bar/r09_detector.js
@@ -0,0 +1,104 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _detector = require("../../actions/detector");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _common = require("./common");
+var _list_detectors = require("../../constants/list_detectors");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, react/jsx-one-expression-per-line,
+react/function-component-definition */
+
+const styles = () => Object.assign({
+ fieldShift: {
+ width: 160
+ },
+ fieldLayout: {
+ width: 100
+ }
+}, _common.commonStyle);
+const detectorSelect = (classes, detectorSt, curveSt, layoutSt, updateDetectorAct) => {
+ if (!_format.default.isSECLayout(layoutSt)) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {});
+ }
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ curves
+ } = detectorSt;
+ const getSelectedDetectorForCurve = (_detectorSt, targetCurveIdx) => {
+ const targetCurve = curves.find(curve => curve.curveIdx === targetCurveIdx);
+ return targetCurve ? targetCurve.selectedDetector : '';
+ };
+ const selectedDetector = getSelectedDetectorForCurve(detectorSt, curveIdx);
+ const onChange = e => updateDetectorAct({
+ curveIdx,
+ selectedDetector: e.target.value
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldLayout),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "select-detector-label",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Detector"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, {
+ labelId: "select-detector-label",
+ label: "Detector",
+ value: selectedDetector,
+ onChange: onChange,
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: "",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout')
+ })
+ }), _list_detectors.LIST_DETECTORS.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: item,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: item.name
+ })
+ }))]
+ })]
+ });
+};
+const Detector = ({
+ classes,
+ detectorSt,
+ curveSt,
+ layoutSt,
+ updateDetectorAct
+}) => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: classes.groupRight,
+ children: detectorSelect(classes, detectorSt, curveSt, layoutSt, updateDetectorAct)
+});
+const mapStateToProps = (state, _props) => (
+// eslint-disable-line
+{
+ detectorSt: state.detector,
+ curveSt: state.curve,
+ layoutSt: state.layout
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ updateDetectorAct: _detector.updateDetector
+}, dispatch);
+Detector.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ updateDetectorAct: _propTypes.default.func.isRequired,
+ detectorSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(Detector));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/r10_cv_density.js b/dist/components/cmd_bar/r10_cv_density.js
new file mode 100644
index 00000000..4f850b0b
--- /dev/null
+++ b/dist/components/cmd_bar/r10_cv_density.js
@@ -0,0 +1,180 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _list_layout = require("../../constants/list_layout");
+var _common = require("./common");
+var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/function-component-definition, react/jsx-one-expression-per-line,
+react/jsx-boolean-value */
+
+const styles = () => ({
+ ..._common.commonStyle,
+ fieldArea: {
+ width: 100
+ },
+ fieldUnit: {
+ width: 75
+ },
+ toggleGroup: {
+ height: 30,
+ marginLeft: 8
+ },
+ toggleBtn: {
+ fontSize: 10,
+ padding: '0 6px',
+ height: 30,
+ minHeight: 30,
+ lineHeight: '30px',
+ textTransform: 'none'
+ }
+});
+const units = ['cm²', 'mm²'];
+const CvDensityControls = ({
+ classes,
+ layoutSt,
+ areaValue,
+ areaUnit,
+ useCurrentDensity,
+ setAreaValueAct,
+ setAreaUnitAct,
+ toggleDensityAct
+}) => {
+ if (layoutSt !== _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {});
+ const handleAreaChange = e => {
+ const raw = e.target.value;
+ if (raw === '') {
+ setAreaValueAct('');
+ return;
+ }
+ const val = parseFloat(raw);
+ if (Number.isNaN(val)) return;
+ if (val < 0) return;
+ setAreaValueAct(val);
+ };
+ const handleAreaBlur = e => {
+ const raw = e.target.value;
+ const val = parseFloat(raw);
+ if (raw === '' || Number.isNaN(val) || val <= 0) {
+ setAreaValueAct(1.0);
+ }
+ };
+ const handleUnitChange = e => {
+ const newUnit = e.target.value;
+ const currVal = areaValue;
+ if (currVal !== '' && Number.isFinite(Number(currVal))) {
+ const num = Number(currVal);
+ const from = areaUnit;
+ const to = newUnit;
+ let converted = num;
+ if (from === 'cm²' && to === 'mm²') converted = num * 100.0;
+ if (from === 'mm²' && to === 'cm²') converted = num / 100.0;
+ setAreaValueAct(converted);
+ }
+ setAreaUnitAct(newUnit);
+ };
+ const handleToggle = (_, val) => {
+ if (val === null) return;
+ const shouldBeDensity = val === 'density';
+ if (shouldBeDensity !== useCurrentDensity) {
+ toggleDensityAct();
+ }
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.group,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldArea),
+ variant: "outlined",
+ disabled: !useCurrentDensity,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ htmlFor: "cv-area",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "WE-ECSA"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.OutlinedInput, {
+ id: "cv-area",
+ label: "WE-ECSA",
+ type: "number",
+ inputProps: {
+ step: '0.0001',
+ min: '0'
+ },
+ value: areaValue,
+ onChange: handleAreaChange,
+ onBlur: handleAreaBlur,
+ className: (0, _classnames.default)(classes.txtInput, 'input-sv-bar-layout'),
+ disabled: !useCurrentDensity
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.fieldUnit),
+ variant: "outlined",
+ disabled: !useCurrentDensity,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, {
+ id: "cv-area-unit",
+ className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'),
+ children: "Unit"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Select, {
+ value: areaUnit,
+ onChange: handleUnitChange,
+ labelId: "cv-area-unit",
+ label: "Unit",
+ className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-layout'),
+ disabled: !useCurrentDensity,
+ children: units.map(u => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: u,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'),
+ children: u
+ })
+ }, u))
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.ToggleButtonGroup, {
+ exclusive: true,
+ size: "small",
+ value: useCurrentDensity ? 'density' : 'current',
+ onChange: handleToggle,
+ className: (0, _classnames.default)(classes.selectInput, classes.toggleGroup, 'input-sv-bar-layout'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.ToggleButton, {
+ value: "current",
+ className: (0, _classnames.default)(classes.txtOpt, classes.toggleBtn),
+ children: "Current"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.ToggleButton, {
+ value: "density",
+ className: (0, _classnames.default)(classes.txtOpt, classes.toggleBtn),
+ children: "Current / Area"
+ })]
+ })]
+ });
+};
+CvDensityControls.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ areaValue: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
+ areaUnit: _propTypes.default.string.isRequired,
+ useCurrentDensity: _propTypes.default.bool.isRequired,
+ setAreaValueAct: _propTypes.default.func.isRequired,
+ setAreaUnitAct: _propTypes.default.func.isRequired,
+ toggleDensityAct: _propTypes.default.func.isRequired
+};
+const mapStateToProps = state => ({
+ layoutSt: state.layout,
+ areaValue: state.cyclicvolta.areaValue,
+ areaUnit: state.cyclicvolta.areaUnit,
+ useCurrentDensity: state.cyclicvolta.useCurrentDensity
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setAreaValueAct: _cyclic_voltammetry.setCyclicVoltaAreaValue,
+ setAreaUnitAct: _cyclic_voltammetry.setCyclicVoltaAreaUnit,
+ toggleDensityAct: _cyclic_voltammetry.toggleCyclicVoltaDensity
+}, dispatch);
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(CvDensityControls));
\ No newline at end of file
diff --git a/dist/components/cmd_bar/tri_btn.js b/dist/components/cmd_bar/tri_btn.js
new file mode 100644
index 00000000..64800f48
--- /dev/null
+++ b/dist/components/cmd_bar/tri_btn.js
@@ -0,0 +1,131 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _styles = require("@mui/styles");
+var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _common = require("./common");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread */
+
+const styles = () => Object.assign({
+ btnYes: {
+ color: 'green'
+ },
+ btnNo: {
+ color: 'red'
+ },
+ btnTxtConfirm: {
+ fontFamily: 'Helvetica',
+ fontSize: 12
+ }
+}, _common.commonStyle);
+class TriBtn extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ toggled: false
+ };
+ this.onToggle = this.onToggle.bind(this);
+ this.renderStageOne = this.renderStageOne.bind(this);
+ this.renderStageTwo = this.renderStageTwo.bind(this);
+ }
+ onToggle(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ const {
+ toggled
+ } = this.state;
+ this.setState({
+ toggled: !toggled
+ });
+ }
+ renderStageOne() {
+ const {
+ content,
+ layoutSt,
+ children,
+ isClearAllDisabled
+ } = this.props;
+ const {
+ tp
+ } = content;
+ const title = /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: tp
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
+ title: title,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-one'),
+ disabled: isClearAllDisabled === false ? false : _cfg.default.btnCmdMpy(layoutSt) && _cfg.default.btnCmdIntg(layoutSt),
+ onClick: this.onToggle,
+ children: children
+ })
+ })
+ });
+ }
+ renderStageTwo() {
+ const {
+ classes,
+ layoutSt,
+ cb
+ } = this.props;
+ const onExec = e => {
+ cb();
+ this.onToggle(e);
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ disabled: _cfg.default.btnCmdMpy(layoutSt) && _cfg.default.btnCmdIntg(layoutSt),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtLabel, 'txt-sv-bar-desc'),
+ children: "Delete ALL?"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-yes'),
+ onClick: onExec,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, classes.btnYes, 'txt-sv-bar-yes'),
+ children: "Y"
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, {
+ className: (0, _classnames.default)('btn-sv-bar-no'),
+ onClick: this.onToggle,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txt, classes.btnNo, 'txt-sv-bar-no'),
+ children: "N"
+ })
+ })]
+ });
+ }
+ render() {
+ const {
+ toggled
+ } = this.state;
+ return !toggled ? this.renderStageOne() : this.renderStageTwo();
+ }
+}
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+TriBtn.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ content: _propTypes.default.object.isRequired,
+ cb: _propTypes.default.func.isRequired,
+ children: _propTypes.default.node.isRequired,
+ isClearAllDisabled: _propTypes.default.bool.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(TriBtn));
\ No newline at end of file
diff --git a/dist/components/common/chem.js b/dist/components/common/chem.js
new file mode 100644
index 00000000..7a15e0be
--- /dev/null
+++ b/dist/components/common/chem.js
@@ -0,0 +1,115 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+/* eslint-disable */
+
+const SmaToSvg = sma => {
+ switch (sma) {
+ case 'C-,:O':
+ return '';
+ case 'C-,:C(=O)-,:O-,:C':
+ return '';
+ case 'C-,:O-,:c':
+ return '';
+ case 'c-,:[Cl]':
+ return '';
+ case 'c:,-[n&H1]:,-c':
+ return '';
+ case 'c-,:O':
+ return '';
+ case 'C-,:[Cl]':
+ return '';
+ case 'C-,:C(-,:C)=O':
+ return '';
+ case 'c-,:[N&+](=O)-,:[O&-]':
+ return '';
+ case 'C-,:C=C':
+ return '';
+ case 'c-,:[Br]':
+ return '';
+ case 'C-,:O-,:C':
+ return '';
+ case 'C-,:[Br]':
+ return '';
+ case 'C-,:C(-,:c)=O':
+ return '';
+ case 'c-,:N':
+ return '';
+ case 'C-,:F':
+ return '';
+ case 'c-,:C(=O)-,:O-,:C':
+ return '';
+ case 'c:,-o:,-c':
+ return '';
+ case 'C-,:C(=O)-,:O':
+ return '';
+ case 'c-,:F':
+ return '';
+ case 'c=O':
+ return '';
+ case 'C-,:N-,:C':
+ return '';
+ case 'C-,:N(-,:C)-,:C':
+ return '';
+ case 'C-,:N':
+ return '';
+ case 'C-,:n(-,:c):,-c':
+ return '';
+ case 'c-,:C(=O)-,:O':
+ return '';
+ case 'c-,:C=O':
+ return '';
+ case 'C-,:C#N':
+ return '';
+ case 'C-,:C=C-,:C':
+ return '';
+ case 'C-,:C(=O)-,:N-,:C':
+ return '';
+ case 'c-,:C#N':
+ return '';
+ case 'C-,:C(=O)-,:N-,:c':
+ return '';
+ case 'C-,:C(-,:C)=C':
+ return '';
+ case 'c:,-s:,-c':
+ return '';
+ case 'C-,:C#C-,:C':
+ return '';
+ case 'C#C-,:C':
+ return '';
+ case 'c-,:C(-,:c)=O':
+ return '';
+ case 'C-,:C(-,:C)=C-,:C':
+ return '';
+ case 'c-,:N(-,:C)-,:C':
+ return '';
+ case 'C-,:N-,:c':
+ return '';
+ case 'C-,:O-,:C(-,:C)=O':
+ return '';
+ case 'c-,:O-,:C':
+ return '';
+ case 'c:,-n:,-c':
+ return '';
+ case 'C=C-,:C':
+ return '';
+ case 'c-,:C(-,:C)=O':
+ return '';
+ case 'c:,-n(-,:c)-,:C':
+ return '';
+ case 'C-,:N-,:C(-,:C)=O':
+ return '';
+ case 'c-,:N-,:C(-,:C)=O':
+ return '';
+ case 'C=C(-,:C)-,:C':
+ return '';
+ default:
+ return '';
+ }
+};
+
+/* eslint-enable */
+var _default = exports.default = SmaToSvg;
\ No newline at end of file
diff --git a/dist/components/common/comps.js b/dist/components/common/comps.js
new file mode 100644
index 00000000..c366d9f5
--- /dev/null
+++ b/dist/components/common/comps.js
@@ -0,0 +1,15 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.TabLabel = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _jsxRuntime = require("react/jsx-runtime");
+const TabLabel = (classes, label, extClsName = 'txt-tab-label') => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tabLabel, extClsName),
+ children: label
+});
+exports.TabLabel = TabLabel;
\ No newline at end of file
diff --git a/dist/components/common/draw.js b/dist/components/common/draw.js
new file mode 100644
index 00000000..deba70ef
--- /dev/null
+++ b/dist/components/common/draw.js
@@ -0,0 +1,51 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.drawMain = exports.drawLabel = exports.drawDisplay = exports.drawDestroy = exports.drawArrowOnCurve = void 0;
+const d3 = require('d3');
+const drawMain = (klass, w, h) => {
+ d3.select(klass).append('svg').attr('class', 'd3Svg').attr('preserveAspectRatio', 'xMinYMin meet').attr('viewBox', `0 0 ${w} ${h}`);
+};
+exports.drawMain = drawMain;
+const drawLabel = (klass, cLabel, xLabel, yLabel) => {
+ d3.select(klass).selectAll('.xLabel').text(xLabel);
+ d3.select(klass).selectAll('.yLabel').text(yLabel);
+ if (cLabel) {
+ d3.select(klass).selectAll('.mark-text').text(cLabel);
+ }
+};
+exports.drawLabel = drawLabel;
+const drawDisplay = (klass, isHidden) => {
+ if (isHidden) {
+ d3.select(klass).selectAll('svg').style('width', 0);
+ } else {
+ d3.select(klass).selectAll('svg').style('width', '100%');
+ }
+};
+exports.drawDisplay = drawDisplay;
+const drawDestroy = klass => d3.select(`${klass} > *`).remove();
+exports.drawDestroy = drawDestroy;
+const drawArrowOnCurve = (klass, isHidden) => {
+ if (isHidden) {
+ d3.select(klass).selectAll('marker').remove();
+ } else {
+ d3.select(klass).selectAll('marker').remove();
+ const arrowLeft = d3.select(klass).selectAll('defs').append('marker').attr('id', 'arrow-left').attr('viewBox', '0 0 10 10').attr('refX', 5).attr('refY', 5).attr('markerWidth', 6).attr('markerHeight', 6).attr('orient', 'auto').attr('fill', '#00AA0099');
+ arrowLeft.append('path').attr('d', 'M 0 0 L 10 5 L 0 10 z');
+
+ // const arrowRight = d3.select(klass).selectAll('defs')
+ // .append('marker')
+ // .attr('id', 'arrow-right')
+ // .attr('viewBox', '0 0 10 10')
+ // .attr('refX', 5)
+ // .attr('refY', 5)
+ // .attr('markerWidth', 6)
+ // .attr('markerHeight', 6)
+ // .attr('orient', 'auto-start-reverse');
+ // arrowRight.append('path')
+ // .attr('d', 'M 0 0 L 10 5 L 0 10 z');
+ }
+};
+exports.drawArrowOnCurve = drawArrowOnCurve;
\ No newline at end of file
diff --git a/dist/components/d3_line/index.js b/dist/components/d3_line/index.js
new file mode 100644
index 00000000..a9827f20
--- /dev/null
+++ b/dist/components/d3_line/index.js
@@ -0,0 +1,243 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _chem = require("../../helpers/chem");
+var _manager = require("../../actions/manager");
+var _ui = require("../../actions/ui");
+var _integration = require("../../actions/integration");
+var _line_focus = _interopRequireDefault(require("./line_focus"));
+var _draw = require("../common/draw");
+var _list_ui = require("../../constants/list_ui");
+var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable no-mixed-operators */
+
+const W = Math.round(window.innerWidth * 0.90 * 9 / 12); // ROI
+const H = Math.round(window.innerHeight * 0.90 * 0.85); // ROI
+
+class ViewerLine extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ const {
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct
+ } = props;
+ this.rootKlass = '.d3Line';
+ this.focus = new _line_focus.default({
+ W,
+ H,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct
+ });
+ this.normChange = this.normChange.bind(this);
+ }
+ componentDidMount() {
+ const {
+ seed,
+ peak,
+ cLabel,
+ xLabel,
+ yLabel,
+ feature,
+ freq,
+ comparisons,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ integationSt,
+ mtplySt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ isHidden,
+ wavelength,
+ axesUnitsSt,
+ resetAllAct
+ } = this.props;
+ (0, _draw.drawDestroy)(this.rootKlass);
+ resetAllAct(feature);
+ let xxLabel = xLabel;
+ let yyLabel = yLabel;
+ if (axesUnitsSt) {
+ const {
+ axes
+ } = axesUnitsSt;
+ const {
+ xUnit,
+ yUnit
+ } = axes[0];
+ xxLabel = xUnit === '' ? xLabel : xUnit;
+ yyLabel = yUnit === '' ? yLabel : yUnit;
+ }
+ const filterSeed = seed;
+ const filterPeak = peak;
+ (0, _draw.drawMain)(this.rootKlass, W, H);
+ this.focus.create({
+ filterSeed,
+ filterPeak,
+ freq,
+ comparisons,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ integationSt,
+ mtplySt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ wavelength
+ });
+ (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel);
+ (0, _draw.drawDisplay)(this.rootKlass, isHidden);
+ }
+ componentDidUpdate(prevProps) {
+ const {
+ seed,
+ peak,
+ cLabel,
+ xLabel,
+ yLabel,
+ freq,
+ comparisons,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ integationSt,
+ mtplySt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ isHidden,
+ wavelength,
+ axesUnitsSt
+ } = this.props;
+ this.normChange(prevProps);
+ let xxLabel = xLabel;
+ let yyLabel = yLabel;
+ if (axesUnitsSt) {
+ const {
+ axes
+ } = axesUnitsSt;
+ const {
+ xUnit,
+ yUnit
+ } = axes[0];
+ xxLabel = xUnit === '' ? xLabel : xUnit;
+ yyLabel = yUnit === '' ? yLabel : yUnit;
+ }
+ const filterSeed = seed;
+ const filterPeak = peak;
+ this.focus.update({
+ filterSeed,
+ filterPeak,
+ freq,
+ comparisons,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ integationSt,
+ mtplySt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ wavelength
+ });
+ (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel);
+ (0, _draw.drawDisplay)(this.rootKlass, isHidden);
+ }
+ componentWillUnmount() {
+ (0, _draw.drawDestroy)(this.rootKlass);
+ }
+ normChange(prevProps) {
+ const {
+ feature,
+ resetAllAct
+ } = this.props;
+ const oldFeature = prevProps.feature;
+ if (oldFeature !== feature) {
+ resetAllAct(feature);
+ }
+ }
+ render() {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: "d3Line"
+ });
+ }
+}
+const mapStateToProps = (state, props) => ({
+ seed: (0, _chem.Topic2Seed)(state, props),
+ peak: (0, _chem.Feature2Peak)(state, props),
+ freq: (0, _chem.ToFrequency)(state, props),
+ comparisons: (0, _chem.GetComparisons)(state, props),
+ tTrEndPts: (0, _chem.ToThresEndPts)(state, props),
+ tSfPeaks: (0, _chem.ToShiftPeaks)(state, props),
+ editPeakSt: state.editPeak.present,
+ layoutSt: state.layout,
+ integationSt: state.integration.present,
+ mtplySt: state.multiplicity.present,
+ sweepExtentSt: state.ui.sweepExtent,
+ isUiAddIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ isUiSplitIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT,
+ isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0,
+ wavelength: state.wavelength,
+ axesUnitsSt: state.axesUnits
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ resetAllAct: _manager.resetAll,
+ clickUiTargetAct: _ui.clickUiTarget,
+ selectUiSweepAct: _ui.selectUiSweep,
+ scrollUiWheelAct: _ui.scrollUiWheel,
+ splitIntegrationAct: _integration.splitIntegration,
+ addNewCylicVoltaPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak,
+ addCylicVoltaMaxPeakAct: _cyclic_voltammetry.addCylicVoltaMaxPeak,
+ addCylicVoltaMinPeakAct: _cyclic_voltammetry.addCylicVoltaMinPeak
+}, dispatch);
+ViewerLine.propTypes = {
+ seed: _propTypes.default.array.isRequired,
+ peak: _propTypes.default.array.isRequired,
+ freq: _propTypes.default.oneOfType([_propTypes.default.bool, _propTypes.default.number]).isRequired,
+ comparisons: _propTypes.default.array.isRequired,
+ cLabel: _propTypes.default.string.isRequired,
+ xLabel: _propTypes.default.string.isRequired,
+ yLabel: _propTypes.default.string.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ tTrEndPts: _propTypes.default.array.isRequired,
+ tSfPeaks: _propTypes.default.array.isRequired,
+ editPeakSt: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ integationSt: _propTypes.default.object.isRequired,
+ mtplySt: _propTypes.default.object.isRequired,
+ sweepExtentSt: _propTypes.default.object.isRequired,
+ isUiAddIntgSt: _propTypes.default.bool.isRequired,
+ isUiSplitIntgSt: _propTypes.default.bool.isRequired,
+ isUiNoBrushSt: _propTypes.default.bool.isRequired,
+ resetAllAct: _propTypes.default.func.isRequired,
+ clickUiTargetAct: _propTypes.default.func.isRequired,
+ selectUiSweepAct: _propTypes.default.func.isRequired,
+ scrollUiWheelAct: _propTypes.default.func.isRequired,
+ splitIntegrationAct: _propTypes.default.func.isRequired,
+ isHidden: _propTypes.default.bool.isRequired,
+ wavelength: _propTypes.default.object.isRequired,
+ axesUnitsSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)(ViewerLine);
\ No newline at end of file
diff --git a/dist/components/d3_line/line_focus.js b/dist/components/d3_line/line_focus.js
new file mode 100644
index 00000000..291dc803
--- /dev/null
+++ b/dist/components/d3_line/line_focus.js
@@ -0,0 +1,725 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _init = require("../../helpers/init");
+var _mount = require("../../helpers/mount");
+var _brush = _interopRequireDefault(require("../../helpers/brush"));
+var _compass = require("../../helpers/compass");
+var _integration_split = require("../../helpers/integration_split");
+var _converter = require("../../helpers/converter");
+var _focus = require("../../helpers/focus");
+var _integration = require("../../helpers/integration");
+var _multiplicity_calc = require("../../helpers/multiplicity_calc");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _list_layout = require("../../constants/list_layout");
+/* eslint-disable prefer-object-spread, no-mixed-operators */
+
+const d3 = require('d3');
+class LineFocus {
+ constructor(props) {
+ const {
+ W,
+ H,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct
+ } = props;
+ this.jcampIdx = 0;
+ this.rootKlass = '.d3Line';
+ this.margin = {
+ t: 5,
+ b: 40,
+ l: 60,
+ r: 5
+ };
+ this.w = W - this.margin.l - this.margin.r;
+ this.h = H - this.margin.t - this.margin.b;
+ this.clickUiTargetAct = clickUiTargetAct;
+ this.selectUiSweepAct = selectUiSweepAct;
+ this.scrollUiWheelAct = scrollUiWheelAct;
+ this.splitIntegrationAct = splitIntegrationAct;
+ this.brush = d3.brush();
+ this.brushX = d3.brushX();
+ this.axis = null;
+ this.path = null;
+ this.thresLineUp = null;
+ this.thresLineDw = null;
+ this.grid = null;
+ this.tags = null;
+ this.ref = null;
+ this.ccPattern = null;
+ this.data = [];
+ this.dataPks = [];
+ this.tTrEndPts = null;
+ this.tSfPeaks = null;
+ this.root = null;
+ this.svg = null;
+ this.axisCall = (0, _init.InitAxisCall)(5);
+ this.pathCall = null;
+ this.tip = null;
+ this.factor = 0.125;
+ this.currentExtent = null;
+ this.shouldUpdate = {};
+ this.freq = false;
+ this.layout = _list_layout.LIST_LAYOUT.H1;
+ this.isUiAddIntgSt = false;
+ this.isUiSplitIntgSt = false;
+ this.integrationSplitTargets = null;
+ this.firstIntegrationPoint = null;
+ this.getShouldUpdate = this.getShouldUpdate.bind(this);
+ this.resetShouldUpdate = this.resetShouldUpdate.bind(this);
+ this.setTip = this.setTip.bind(this);
+ this.setDataParams = this.setDataParams.bind(this);
+ this.create = this.create.bind(this);
+ this.update = this.update.bind(this);
+ this.setConfig = this.setConfig.bind(this);
+ this.drawLine = this.drawLine.bind(this);
+ this.drawThres = this.drawThres.bind(this);
+ this.drawGrid = this.drawGrid.bind(this);
+ this.drawAUC = this.drawAUC.bind(this);
+ this.drawPeaks = this.drawPeaks.bind(this);
+ this.drawRef = this.drawRef.bind(this);
+ this.drawInteg = this.drawInteg.bind(this);
+ this.drawMtply = this.drawMtply.bind(this);
+ this.drawComparisons = this.drawComparisons.bind(this);
+ this.onClickTarget = this.onClickTarget.bind(this);
+ this.onClickIntegrationTarget = this.onClickIntegrationTarget.bind(this);
+ this.onIntegrationMouseMove = this.onIntegrationMouseMove.bind(this);
+ this.clearSplitPreview = this.clearSplitPreview.bind(this);
+ this.mergedPeaks = this.mergedPeaks.bind(this);
+ this.isFirefox = typeof InstallTrigger !== 'undefined';
+ this.wavelength = null;
+ }
+ getShouldUpdate(nextEpSt, nextItSt, nextMySt) {
+ const {
+ prevXt,
+ prevYt,
+ prevEpSt,
+ prevLySt,
+ prevItSt,
+ prevMySt,
+ prevTePt,
+ prevDtPk,
+ prevSfPk,
+ prevData
+ } = this.shouldUpdate;
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const sameXY = xt(1.1) === prevXt && prevYt === yt(1.1);
+ const sameEpSt = prevEpSt === nextEpSt;
+ const sameLySt = prevLySt === this.layout;
+ const sameItSt = prevItSt === nextItSt;
+ const sameMySt = prevMySt === nextMySt;
+ const sameTePt = prevTePt === this.tTrEndPts.length;
+ const sameDtPk = prevDtPk === this.dataPks.length;
+ const sameSfPk = JSON.stringify(prevSfPk) === JSON.stringify(this.tSfPeaks);
+ const sameData = prevData === this.data.length;
+ const sameRef = prevEpSt.prevOffset === nextEpSt.prevOffset;
+ this.shouldUpdate = Object.assign({}, this.shouldUpdate, {
+ sameXY,
+ sameEpSt,
+ sameLySt,
+ sameItSt,
+ sameMySt,
+ // eslint-disable-line
+ sameTePt,
+ sameDtPk,
+ sameSfPk,
+ sameData,
+ sameRef // eslint-disable-line
+ });
+ }
+ resetShouldUpdate(prevEpSt, prevItSt, prevMySt) {
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const prevXt = xt(1.1);
+ const prevYt = yt(1.1);
+ const prevTePt = this.tTrEndPts.length;
+ const prevDtPk = this.dataPks.length;
+ const prevSfPk = this.tSfPeaks;
+ const prevData = this.data.length;
+ const prevLySt = this.layout;
+ this.shouldUpdate = Object.assign({}, this.shouldUpdate, {
+ prevXt,
+ prevYt,
+ prevEpSt,
+ prevLySt,
+ prevItSt,
+ prevMySt,
+ // eslint-disable-line
+ prevTePt,
+ prevDtPk,
+ prevSfPk,
+ prevData // eslint-disable-line
+ });
+ }
+ setTip() {
+ this.tip = (0, _init.InitTip)();
+ this.root.call(this.tip);
+ }
+ setDataParams(data, peaks, tTrEndPts, tSfPeaks, freq, layout, wavelength) {
+ this.data = [...data];
+ this.dataPks = [...peaks];
+ this.tTrEndPts = tTrEndPts;
+ this.tSfPeaks = tSfPeaks;
+ this.freq = freq;
+ this.layout = layout;
+ this.wavelength = wavelength;
+ }
+ updatePathCall(xt, yt) {
+ this.pathCall = d3.line().x(d => xt(d.x)).y(d => yt(d.y));
+ }
+ setConfig(sweepExtentSt) {
+ // Domain Calculate
+ let {
+ xExtent,
+ yExtent
+ } = sweepExtentSt || {
+ xExtent: false,
+ yExtent: false
+ };
+ if (!xExtent || !yExtent) {
+ const xes = d3.extent(this.data, d => d.x).sort((a, b) => a - b);
+ xExtent = {
+ xL: xes[0],
+ xU: xes[1]
+ };
+ const btm = d3.min(this.data, d => d.y);
+ const top = d3.max(this.data, d => d.y);
+ const height = top - btm;
+ yExtent = {
+ yL: btm - this.factor * height,
+ yU: top + this.factor * height
+ };
+ }
+ this.scales.x.domain([xExtent.xL, xExtent.xU]);
+ this.scales.y.domain([yExtent.yL, yExtent.yU]);
+
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+
+ // Axis Call
+ this.axisCall.x.scale(xt);
+ this.axisCall.y.scale(yt);
+ this.currentExtent = {
+ xExtent,
+ yExtent
+ };
+ }
+ drawLine() {
+ const {
+ sameXY,
+ sameRef,
+ sameSfPk
+ } = this.shouldUpdate;
+ if (sameXY && sameRef && sameSfPk) return;
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ this.updatePathCall(xt, yt);
+ this.path.attr('d', this.pathCall(this.data));
+ }
+ drawThres() {
+ if (this.tTrEndPts.length > 0) {
+ this.thresLineUp.attr('d', this.pathCall(this.tTrEndPts));
+ this.thresLineUp.attr('visibility', 'visible');
+ const [left, right] = this.tTrEndPts;
+ const dwMirrorEndPts = [Object.assign({}, left, {
+ y: -left.y
+ }), Object.assign({}, right, {
+ y: -right.y
+ })];
+ this.thresLineDw.attr('d', this.pathCall(dwMirrorEndPts));
+ this.thresLineDw.attr('visibility', 'visible');
+ } else {
+ this.thresLineUp.attr('visibility', 'hidden');
+ this.thresLineDw.attr('visibility', 'hidden');
+ }
+ }
+ drawGrid() {
+ const {
+ sameXY,
+ sameSfPk
+ } = this.shouldUpdate;
+ if (sameXY && sameSfPk) return;
+ this.grid.x.call(this.axisCall.x.tickSize(-this.h, 0, 0)).selectAll('line').attr('stroke', '#ddd').attr('stroke-opacity', 0.6).attr('fill', 'none');
+ this.grid.y.call(this.axisCall.y.tickSize(-this.w, 0, 0)).selectAll('line').attr('stroke', '#ddd').attr('stroke-opacity', 0.6).attr('fill', 'none');
+ }
+ onClickTarget(event, data) {
+ event.stopPropagation();
+ event.preventDefault();
+ const onPeak = true;
+ this.clickUiTargetAct(data, onPeak);
+ }
+ clearSplitPreview() {
+ (0, _integration_split.clearIntegrationSplitPreview)(this);
+ }
+ onIntegrationMouseMove(event, data, shift, ignoreRef) {
+ if (!this.isUiSplitIntgSt) return;
+ const splitX = (0, _integration_split.getSplitXFromEvent)(event, this);
+ (0, _integration_split.drawIntegrationSplitPreview)(this, data, splitX, shift, ignoreRef);
+ }
+ onClickIntegrationTarget(event, data) {
+ if (!this.isUiSplitIntgSt) {
+ this.onClickTarget(event, data);
+ return;
+ }
+ event.stopPropagation();
+ event.preventDefault();
+ const splitX = (0, _integration_split.getSplitXFromEvent)(event, this);
+ this.clearSplitPreview();
+ this.splitIntegrationAct({
+ curveIdx: this.jcampIdx,
+ target: data,
+ splitX,
+ data: this.data
+ });
+ }
+ mergedPeaks(editPeakSt) {
+ if (!editPeakSt) return this.dataPks;
+ this.dataPks = (0, _converter.PksEdit)(this.dataPks, editPeakSt);
+ return this.dataPks;
+ }
+ drawAUC(stack, shift = 0) {
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const auc = this.tags.aucPath.selectAll('path').data(stack);
+ auc.exit().attr('class', 'exit').remove();
+ const integCurve = border => {
+ const {
+ xL,
+ xU
+ } = border;
+ const ps = (0, _integration.getIntegrationPoints)(xL, xU, this.data);
+ if (!ps[0]) return null;
+ const baselineY = (0, _integration.getLinearBaseline)(ps);
+ return d3.area().x(d => xt(d.x)).y0(d => yt(baselineY(d))).y1(d => yt(d.y))(ps);
+ };
+ 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) => {
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'none');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill', 'red');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill-opacity', 0.2);
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, true)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ }
+ drawPeaks(editPeakSt) {
+ const {
+ sameXY,
+ sameEpSt,
+ sameDtPk,
+ sameSfPk
+ } = this.shouldUpdate;
+ if (!_format.default.isCyclicVoltaLayout(this.layout) && sameXY && sameEpSt && sameDtPk && sameSfPk) return;
+
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const dPks = this.mergedPeaks(editPeakSt);
+ const mpp = this.tags.pPath.selectAll('path').data(dPks);
+ mpp.exit().attr('class', 'exit').remove();
+ const linePath = [{
+ x: -0.5,
+ y: 10
+ }, {
+ x: -0.5,
+ y: -20
+ }, {
+ x: 0.5,
+ y: -20
+ }, {
+ x: 0.5,
+ y: 10
+ }];
+ // const faktor = layoutSt === LIST_LAYOUT.IR ? -1 : 1;
+ const lineSymbol = d3.line().x(d => d.x).y(d => d.y)(linePath);
+ mpp.enter().append('path').attr('d', lineSymbol).attr('class', 'enter-peak').attr('fill', 'red').attr('stroke', 'pink').attr('stroke-width', 3).attr('stroke-opacity', 0.0).merge(mpp).attr('id', d => `mpp${Math.round(1000 * d.x)}`).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y)})`).on('mouseover', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '1.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'blue');
+ const tipParams = {
+ d,
+ layout: this.layout
+ };
+ this.tip.show(tipParams, event.target);
+ }).on('mouseout', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '0.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'red');
+ const tipParams = {
+ d,
+ layout: this.layout
+ };
+ this.tip.hide(tipParams, event.target);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ const ignoreRef = _format.default.isHplcUvVisLayout(this.layout);
+ if (ignoreRef) {
+ const bpTxt = this.tags.bpTxt.selectAll('text').data(dPks);
+ bpTxt.exit().attr('class', 'exit').remove();
+ bpTxt.enter().append('text').attr('class', 'peak-text').attr('font-family', 'Helvetica').style('font-size', '12px').attr('fill', '#228B22').style('text-anchor', 'middle').merge(bpTxt).attr('id', d => `mpp${Math.round(1000 * d.x)}`).text(d => d.x.toFixed(2)).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y) - 25})`).on('click', (event, d) => this.onClickTarget(event, d));
+ }
+ }
+ drawInteg(integationSt) {
+ const {
+ sameXY,
+ sameLySt,
+ sameItSt,
+ sameData
+ } = this.shouldUpdate;
+ if (sameXY && sameLySt && sameItSt && sameData) return;
+ const {
+ selectedIdx,
+ integrations
+ } = integationSt;
+ const selectedIntegration = integrations[selectedIdx];
+ const {
+ stack,
+ refArea,
+ refFactor,
+ shift
+ } = selectedIntegration;
+ const isDisable = _cfg.default.btnCmdIntg(this.layout);
+ const ignoreRef = _format.default.isHplcUvVisLayout(this.layout);
+ const itgs = isDisable ? [] : stack;
+ Object.assign(this, {
+ integrationSplitTargets: {
+ stack: itgs,
+ shift,
+ ignoreRef
+ }
+ });
+ const igbp = this.tags.igbPath.selectAll('path').data(itgs);
+ igbp.exit().attr('class', 'exit').remove();
+ const igcp = this.tags.igcPath.selectAll('path').data(itgs);
+ igcp.exit().attr('class', 'exit').remove();
+ const igtp = this.tags.igtPath.selectAll('text').data(itgs);
+ igtp.exit().attr('class', 'exit').remove();
+ if (itgs.length === 0 || isDisable) {
+ // remove drawn area under curve
+ const auc = this.tags.aucPath.selectAll('path').data(stack);
+ auc.exit().attr('class', 'exit').remove();
+ auc.merge(auc);
+ return;
+ }
+ if (ignoreRef) {
+ this.drawAUC(stack, shift);
+ } else {
+ // rescale for zoom
+ const {
+ xt
+ } = (0, _compass.TfRescale)(this);
+ const dh = 50;
+ const integBar = data => d3.line()([[xt(data.xL - shift), dh], [xt(data.xL - shift), dh - 10], [xt(data.xL - shift), dh - 5], [xt(data.xU - shift), dh - 5], [xt(data.xU - shift), dh - 10], [xt(data.xU - shift), dh]]);
+ igbp.enter().append('path').attr('class', 'igbp').attr('fill', 'none').attr('stroke', '#228B22').attr('stroke-width', 2).merge(igbp).attr('id', d => `igbp${(0, _focus.itgIdTag)(d)}`).attr('d', d => integBar(d)).on('mouseover', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ const integCurve = border => {
+ const {
+ xL,
+ xU
+ } = border;
+ const [nXL, nXU] = [xL - shift, xU - shift];
+ const ps = this.data.filter(d => d.x > nXL && d.x < nXU);
+ const kMax = this.data[this.data.length - 1].k;
+ if (!ps[0]) return null;
+ const kRef = ps[0].k;
+ if (!this.reverseXAxis(this.layout)) {
+ return d3.line().x(d => xt(d.x)).y(d => 100 - (kRef - d.k) * 400 / kMax)(ps);
+ }
+ return d3.line().x(d => xt(d.x)).y(d => 300 - (d.k - kRef) * 400 / kMax)(ps);
+ };
+ igcp.enter().append('path').attr('class', 'igcp').attr('fill', 'none').attr('stroke', '#228B22').attr('stroke-width', 2).merge(igcp).attr('id', d => `igbc${(0, _focus.itgIdTag)(d)}`).attr('d', d => integCurve(d)).on('mouseover', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ 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) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ }
+ }
+ drawMtply(mtplySt) {
+ const {
+ sameXY,
+ sameLySt,
+ sameMySt
+ } = this.shouldUpdate;
+ if (sameXY && sameLySt && sameMySt) return;
+ const {
+ selectedIdx,
+ multiplicities
+ } = mtplySt;
+ const selectedMulti = multiplicities[selectedIdx];
+ const {
+ stack,
+ smExtext,
+ shift
+ } = selectedMulti;
+ const mpys = stack;
+ const isDisable = _cfg.default.btnCmdMpy(this.layout);
+ if (mpys === 0 || isDisable) return;
+ // rescale for zoom
+ const {
+ xt
+ } = (0, _compass.TfRescale)(this);
+ const mpyb = this.tags.mpybPath.selectAll('path').data(mpys);
+ mpyb.exit().attr('class', 'exit').remove();
+ const mpyt1 = this.tags.mpyt1Path.selectAll('text').data(mpys);
+ mpyt1.exit().attr('class', 'exit').remove();
+ const mpyt2 = this.tags.mpyt2Path.selectAll('text').data(mpys);
+ mpyt2.exit().attr('class', 'exit').remove();
+ let mPeaks = mpys.map(m => {
+ const {
+ peaks,
+ xExtent
+ } = m;
+ return peaks.map(p => Object.assign({}, p, {
+ xExtent
+ }));
+ });
+ mPeaks = [].concat(...mPeaks);
+ const mpyp = this.tags.mpypPath.selectAll('path').data(mPeaks);
+ mpyp.exit().attr('class', 'exit').remove();
+ const height = this.h;
+ const dh = Math.abs(0.06 * height);
+ const mpyBar = data => d3.line()([[xt(data.xExtent.xL - shift), height - dh], [xt(data.xExtent.xL - shift), height - dh - 10], [xt(data.xExtent.xL - shift), height - dh - 5], [xt(data.xExtent.xU - shift), height - dh - 5], [xt(data.xExtent.xU - shift), height - dh - 10], [xt(data.xExtent.xU - shift), height - dh]]);
+ const mpyColor = d => {
+ const {
+ xL,
+ xU
+ } = d.xExtent;
+ return smExtext.xL === xL && smExtext.xU === xU ? 'purple' : '#DA70D6';
+ };
+ 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) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ mpyt1.enter().append('text').attr('class', 'mpyt1').attr('font-family', 'Helvetica').style('font-size', '12px').style('text-anchor', 'middle').merge(mpyt1).attr('fill', d => mpyColor(d)).attr('id', d => `mpyt1${(0, _focus.mpyIdTag)(d)}`).text(d => `${(0, _multiplicity_calc.calcMpyCenter)(d.peaks, shift, d.mpyType).toFixed(3)}`).attr('transform', d => `translate(${xt((d.xExtent.xL + d.xExtent.xU) / 2 - shift)}, ${height - dh + 12})`).on('mouseover', (event, d) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ mpyt2.enter().append('text').attr('class', 'mpyt2').attr('font-family', 'Helvetica').style('font-size', '12px').style('text-anchor', 'middle').merge(mpyt2).attr('fill', d => mpyColor(d)).attr('id', d => `mpyt2${(0, _focus.mpyIdTag)(d)}`).text(d => `(${d.mpyType})`).attr('transform', d => `translate(${xt((d.xExtent.xL + d.xExtent.xU) / 2 - shift)}, ${height - dh + 24})`).on('mouseover', (event, d) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ const mpypH = height - dh;
+ const mpypPath = pk => [{
+ x: xt(pk.x - shift) - 0.5,
+ y: mpypH - 5
+ }, {
+ x: xt(pk.x - shift) - 0.5,
+ y: mpypH - 20
+ }, {
+ x: xt(pk.x - shift) + 0.5,
+ y: mpypH - 20
+ }, {
+ x: xt(pk.x - shift) + 0.5,
+ y: mpypH - 5
+ }];
+ // const faktor = layoutSt === LIST_LAYOUT.IR ? -1 : 1;
+ const lineSymbol = d3.line().x(d => d.x).y(d => d.y);
+ mpyp.enter().append('path').attr('class', 'mpyp').attr('fill', 'none').merge(mpyp).attr('stroke', d => mpyColor(d)).attr('d', d => lineSymbol(mpypPath(d))).attr('id', d => `mpyp${(0, _focus.mpyIdTag)(d)}`).on('mouseover', (event, d) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ }
+ drawRef() {
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const ccp = this.ref.selectAll('path').data(this.tSfPeaks);
+ ccp.exit().attr('class', 'exit').remove();
+ const linePath = [{
+ x: -0.5,
+ y: 10
+ }, {
+ x: -4,
+ y: -20
+ }, {
+ x: 4,
+ y: -20
+ }, {
+ x: 0.5,
+ y: 10
+ }];
+ const faktor = _format.default.isIrLayout(this.layout) ? -1 : 1;
+ const lineSymbol = d3.line().x(d => d.x).y(d => faktor * d.y)(linePath);
+ ccp.enter().append('path').attr('d', lineSymbol).attr('class', 'enter-ref').attr('fill', 'green').attr('fill-opacity', 0.8).merge(ccp).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y)})`);
+ }
+ drawComparisons(comparisons) {
+ d3.selectAll('.line-clip-compare').remove();
+ if (!comparisons) return null;
+ comparisons.forEach((c, idx) => {
+ if (!c.show) return;
+ const path = (0, _mount.MountComparePath)(this, _format.default.compareColors(idx), idx); // #D5D8DC
+ path.attr('d', this.pathCall(c.data));
+ });
+ return null;
+ }
+ reverseXAxis(layoutSt) {
+ return [_list_layout.LIST_LAYOUT.UVVIS, _list_layout.LIST_LAYOUT.HPLC_UVVIS, _list_layout.LIST_LAYOUT.TGA, _list_layout.LIST_LAYOUT.DSC, _list_layout.LIST_LAYOUT.XRD, _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY, _list_layout.LIST_LAYOUT.CDS, _list_layout.LIST_LAYOUT.DLS_ACF, _list_layout.LIST_LAYOUT.SEC, _list_layout.LIST_LAYOUT.GC, _list_layout.LIST_LAYOUT.EMISSIONS, _list_layout.LIST_LAYOUT.DLS_INTENSITY].indexOf(layoutSt) < 0;
+ }
+ create({
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ freq,
+ comparisons,
+ editPeakSt,
+ layoutSt,
+ integationSt,
+ mtplySt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ wavelength
+ }) {
+ this.svg = d3.select('.d3Svg');
+ (0, _mount.MountMainFrame)(this, 'focus');
+ (0, _mount.MountClip)(this);
+ this.root = d3.select(this.rootKlass).selectAll('.focus-main');
+ this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt));
+ this.setTip();
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, freq, layoutSt, wavelength);
+ Object.assign(this, {
+ isUiSplitIntgSt
+ });
+ if (!isUiSplitIntgSt) this.clearSplitPreview();
+ (0, _compass.MountCompass)(this);
+ this.axis = (0, _mount.MountAxis)(this);
+ this.path = (0, _mount.MountPath)(this, 'steelblue');
+ [this.thresLineUp, this.thresLineDw] = (0, _mount.MountThresLine)(this, 'green');
+ this.grid = (0, _mount.MountGrid)(this);
+ this.tags = (0, _mount.MountTags)(this);
+ this.ref = (0, _mount.MountRef)(this);
+ (0, _mount.MountAxisLabelX)(this);
+ (0, _mount.MountAxisLabelY)(this);
+ if (this.data && this.data.length > 0) {
+ this.setConfig(sweepExtentSt);
+ this.drawLine();
+ this.drawThres();
+ this.drawGrid();
+ this.drawRef();
+ this.drawPeaks(editPeakSt);
+ this.drawInteg(integationSt);
+ this.drawMtply(mtplySt);
+ this.drawComparisons(comparisons);
+ }
+ (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt);
+ this.resetShouldUpdate(editPeakSt, integationSt, mtplySt);
+ }
+ update({
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ freq,
+ comparisons,
+ editPeakSt,
+ layoutSt,
+ integationSt,
+ mtplySt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ wavelength
+ }) {
+ this.root = d3.select(this.rootKlass).selectAll('.focus-main');
+ this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt));
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, freq, layoutSt, wavelength);
+ Object.assign(this, {
+ isUiSplitIntgSt
+ });
+ if (!isUiSplitIntgSt) this.clearSplitPreview();
+ if (this.data && this.data.length > 0) {
+ this.setConfig(sweepExtentSt);
+ this.getShouldUpdate(editPeakSt, integationSt, mtplySt);
+ this.drawLine();
+ this.drawThres();
+ this.drawGrid();
+ this.drawRef();
+ this.drawPeaks(editPeakSt);
+ this.drawInteg(integationSt);
+ this.drawMtply(mtplySt);
+ this.drawComparisons(comparisons);
+ }
+ (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt);
+ this.resetShouldUpdate(editPeakSt, integationSt, mtplySt);
+ }
+}
+var _default = exports.default = LineFocus;
\ No newline at end of file
diff --git a/dist/components/d3_multi/index.js b/dist/components/d3_multi/index.js
new file mode 100644
index 00000000..d38ce0ab
--- /dev/null
+++ b/dist/components/d3_multi/index.js
@@ -0,0 +1,436 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _chem = require("../../helpers/chem");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _manager = require("../../actions/manager");
+var _ui = require("../../actions/ui");
+var _integration = require("../../actions/integration");
+var _list_ui = require("../../constants/list_ui");
+var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry");
+var _multi_focus = _interopRequireDefault(require("./multi_focus"));
+var _draw = require("../common/draw");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable no-mixed-operators, react/require-default-props,
+react/no-unused-prop-types */
+
+const W = Math.round(window.innerWidth * 0.90 * 9 / 12); // ROI
+const H = Math.round(window.innerHeight * 0.90 * 0.85); // ROI
+
+class ViewerMulti extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ const {
+ entities,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct
+ } = this.props;
+ this.rootKlass = '.d3Line';
+ this.containerRef = /*#__PURE__*/_react.default.createRef();
+ this.currentSize = null;
+ this.resizeObserver = null;
+ this.focus = new _multi_focus.default({
+ W,
+ H,
+ entities,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct
+ });
+ this.normChange = this.normChange.bind(this);
+ this.handleResize = this.handleResize.bind(this);
+ }
+ componentDidMount() {
+ this.renderChart(this.props, true);
+ this.setupResizeObserver();
+ const {
+ curveSt,
+ seed,
+ peak,
+ cLabel,
+ xLabel,
+ yLabel,
+ feature,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ isHidden,
+ resetAllAct,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt,
+ axesUnitsSt
+ } = this.props;
+ (0, _draw.drawDestroy)(this.rootKlass);
+ resetAllAct(feature);
+ let xxLabel = xLabel;
+ let yyLabel = yLabel;
+ if (axesUnitsSt) {
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ axes
+ } = axesUnitsSt;
+ let selectedAxes = axes[curveIdx];
+ if (!selectedAxes) {
+ selectedAxes = {
+ xUnit: '',
+ yUnit: ''
+ };
+ }
+ const {
+ xUnit,
+ yUnit
+ } = selectedAxes;
+ xxLabel = xUnit === '' ? xLabel : xUnit;
+ yyLabel = yUnit === '' ? yLabel : yUnit;
+ }
+ if (cyclicvoltaSt && cyclicvoltaSt.useCurrentDensity) {
+ const areaUnit = cyclicvoltaSt.areaUnit || 'cm²';
+ const baseUnit = /mA/i.test(String(yyLabel)) ? 'mA' : 'A';
+ yyLabel = `Current density in ${baseUnit}/${areaUnit}`;
+ }
+ const filterSeed = seed;
+ const filterPeak = peak;
+ (0, _draw.drawMain)(this.rootKlass, W, H);
+ this.focus.create({
+ curveSt,
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt
+ });
+ (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel);
+ (0, _draw.drawDisplay)(this.rootKlass, isHidden);
+ (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden);
+ }
+ componentDidUpdate(prevProps) {
+ const {
+ entities,
+ curveSt,
+ seed,
+ peak,
+ cLabel,
+ xLabel,
+ yLabel,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ isHidden,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt,
+ axesUnitsSt
+ } = this.props;
+ this.normChange(prevProps);
+ let xxLabel = xLabel;
+ let yyLabel = yLabel;
+ if (axesUnitsSt) {
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ axes
+ } = axesUnitsSt;
+ let selectedAxes = axes[curveIdx];
+ if (!selectedAxes) {
+ selectedAxes = {
+ xUnit: '',
+ yUnit: ''
+ };
+ }
+ const {
+ xUnit,
+ yUnit
+ } = selectedAxes;
+ xxLabel = xUnit === '' ? xLabel : xUnit;
+ yyLabel = yUnit === '' ? yLabel : yUnit;
+ }
+ if (cyclicvoltaSt && cyclicvoltaSt.useCurrentDensity) {
+ const areaUnit = cyclicvoltaSt.areaUnit || 'cm²';
+ const baseUnit = /mA/i.test(String(yyLabel)) ? 'mA' : 'A';
+ yyLabel = `Current density in ${baseUnit}/${areaUnit}`;
+ }
+ const filterSeed = seed;
+ const filterPeak = peak;
+ if (_format.default.isCyclicVoltaLayout(layoutSt)) {
+ this.handleResize();
+ }
+ this.focus.update({
+ entities,
+ curveSt,
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt
+ });
+ (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel);
+ (0, _draw.drawDisplay)(this.rootKlass, isHidden);
+ (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden);
+ }
+ componentWillUnmount() {
+ (0, _draw.drawDestroy)(this.rootKlass);
+ this.teardownResizeObserver();
+ }
+ handleResize() {
+ const {
+ layoutSt
+ } = this.props;
+ if (!_format.default.isCyclicVoltaLayout(layoutSt)) return;
+ const size = this.getContainerSize();
+ if (!size) return;
+ if (!this.currentSize || size.width !== this.currentSize.width || size.height !== this.currentSize.height) {
+ this.renderChart(this.props, false);
+ }
+ }
+ getContainerSize() {
+ const node = this.containerRef.current;
+ if (!node) return null;
+ const {
+ clientWidth,
+ clientHeight
+ } = node;
+ if (!clientWidth || !clientHeight) return null;
+ return {
+ width: clientWidth,
+ height: clientHeight
+ };
+ }
+ getTargetSize(layoutSt) {
+ if (_format.default.isCyclicVoltaLayout(layoutSt)) {
+ const size = this.getContainerSize();
+ if (size) return size;
+ }
+ return {
+ width: W,
+ height: H
+ };
+ }
+ setupResizeObserver() {
+ if (typeof ResizeObserver === 'undefined') return;
+ if (!this.containerRef.current || this.resizeObserver) return;
+ this.resizeObserver = new ResizeObserver(this.handleResize);
+ this.resizeObserver.observe(this.containerRef.current);
+ }
+ teardownResizeObserver() {
+ if (this.resizeObserver) {
+ this.resizeObserver.disconnect();
+ this.resizeObserver = null;
+ }
+ }
+ normChange(prevProps) {
+ const {
+ feature,
+ resetAllAct,
+ entities
+ } = this.props;
+ const oldEntities = prevProps.entities;
+ if (oldEntities !== entities) {
+ resetAllAct(feature);
+ }
+ }
+ renderChart(props, shouldReset) {
+ const {
+ curveSt,
+ seed,
+ peak,
+ cLabel,
+ xLabel,
+ yLabel,
+ feature,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ isHidden,
+ resetAllAct,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt,
+ axesUnitsSt,
+ entities,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct
+ } = props;
+ const size = this.getTargetSize(layoutSt);
+ this.currentSize = size;
+ (0, _draw.drawDestroy)(this.rootKlass);
+ if (shouldReset) {
+ resetAllAct(feature);
+ }
+ let xxLabel = xLabel;
+ let yyLabel = yLabel;
+ if (axesUnitsSt) {
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ axes
+ } = axesUnitsSt;
+ let selectedAxes = axes[curveIdx];
+ if (!selectedAxes) {
+ selectedAxes = {
+ xUnit: '',
+ yUnit: ''
+ };
+ }
+ const {
+ xUnit,
+ yUnit
+ } = selectedAxes;
+ xxLabel = xUnit === '' ? xLabel : xUnit;
+ yyLabel = yUnit === '' ? yLabel : yUnit;
+ }
+ const filterSeed = seed;
+ const filterPeak = peak;
+ this.focus = new _multi_focus.default({
+ W: size.width,
+ H: size.height,
+ entities,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct
+ });
+ (0, _draw.drawMain)(this.rootKlass, size.width, size.height);
+ this.focus.create({
+ curveSt,
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt
+ });
+ (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel);
+ (0, _draw.drawDisplay)(this.rootKlass, isHidden);
+ (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden);
+ }
+ render() {
+ const {
+ layoutSt
+ } = this.props;
+ const isCyclicVolta = _format.default.isCyclicVoltaLayout(layoutSt);
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: "d3Line",
+ ref: this.containerRef,
+ style: isCyclicVolta ? {
+ height: '100%'
+ } : undefined
+ });
+ }
+}
+const mapStateToProps = (state, props) => ({
+ curveSt: state.curve,
+ seed: (0, _chem.Topic2Seed)(state, props),
+ peak: (0, _chem.Feature2Peak)(state, props),
+ tTrEndPts: (0, _chem.ToThresEndPts)(state, props),
+ tSfPeaks: (0, _chem.ToShiftPeaks)(state, props),
+ editPeakSt: state.editPeak.present,
+ layoutSt: state.layout,
+ sweepExtentSt: state.ui.sweepExtent,
+ isUiAddIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ isUiSplitIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT,
+ isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0,
+ cyclicvoltaSt: state.cyclicvolta,
+ maxminPeakSt: (0, _chem.Feature2MaxMinPeak)(state, props),
+ integationSt: state.integration.present,
+ mtplySt: state.multiplicity.present,
+ axesUnitsSt: state.axesUnits
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ resetAllAct: _manager.resetAll,
+ clickUiTargetAct: _ui.clickUiTarget,
+ selectUiSweepAct: _ui.selectUiSweep,
+ scrollUiWheelAct: _ui.scrollUiWheel,
+ splitIntegrationAct: _integration.splitIntegration,
+ addNewCylicVoltaPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak,
+ addCylicVoltaMaxPeakAct: _cyclic_voltammetry.addCylicVoltaMaxPeak,
+ addCylicVoltaMinPeakAct: _cyclic_voltammetry.addCylicVoltaMinPeak
+}, dispatch);
+ViewerMulti.propTypes = {
+ curveSt: _propTypes.default.object.isRequired,
+ entities: _propTypes.default.array.isRequired,
+ seed: _propTypes.default.array.isRequired,
+ peak: _propTypes.default.array.isRequired,
+ xLabel: _propTypes.default.string.isRequired,
+ yLabel: _propTypes.default.string.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ tTrEndPts: _propTypes.default.array.isRequired,
+ tSfPeaks: _propTypes.default.array.isRequired,
+ editPeakSt: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ integationSt: _propTypes.default.object.isRequired,
+ mtplySt: _propTypes.default.object.isRequired,
+ sweepExtentSt: _propTypes.default.object.isRequired,
+ isUiAddIntgSt: _propTypes.default.bool.isRequired,
+ isUiSplitIntgSt: _propTypes.default.bool.isRequired,
+ isUiNoBrushSt: _propTypes.default.bool.isRequired,
+ resetAllAct: _propTypes.default.func.isRequired,
+ clickUiTargetAct: _propTypes.default.func.isRequired,
+ selectUiSweepAct: _propTypes.default.func.isRequired,
+ scrollUiWheelAct: _propTypes.default.func.isRequired,
+ splitIntegrationAct: _propTypes.default.func.isRequired,
+ isHidden: _propTypes.default.bool,
+ cyclicvoltaSt: _propTypes.default.object.isRequired,
+ maxminPeakSt: _propTypes.default.object,
+ addNewCylicVoltaPairPeakAct: _propTypes.default.func.isRequired,
+ addCylicVoltaMaxPeakAct: _propTypes.default.func.isRequired,
+ addCylicVoltaMinPeakAct: _propTypes.default.func.isRequired,
+ cLabel: _propTypes.default.string,
+ axesUnitsSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)(ViewerMulti);
\ No newline at end of file
diff --git a/dist/components/d3_multi/multi_focus.js b/dist/components/d3_multi/multi_focus.js
new file mode 100644
index 00000000..b4c60a34
--- /dev/null
+++ b/dist/components/d3_multi/multi_focus.js
@@ -0,0 +1,1000 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _init = require("../../helpers/init");
+var _mount = require("../../helpers/mount");
+var _converter = require("../../helpers/converter");
+var _brush = _interopRequireDefault(require("../../helpers/brush"));
+var _compass = require("../../helpers/compass");
+var _integration_split = require("../../helpers/integration_split");
+var _list_layout = require("../../constants/list_layout");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _chem = require("../../helpers/chem");
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _focus = require("../../helpers/focus");
+var _integration = require("../../helpers/integration");
+var _multiplicity_calc = require("../../helpers/multiplicity_calc");
+/* eslint-disable no-unused-vars, prefer-object-spread, no-mixed-operators,
+no-unneeded-ternary, arrow-body-style, max-len */
+
+const d3 = require('d3');
+class MultiFocus {
+ constructor(props) {
+ const {
+ W,
+ H,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ entities,
+ splitIntegrationAct
+ } = props;
+ this.entities = entities;
+ this.jcampIdx = 0;
+ this.isShowAllCurves = false;
+ this.rootKlass = '.d3Line';
+ this.margin = {
+ t: 5,
+ b: 40,
+ l: 60,
+ r: 5
+ };
+ this.w = W - this.margin.l - this.margin.r;
+ this.h = H - this.margin.t - this.margin.b;
+ this.clickUiTargetAct = clickUiTargetAct;
+ this.selectUiSweepAct = selectUiSweepAct;
+ this.scrollUiWheelAct = scrollUiWheelAct;
+ this.splitIntegrationAct = splitIntegrationAct;
+ this.brush = d3.brush();
+ this.brushX = d3.brushX();
+ this.axis = null;
+ this.path = null;
+ this.thresLineUp = null;
+ this.thresLineDw = null;
+ this.grid = null;
+ this.tags = null;
+ this.ref = null;
+ this.data = [];
+ this.otherLineData = [];
+ this.pathColor = 'steelblue';
+ this.dataPks = [];
+ this.dataPeckers = [];
+ this.tTrEndPts = null;
+ this.tSfPeaks = null;
+ this.root = null;
+ this.svg = null;
+ this.axisCall = (0, _init.InitAxisCall)(5);
+ this.pathCall = null;
+ this.tip = null;
+ this.factor = 0.125;
+ this.currentExtent = null;
+ this.shouldUpdate = {};
+ // this.freq = false;
+ this.layout = _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY;
+ this.isUiAddIntgSt = false;
+ this.isUiSplitIntgSt = false;
+ this.integrationSplitTargets = null;
+ this.firstIntegrationPoint = null;
+ this.getShouldUpdate = this.getShouldUpdate.bind(this);
+ this.resetShouldUpdate = this.resetShouldUpdate.bind(this);
+ this.setTip = this.setTip.bind(this);
+ this.setDataParams = this.setDataParams.bind(this);
+ this.create = this.create.bind(this);
+ this.update = this.update.bind(this);
+ this.setConfig = this.setConfig.bind(this);
+ this.drawLine = this.drawLine.bind(this);
+ this.drawThres = this.drawThres.bind(this);
+ this.drawOtherLines = this.drawOtherLines.bind(this);
+ this.drawGrid = this.drawGrid.bind(this);
+ this.drawPeaks = this.drawPeaks.bind(this);
+ this.drawRef = this.drawRef.bind(this);
+ this.drawInteg = this.drawInteg.bind(this);
+ this.drawMtply = this.drawMtply.bind(this);
+ this.drawAUC = this.drawAUC.bind(this);
+ this.onClickTarget = this.onClickTarget.bind(this);
+ this.onClickIntegrationTarget = this.onClickIntegrationTarget.bind(this);
+ this.onIntegrationMouseMove = this.onIntegrationMouseMove.bind(this);
+ this.clearSplitPreview = this.clearSplitPreview.bind(this);
+ this.mergedPeaks = this.mergedPeaks.bind(this);
+ this.setDataPecker = this.setDataPecker.bind(this);
+ this.drawPeckers = this.drawPeckers.bind(this);
+ this.onClickPecker = this.onClickPecker.bind(this);
+ this.isFirefox = typeof InstallTrigger !== 'undefined';
+ this.cyclicvoltaSt = null;
+ this.yTransformFactor = 1.0;
+ }
+ getShouldUpdate(nextEpSt) {
+ const {
+ prevXt,
+ prevYt,
+ prevEpSt,
+ prevLySt,
+ prevTePt,
+ prevDtPk,
+ prevSfPk,
+ prevData,
+ prevYFactor
+ } = this.shouldUpdate;
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const sameXY = xt(1.1) === prevXt && prevYt === yt(1.1);
+ const sameEpSt = prevEpSt === nextEpSt;
+ const sameLySt = prevLySt === this.layout;
+ const sameTePt = prevTePt === this.tTrEndPts.length;
+ const sameDtPk = prevDtPk === this.dataPks.length;
+ const sameSfPk = JSON.stringify(prevSfPk) === JSON.stringify(this.tSfPeaks);
+ const sameData = prevData === this.data.length;
+ const sameYFactor = prevYFactor === this.yTransformFactor;
+ this.shouldUpdate = Object.assign({}, this.shouldUpdate, {
+ sameXY,
+ sameEpSt,
+ sameLySt,
+ // eslint-disable-line
+ sameTePt,
+ sameDtPk,
+ sameSfPk,
+ sameData,
+ sameYFactor // eslint-disable-line
+ });
+ }
+ resetShouldUpdate(prevEpSt) {
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const prevXt = xt(1.1);
+ const prevYt = yt(1.1);
+ const prevTePt = this.tTrEndPts.length;
+ const prevDtPk = this.dataPks.length;
+ const prevSfPk = this.tSfPeaks;
+ const prevData = this.data.length;
+ const prevLySt = this.layout;
+ const prevYFactor = this.yTransformFactor;
+ this.shouldUpdate = Object.assign({}, this.shouldUpdate, {
+ prevXt,
+ prevYt,
+ prevEpSt,
+ prevLySt,
+ // eslint-disable-line
+ prevTePt,
+ prevDtPk,
+ prevSfPk,
+ prevData,
+ prevYFactor // eslint-disable-line
+ });
+ }
+ setTip() {
+ this.tip = (0, _init.InitTip)();
+ this.root.call(this.tip);
+ }
+ computeYTransformFactor(layout, cyclicvoltaSt, feature) {
+ let factor = 1.0;
+ if (layout === _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY && cyclicvoltaSt && cyclicvoltaSt.useCurrentDensity) {
+ const rawArea = (cyclicvoltaSt.areaValue === '' ? 1.0 : cyclicvoltaSt.areaValue) || 1.0;
+ const areaUnit = cyclicvoltaSt.areaUnit || 'cm²';
+ const safeArea = rawArea > 0 ? rawArea : 1.0;
+ const areaInCm2 = areaUnit === 'mm²' ? safeArea / 100.0 : safeArea;
+ factor = 1.0 / areaInCm2;
+ const baseY = feature && feature.yUnit ? String(feature.yUnit) : 'A';
+ if (/mA/i.test(baseY)) {
+ factor *= 1000.0;
+ }
+ if (areaUnit === 'mm²') {
+ factor /= 100.0;
+ }
+ }
+ return factor;
+ }
+ transformYValue(y) {
+ return y * this.yTransformFactor;
+ }
+ setDataParams(filterSeed, peaks, tTrEndPts, tSfPeaks, layout, cyclicvoltaSt, jcampIdx = 0) {
+ this.data = [];
+ this.otherLineData = [];
+ let filterSubLayoutValue = null;
+ const currFeature = this.entities && this.entities[0] ? this.entities[0].feature : null;
+ this.yTransformFactor = this.computeYTransformFactor(layout, cyclicvoltaSt, currFeature);
+ this.entities.forEach((entry, idx) => {
+ const {
+ topic,
+ feature,
+ color
+ } = entry;
+ const offset = (0, _chem.GetCyclicVoltaPreviousShift)(cyclicvoltaSt, jcampIdx);
+ let currData = (0, _chem.convertTopic)(topic, layout, feature, offset);
+ if (idx === jcampIdx) {
+ if (!_format.default.isCyclicVoltaLayout(layout)) {
+ currData = filterSeed;
+ }
+ this.data = [...currData];
+ this.pathColor = color;
+ filterSubLayoutValue = _format.default.isSECLayout(layout) ? feature.xUnit : feature.yUnit;
+ } else {
+ const filterValue = _format.default.isSECLayout(layout) ? feature.xUnit : feature.yUnit;
+ this.otherLineData.push({
+ data: currData,
+ color,
+ filterSublayout: filterValue
+ });
+ }
+ });
+ if (_format.default.isSECLayout(layout) || _format.default.isGCLayout(layout)) {
+ this.otherLineData = this.otherLineData.filter(data => {
+ return data.filterSublayout === filterSubLayoutValue;
+ });
+ }
+ if (this.jcampIdx === jcampIdx) {
+ this.dataPks = [...peaks];
+ } else {
+ this.dataPks = peaks;
+ }
+ this.tTrEndPts = tTrEndPts;
+ this.tSfPeaks = tSfPeaks;
+ this.layout = layout;
+ this.cyclicvoltaSt = cyclicvoltaSt;
+ this.jcampIdx = jcampIdx;
+ }
+ updatePathCall(xt, yt) {
+ this.pathCall = d3.line().x(d => xt(d.x)).y(d => yt(d.y));
+ }
+ setYAxisTickFormat() {
+ const f = this.yTransformFactor || 1;
+ const format = d3.format('.2n');
+ this.axisCall.y.tickFormat(v => format(v * f));
+ }
+ setConfig(sweepExtentSt) {
+ // Domain Calculate
+ let {
+ xExtent,
+ yExtent
+ } = sweepExtentSt || {
+ xExtent: false,
+ yExtent: false
+ };
+ if (!xExtent || !yExtent) {
+ let allData = [...this.data];
+ if (this.otherLineData) {
+ this.otherLineData.forEach(lineData => {
+ allData = [...allData, ...lineData.data];
+ });
+ }
+ const xes = d3.extent(allData, d => d.x).sort((a, b) => a - b);
+ xExtent = {
+ xL: xes[0],
+ xU: xes[1]
+ };
+ const btm = d3.min(allData, d => d.y);
+ const top = d3.max(allData, d => d.y);
+ const height = top - btm;
+ yExtent = {
+ yL: btm - this.factor * height,
+ yU: top + this.factor * height
+ };
+ }
+ this.scales.x.domain([xExtent.xL, xExtent.xU]);
+ this.scales.y.domain([yExtent.yL, yExtent.yU]);
+
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+
+ // Axis Call
+ this.axisCall.x.scale(xt);
+ this.axisCall.y.scale(yt);
+ if (this.layout === _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) {
+ this.setYAxisTickFormat();
+ }
+ this.currentExtent = {
+ xExtent,
+ yExtent
+ };
+ }
+ drawLine() {
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ this.updatePathCall(xt, yt);
+ this.path.attr('d', this.pathCall(this.data));
+ this.path.style('stroke', this.pathColor);
+ if (this.layout === _list_layout.LIST_LAYOUT.AIF) {
+ this.path.attr('marker-mid', 'url(#arrow-left)');
+ }
+ }
+ drawThres() {
+ if (this.tTrEndPts.length > 0) {
+ this.thresLineUp.attr('d', this.pathCall(this.tTrEndPts));
+ this.thresLineUp.attr('visibility', 'visible');
+ const [left, right] = this.tTrEndPts;
+ const dwMirrorEndPts = [Object.assign({}, left, {
+ y: -left.y
+ }), Object.assign({}, right, {
+ y: -right.y
+ })];
+ this.thresLineDw.attr('d', this.pathCall(dwMirrorEndPts));
+ this.thresLineDw.attr('visibility', 'visible');
+ } else {
+ this.thresLineUp.attr('visibility', 'hidden');
+ this.thresLineDw.attr('visibility', 'hidden');
+ }
+ }
+ drawOtherLines(layout) {
+ d3.selectAll('.line-clip-compare').remove();
+ if (!this.otherLineData) return null;
+ this.otherLineData.forEach((entry, idx) => {
+ const {
+ data,
+ color
+ } = entry;
+ const pathColor = color ? color : _format.default.mutiEntitiesColors(idx);
+ const path = (0, _mount.MountComparePath)(this, pathColor, idx, 0.4);
+ path.attr('d', this.pathCall(data));
+ if (this.layout === _list_layout.LIST_LAYOUT.AIF && this.isShowAllCurves === true) {
+ path.attr('marker-mid', 'url(#arrow-left)');
+ }
+ });
+ return null;
+ }
+ drawGrid() {
+ const {
+ sameXY,
+ sameYFactor
+ } = this.shouldUpdate;
+ if (sameXY && sameYFactor) return;
+ this.grid.x.call(this.axisCall.x.tickSize(-this.h, 0, 0)).selectAll('line').attr('stroke', '#ddd').attr('stroke-opacity', 0.6).attr('fill', 'none');
+ this.grid.y.call(this.axisCall.y.tickSize(-this.w, 0, 0)).selectAll('line').attr('stroke', '#ddd').attr('stroke-opacity', 0.6).attr('fill', 'none');
+ }
+ onClickTarget(event, data) {
+ event.stopPropagation();
+ event.preventDefault();
+ const onPeak = true;
+ if (this.layout === _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) {
+ const {
+ spectraList
+ } = this.cyclicvoltaSt;
+ const spectra = spectraList[this.jcampIdx];
+ const voltammetryPeakIdx = spectra.selectedIdx;
+ this.clickUiTargetAct(data, onPeak, voltammetryPeakIdx, this.jcampIdx);
+ } else {
+ this.clickUiTargetAct(data, onPeak, false, this.jcampIdx);
+ }
+ }
+ clearSplitPreview() {
+ (0, _integration_split.clearIntegrationSplitPreview)(this);
+ }
+ onIntegrationMouseMove(event, data, shift, ignoreRef) {
+ if (!this.isUiSplitIntgSt) return;
+ const splitX = (0, _integration_split.getSplitXFromEvent)(event, this);
+ (0, _integration_split.drawIntegrationSplitPreview)(this, data, splitX, shift, ignoreRef);
+ }
+ onClickIntegrationTarget(event, data) {
+ if (!this.isUiSplitIntgSt) {
+ this.onClickTarget(event, data);
+ return;
+ }
+ event.stopPropagation();
+ event.preventDefault();
+ const splitX = (0, _integration_split.getSplitXFromEvent)(event, this);
+ this.clearSplitPreview();
+ this.splitIntegrationAct({
+ curveIdx: this.jcampIdx,
+ target: data,
+ splitX,
+ data: this.data
+ });
+ }
+ onClickPecker(event, data) {
+ event.stopPropagation();
+ event.preventDefault();
+ const onPecker = true;
+ const {
+ spectraList
+ } = this.cyclicvoltaSt;
+ const spectra = spectraList[this.jcampIdx];
+ const voltammetryPeakIdx = spectra.selectedIdx;
+ this.clickUiTargetAct(data, false, voltammetryPeakIdx, this.jcampIdx, onPecker);
+ }
+ mergedPeaks(editPeakSt) {
+ if (!editPeakSt) return this.dataPks;
+ const {
+ spectraList
+ } = this.cyclicvoltaSt;
+ const spectra = spectraList[this.jcampIdx];
+ if (spectra) {
+ this.dataPks = [];
+ this.dataPks = (0, _converter.PksEdit)(this.dataPks, editPeakSt, spectra.list);
+ } else {
+ const newEditPeaks = Object.assign({}, editPeakSt, {
+ selectedIdx: this.jcampIdx
+ });
+ this.dataPks = (0, _converter.PksEdit)(this.dataPks, newEditPeaks, []);
+ }
+ return this.dataPks;
+ }
+ setDataPecker() {
+ const {
+ spectraList
+ } = this.cyclicvoltaSt;
+ const spectra = spectraList[this.jcampIdx];
+ if (spectra) {
+ this.dataPeckers = (0, _converter.PeckersEdit)(spectra.list);
+ }
+ return this.dataPeckers;
+ }
+ drawAUC(stack, shift = 0) {
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const auc = this.tags.aucPath.selectAll('path').data(stack);
+ auc.exit().attr('class', 'exit').remove();
+ const integCurve = border => {
+ const {
+ xL,
+ xU
+ } = border;
+ const ps = (0, _integration.getIntegrationPoints)(xL, xU, this.data);
+ if (!ps[0]) return null;
+ const baselineY = (0, _integration.getLinearBaseline)(ps);
+ return d3.area().x(d => xt(d.x)).y0(d => yt(baselineY(d))).y1(d => yt(d.y))(ps);
+ };
+ 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) => {
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'none');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill', 'red');
+ d3.select(`#auc${(0, _focus.itgIdTag)(d)}`).style('fill-opacity', 0.2);
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, true)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ }
+ drawPeaks(editPeakSt) {
+ const {
+ sameXY,
+ sameEpSt,
+ sameDtPk,
+ sameSfPk
+ } = this.shouldUpdate;
+ if (!_format.default.isCyclicVoltaLayout(this.layout) && sameXY && sameEpSt && sameDtPk && sameSfPk) return;
+
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const dPks = this.mergedPeaks(editPeakSt);
+ const {
+ spectraList
+ } = this.cyclicvoltaSt;
+ const spectra = spectraList[this.jcampIdx];
+ let indexOfCVRefPeaks = [];
+ if (spectra) {
+ const {
+ shift,
+ hasRefPeak
+ } = spectra;
+ const {
+ ref
+ } = shift;
+ if (ref && hasRefPeak) {
+ const {
+ min,
+ max
+ } = ref;
+ indexOfCVRefPeaks = dPks.map((p, index) => {
+ return p === min || p === max ? -1 : index;
+ });
+ }
+ }
+ const mpp = this.tags.pPath.selectAll('path').data(dPks);
+ mpp.exit().attr('class', 'exit').remove();
+ const linePath = [{
+ x: -0.5,
+ y: 10
+ }, {
+ x: -0.5,
+ y: -20
+ }, {
+ x: 0.5,
+ y: -20
+ }, {
+ x: 0.5,
+ y: 10
+ }];
+ const lineSymbol = d3.line().x(d => d.x).y(d => d.y)(linePath);
+ const lineRefPath = [{
+ x: -0.5,
+ y: 10
+ }, {
+ x: -4,
+ y: -20
+ }, {
+ x: 4,
+ y: -20
+ }, {
+ x: 0.5,
+ y: 10
+ }];
+ const lineSymbolRef = d3.line().x(d => d.x).y(d => d.y)(lineRefPath);
+ mpp.enter().append('path').attr('d', (_, index) => {
+ return indexOfCVRefPeaks[index] === -1 ? lineSymbolRef : lineSymbol;
+ }).attr('class', 'enter-peak').attr('fill', (_, index) => {
+ return indexOfCVRefPeaks[index] === -1 ? 'blue' : 'red';
+ }).attr('stroke', 'pink').attr('stroke-width', 3).attr('stroke-opacity', 0.0).merge(mpp).attr('id', d => `mpp${Math.round(1000 * d.x)}`).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y)})`).on('mouseover', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '1.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'blue');
+ const tipParams = {
+ d,
+ layout: this.layout,
+ yFactor: this.yTransformFactor
+ };
+ this.tip.show(tipParams, event.target);
+ }).on('mouseout', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '0.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'red');
+ const tipParams = {
+ d,
+ layout: this.layout,
+ yFactor: this.yTransformFactor
+ };
+ this.tip.hide(tipParams, event.target);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ const ignoreRef = _format.default.isHplcUvVisLayout(this.layout);
+ if (ignoreRef) {
+ const bpTxt = this.tags.bpTxt.selectAll('text').data(dPks);
+ bpTxt.exit().attr('class', 'exit').remove();
+ bpTxt.enter().append('text').attr('class', 'peak-text').attr('font-family', 'Helvetica').style('font-size', '12px').attr('fill', '#228B22').style('text-anchor', 'middle').merge(bpTxt).attr('id', d => `mpp${Math.round(1000 * d.x)}`).text(d => d.x.toFixed(2)).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y) - 25})`).on('click', (event, d) => this.onClickTarget(event, d));
+ }
+ mpp.attr('fill', (_, index) => {
+ return indexOfCVRefPeaks[index] === -1 ? 'blue' : 'red';
+ });
+ mpp.attr('d', (_, index) => {
+ return indexOfCVRefPeaks[index] === -1 ? lineSymbolRef : lineSymbol;
+ });
+ }
+ drawPeckers() {
+ const {
+ sameXY,
+ sameEpSt,
+ sameDtPk,
+ sameSfPk
+ } = this.shouldUpdate;
+ if (!_format.default.isCyclicVoltaLayout(this.layout) && sameXY && sameEpSt && sameDtPk && sameSfPk) return;
+
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const dPks = this.setDataPecker();
+ const mpp = this.tags.peckerPath.selectAll('path').data(dPks);
+ mpp.exit().attr('class', 'exit').remove();
+ const linePath = [{
+ x: -0.5,
+ y: 10
+ }, {
+ x: -0.5,
+ y: -20
+ }, {
+ x: 0.5,
+ y: -20
+ }, {
+ x: 0.5,
+ y: 10
+ }];
+ const lineSymbol = d3.line().x(d => d.x).y(d => d.y)(linePath);
+ mpp.enter().append('path').attr('d', lineSymbol).attr('class', 'enter-peak').attr('fill', '#228B22').attr('stroke', 'pink').attr('stroke-width', 3).attr('stroke-opacity', 0.0).merge(mpp).attr('id', d => `mpp${Math.round(1000 * d.x)}`).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y)})`).on('mouseover', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '1.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'blue');
+ const tipParams = {
+ d,
+ layout: this.layout,
+ yFactor: this.yTransformFactor
+ };
+ this.tip.show(tipParams, event.target);
+ }).on('mouseout', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '0.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', '#228B22');
+ const tipParams = {
+ d,
+ layout: this.layout,
+ yFactor: this.yTransformFactor
+ };
+ this.tip.hide(tipParams, event.target);
+ }).on('click', (event, d) => this.onClickPecker(event, d));
+ }
+ drawInteg(integationSt) {
+ const {
+ sameXY,
+ sameLySt,
+ sameItSt,
+ sameData
+ } = this.shouldUpdate;
+ if (sameXY && sameLySt && sameItSt && sameData) return;
+ const {
+ integrations
+ } = integationSt;
+ const selectedIntegration = integrations[this.jcampIdx];
+ if (selectedIntegration === false || selectedIntegration === undefined) {
+ Object.assign(this, {
+ integrationSplitTargets: {
+ stack: [],
+ shift: 0,
+ ignoreRef: false
+ }
+ });
+ const itgs = [];
+ const igbp = this.tags.igbPath.selectAll('path').data(itgs);
+ igbp.exit().attr('class', 'exit').remove();
+ const igcp = this.tags.igcPath.selectAll('path').data(itgs);
+ igcp.exit().attr('class', 'exit').remove();
+ const igtp = this.tags.igtPath.selectAll('text').data(itgs);
+ igtp.exit().attr('class', 'exit').remove();
+ return;
+ }
+ const {
+ stack,
+ refArea,
+ refFactor,
+ shift
+ } = selectedIntegration;
+ const isDisable = _cfg.default.btnCmdIntg(this.layout);
+ const ignoreRef = _format.default.isHplcUvVisLayout(this.layout);
+ const itgs = isDisable ? [] : stack;
+ Object.assign(this, {
+ integrationSplitTargets: {
+ stack: itgs,
+ shift,
+ ignoreRef
+ }
+ });
+ const igbp = this.tags.igbPath.selectAll('path').data(itgs);
+ igbp.exit().attr('class', 'exit').remove();
+ const igcp = this.tags.igcPath.selectAll('path').data(itgs);
+ igcp.exit().attr('class', 'exit').remove();
+ const igtp = this.tags.igtPath.selectAll('text').data(itgs);
+ igtp.exit().attr('class', 'exit').remove();
+ if (itgs.length === 0 || isDisable) {
+ // remove drawn area under curve
+ const auc = this.tags.aucPath.selectAll('path').data(stack);
+ auc.exit().attr('class', 'exit').remove();
+ auc.merge(auc);
+ return;
+ }
+ if (ignoreRef) {
+ this.drawAUC(stack, shift);
+ } else {
+ // rescale for zoom
+ const {
+ xt
+ } = (0, _compass.TfRescale)(this);
+ const dh = 50;
+ const integBar = data => d3.line()([[xt(data.xL - shift), dh], [xt(data.xL - shift), dh - 10], [xt(data.xL - shift), dh - 5], [xt(data.xU - shift), dh - 5], [xt(data.xU - shift), dh - 10], [xt(data.xU - shift), dh]]);
+ igbp.enter().append('path').attr('class', 'igbp').attr('fill', 'none').attr('stroke', '#228B22').attr('stroke-width', 2).merge(igbp).attr('id', d => `igbp${(0, _focus.itgIdTag)(d)}`).attr('d', d => integBar(d)).on('mouseover', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ const integCurve = border => {
+ const {
+ xL,
+ xU
+ } = border;
+ const [nXL, nXU] = [xL - shift, xU - shift];
+ const ps = this.data.filter(d => d.x > nXL && d.x < nXU);
+ const kMax = this.data[this.data.length - 1].k;
+ if (!ps[0]) return null;
+ const kRef = ps[0].k;
+ if (!this.reverseXAxis(this.layout)) {
+ return d3.line().x(d => xt(d.x)).y(d => 100 - (kRef - d.k) * 400 / kMax)(ps);
+ }
+ return d3.line().x(d => xt(d.x)).y(d => 300 - (d.k - kRef) * 400 / kMax)(ps);
+ };
+ igcp.enter().append('path').attr('class', 'igcp').attr('fill', 'none').attr('stroke', '#228B22').attr('stroke-width', 2).merge(igcp).attr('id', d => `igbc${(0, _focus.itgIdTag)(d)}`).attr('d', d => integCurve(d)).on('mouseover', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ 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) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', 'blue');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', 'blue');
+ }).on('mouseout', (event, d) => {
+ d3.select(`#igbp${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igbc${(0, _focus.itgIdTag)(d)}`).attr('stroke', '#228B22');
+ d3.select(`#igtp${(0, _focus.itgIdTag)(d)}`).style('fill', '#228B22');
+ this.clearSplitPreview();
+ }).on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef)).on('click', (event, d) => this.onClickIntegrationTarget(event, d));
+ }
+ }
+ drawMtply(mtplySt) {
+ const {
+ sameXY,
+ sameLySt,
+ sameMySt
+ } = this.shouldUpdate;
+ if (sameXY && sameLySt && sameMySt) return;
+ const {
+ multiplicities
+ } = mtplySt;
+ const selectedMulti = multiplicities[this.jcampIdx];
+ if (selectedMulti === false || selectedMulti === undefined) {
+ const mpys = [];
+ const mpyb = this.tags.mpybPath.selectAll('path').data(mpys);
+ mpyb.exit().attr('class', 'exit').remove();
+ const mpyt1 = this.tags.mpyt1Path.selectAll('text').data(mpys);
+ mpyt1.exit().attr('class', 'exit').remove();
+ const mpyt2 = this.tags.mpyt2Path.selectAll('text').data(mpys);
+ mpyt2.exit().attr('class', 'exit').remove();
+ let mPeaks = mpys.map(m => {
+ const {
+ peaks,
+ xExtent
+ } = m;
+ return peaks.map(p => Object.assign({}, p, {
+ xExtent
+ }));
+ });
+ mPeaks = [].concat(...mPeaks);
+ const mpyp = this.tags.mpypPath.selectAll('path').data(mPeaks);
+ mpyp.exit().attr('class', 'exit').remove();
+ return;
+ }
+ const {
+ stack,
+ smExtext,
+ shift
+ } = selectedMulti;
+ const mpys = stack;
+ const isDisable = _cfg.default.btnCmdMpy(this.layout);
+ if (mpys === 0 || isDisable) return;
+ // rescale for zoom
+ const {
+ xt
+ } = (0, _compass.TfRescale)(this);
+ const mpyb = this.tags.mpybPath.selectAll('path').data(mpys);
+ mpyb.exit().attr('class', 'exit').remove();
+ const mpyt1 = this.tags.mpyt1Path.selectAll('text').data(mpys);
+ mpyt1.exit().attr('class', 'exit').remove();
+ const mpyt2 = this.tags.mpyt2Path.selectAll('text').data(mpys);
+ mpyt2.exit().attr('class', 'exit').remove();
+ let mPeaks = mpys.map(m => {
+ const {
+ peaks,
+ xExtent
+ } = m;
+ return peaks.map(p => Object.assign({}, p, {
+ xExtent
+ }));
+ });
+ mPeaks = [].concat(...mPeaks);
+ const mpyp = this.tags.mpypPath.selectAll('path').data(mPeaks);
+ mpyp.exit().attr('class', 'exit').remove();
+ const height = this.h;
+ const dh = Math.abs(0.06 * height);
+ const mpyBar = data => d3.line()([[xt(data.xExtent.xL - shift), height - dh], [xt(data.xExtent.xL - shift), height - dh - 10], [xt(data.xExtent.xL - shift), height - dh - 5], [xt(data.xExtent.xU - shift), height - dh - 5], [xt(data.xExtent.xU - shift), height - dh - 10], [xt(data.xExtent.xU - shift), height - dh]]);
+ const mpyColor = d => {
+ const {
+ xL,
+ xU
+ } = d.xExtent;
+ return smExtext.xL === xL && smExtext.xU === xU ? 'purple' : '#DA70D6';
+ };
+ 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) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ mpyt1.enter().append('text').attr('class', 'mpyt1').attr('font-family', 'Helvetica').style('font-size', '12px').style('text-anchor', 'middle').merge(mpyt1).attr('fill', d => mpyColor(d)).attr('id', d => `mpyt1${(0, _focus.mpyIdTag)(d)}`).text(d => `${(0, _multiplicity_calc.calcMpyCenter)(d.peaks, shift, d.mpyType).toFixed(3)}`).attr('transform', d => `translate(${xt((d.xExtent.xL + d.xExtent.xU) / 2 - shift)}, ${height - dh + 12})`).on('mouseover', (event, d) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ mpyt2.enter().append('text').attr('class', 'mpyt2').attr('font-family', 'Helvetica').style('font-size', '12px').style('text-anchor', 'middle').merge(mpyt2).attr('fill', d => mpyColor(d)).attr('id', d => `mpyt2${(0, _focus.mpyIdTag)(d)}`).text(d => `(${d.mpyType})`).attr('transform', d => `translate(${xt((d.xExtent.xL + d.xExtent.xU) / 2 - shift)}, ${height - dh + 24})`).on('mouseover', (event, d) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ const mpypH = height - dh;
+ const mpypPath = pk => [{
+ x: xt(pk.x - shift) - 0.5,
+ y: mpypH - 5
+ }, {
+ x: xt(pk.x - shift) - 0.5,
+ y: mpypH - 20
+ }, {
+ x: xt(pk.x - shift) + 0.5,
+ y: mpypH - 20
+ }, {
+ x: xt(pk.x - shift) + 0.5,
+ y: mpypH - 5
+ }];
+ // const faktor = layoutSt === LIST_LAYOUT.IR ? -1 : 1;
+ const lineSymbol = d3.line().x(d => d.x).y(d => d.y);
+ mpyp.enter().append('path').attr('class', 'mpyp').attr('fill', 'none').merge(mpyp).attr('stroke', d => mpyColor(d)).attr('d', d => lineSymbol(mpypPath(d))).attr('id', d => `mpyp${(0, _focus.mpyIdTag)(d)}`).on('mouseover', (event, d) => {
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', 'blue');
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', 'blue');
+ }).on('mouseout', (event, d) => {
+ const dColor = mpyColor(d);
+ d3.selectAll(`#mpyb${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ d3.selectAll(`#mpyt1${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyt2${(0, _focus.mpyIdTag)(d)}`).style('fill', dColor);
+ d3.selectAll(`#mpyp${(0, _focus.mpyIdTag)(d)}`).attr('stroke', dColor);
+ }).on('click', (event, d) => this.onClickTarget(event, d));
+ }
+ drawRef() {
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ const ccp = this.ref.selectAll('path').data(this.tSfPeaks);
+ ccp.exit().attr('class', 'exit').remove();
+ const linePath = [{
+ x: -0.5,
+ y: 10
+ }, {
+ x: -4,
+ y: -20
+ }, {
+ x: 4,
+ y: -20
+ }, {
+ x: 0.5,
+ y: 10
+ }];
+ const faktor = _format.default.isIrLayout(this.layout) ? -1 : 1;
+ const lineSymbol = d3.line().x(d => d.x).y(d => faktor * d.y)(linePath);
+ ccp.enter().append('path').attr('d', lineSymbol).attr('class', 'enter-ref').attr('fill', 'green').attr('fill-opacity', 0.8).merge(ccp).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y)})`);
+ }
+ reverseXAxis(layoutSt) {
+ return [_list_layout.LIST_LAYOUT.UVVIS, _list_layout.LIST_LAYOUT.HPLC_UVVIS, _list_layout.LIST_LAYOUT.TGA, _list_layout.LIST_LAYOUT.DSC, _list_layout.LIST_LAYOUT.XRD, _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY, _list_layout.LIST_LAYOUT.CDS, _list_layout.LIST_LAYOUT.SEC, _list_layout.LIST_LAYOUT.GC, _list_layout.LIST_LAYOUT.AIF].indexOf(layoutSt) < 0;
+ }
+ create({
+ curveSt,
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt
+ }) {
+ this.svg = d3.select(this.rootKlass).select('.d3Svg');
+ (0, _mount.MountMainFrame)(this, 'focus');
+ (0, _mount.MountClip)(this);
+ const {
+ curveIdx,
+ isShowAllCurve
+ } = curveSt;
+ const jcampIdx = curveIdx;
+ this.isShowAllCurves = isShowAllCurve;
+ this.root = d3.select(this.rootKlass).selectAll('.focus-main');
+ this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt));
+ this.setTip();
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx);
+ Object.assign(this, {
+ isUiSplitIntgSt
+ });
+ if (!isUiSplitIntgSt) this.clearSplitPreview();
+ (0, _compass.MountCompass)(this);
+ this.axis = (0, _mount.MountAxis)(this);
+ this.path = (0, _mount.MountPath)(this, this.pathColor);
+ [this.thresLineUp, this.thresLineDw] = (0, _mount.MountThresLine)(this, 'green');
+ this.grid = (0, _mount.MountGrid)(this);
+ this.tags = (0, _mount.MountTags)(this);
+ this.ref = (0, _mount.MountRef)(this);
+ (0, _mount.MountAxisLabelX)(this);
+ (0, _mount.MountAxisLabelY)(this);
+ if (this.data && this.data.length > 0) {
+ this.setConfig(sweepExtentSt);
+ this.drawLine();
+ this.drawThres();
+ this.drawGrid();
+ this.drawOtherLines(layoutSt);
+ this.drawPeaks(editPeakSt);
+ this.drawRef();
+ this.drawPeckers();
+ this.drawInteg(integationSt);
+ this.drawMtply(mtplySt);
+ }
+ (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt);
+ this.resetShouldUpdate(editPeakSt);
+ }
+ update({
+ entities,
+ curveSt,
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ editPeakSt,
+ layoutSt,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiNoBrushSt,
+ cyclicvoltaSt,
+ integationSt,
+ mtplySt
+ }) {
+ this.root = d3.select(this.rootKlass).selectAll('.focus-main');
+ this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt));
+ const {
+ curveIdx,
+ isShowAllCurve
+ } = curveSt;
+ const jcampIdx = curveIdx;
+ this.isShowAllCurves = isShowAllCurve;
+ this.entities = entities;
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx);
+ Object.assign(this, {
+ isUiSplitIntgSt
+ });
+ if (!isUiSplitIntgSt) this.clearSplitPreview();
+ if (this.data && this.data.length > 0) {
+ this.setConfig(sweepExtentSt);
+ this.getShouldUpdate(editPeakSt);
+ this.drawLine();
+ this.drawThres();
+ this.drawGrid();
+ this.drawOtherLines(layoutSt);
+ this.drawPeaks(editPeakSt);
+ this.drawRef();
+ this.drawPeckers();
+ this.drawInteg(integationSt);
+ this.drawMtply(mtplySt);
+ }
+ (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt);
+ this.resetShouldUpdate(editPeakSt);
+ }
+}
+var _default = exports.default = MultiFocus;
\ No newline at end of file
diff --git a/dist/components/d3_rect/index.js b/dist/components/d3_rect/index.js
new file mode 100644
index 00000000..8c537de3
--- /dev/null
+++ b/dist/components/d3_rect/index.js
@@ -0,0 +1,152 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _chem = require("../../helpers/chem");
+var _manager = require("../../actions/manager");
+var _ui = require("../../actions/ui");
+var _rect_focus = _interopRequireDefault(require("./rect_focus"));
+var _draw = require("../common/draw");
+var _list_ui = require("../../constants/list_ui");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable no-mixed-operators */
+
+const W = Math.round(window.innerWidth * 0.90 * 9 / 12); // ROI
+const H = Math.round(window.innerHeight * 0.90 * 0.85); // ROI
+
+class ViewerRect extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ const {
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct
+ } = props;
+ this.rootKlass = '.d3Rect';
+ this.focus = new _rect_focus.default({
+ W,
+ H,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct
+ });
+ this.normChange = this.normChange.bind(this);
+ }
+ componentDidMount() {
+ const {
+ seed,
+ peak,
+ cLabel,
+ xLabel,
+ yLabel,
+ feature,
+ tTrEndPts,
+ tSfPeaks,
+ isHidden,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiNoBrushSt,
+ resetAllAct
+ } = this.props;
+ (0, _draw.drawDestroy)(this.rootKlass);
+ resetAllAct(feature);
+ const filterSeed = seed;
+ const filterPeak = peak;
+ (0, _draw.drawMain)(this.rootKlass, W, H);
+ this.focus.create({
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiNoBrushSt
+ });
+ (0, _draw.drawLabel)(this.rootKlass, cLabel, xLabel, yLabel);
+ (0, _draw.drawDisplay)(this.rootKlass, isHidden);
+ }
+ componentDidUpdate(prevProps) {
+ const {
+ seed,
+ peak,
+ tTrEndPts,
+ tSfPeaks,
+ isHidden,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiNoBrushSt
+ } = this.props;
+ this.normChange(prevProps);
+ const filterSeed = seed;
+ const filterPeak = peak;
+ this.focus.update({
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiNoBrushSt
+ });
+ (0, _draw.drawDisplay)(this.rootKlass, isHidden);
+ }
+ componentWillUnmount() {
+ (0, _draw.drawDestroy)(this.rootKlass);
+ }
+ normChange(prevProps) {
+ const {
+ feature,
+ resetAllAct
+ } = this.props;
+ const oldFeature = prevProps.feature;
+ if (oldFeature !== feature) {
+ resetAllAct(feature);
+ }
+ }
+ render() {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: "d3Rect"
+ });
+ }
+}
+const mapStateToProps = (state, props) => ({
+ seed: (0, _chem.Topic2Seed)(state, props),
+ peak: (0, _chem.Feature2Peak)(state, props),
+ tTrEndPts: (0, _chem.ToThresEndPts)(state, props),
+ tSfPeaks: (0, _chem.ToShiftPeaks)(state, props),
+ sweepExtentSt: state.ui.sweepExtent,
+ isUiAddIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ resetAllAct: _manager.resetAll,
+ clickUiTargetAct: _ui.clickUiTarget,
+ selectUiSweepAct: _ui.selectUiSweep,
+ scrollUiWheelAct: _ui.scrollUiWheel
+}, dispatch);
+ViewerRect.propTypes = {
+ seed: _propTypes.default.array.isRequired,
+ peak: _propTypes.default.array.isRequired,
+ cLabel: _propTypes.default.string.isRequired,
+ xLabel: _propTypes.default.string.isRequired,
+ yLabel: _propTypes.default.string.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ tTrEndPts: _propTypes.default.array.isRequired,
+ tSfPeaks: _propTypes.default.array.isRequired,
+ sweepExtentSt: _propTypes.default.object.isRequired,
+ isUiAddIntgSt: _propTypes.default.bool.isRequired,
+ isUiNoBrushSt: _propTypes.default.bool.isRequired,
+ resetAllAct: _propTypes.default.func.isRequired,
+ clickUiTargetAct: _propTypes.default.func.isRequired,
+ selectUiSweepAct: _propTypes.default.func.isRequired,
+ scrollUiWheelAct: _propTypes.default.func.isRequired,
+ isHidden: _propTypes.default.bool.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)(ViewerRect);
\ No newline at end of file
diff --git a/dist/components/d3_rect/rect_focus.js b/dist/components/d3_rect/rect_focus.js
new file mode 100644
index 00000000..e9bb0ff5
--- /dev/null
+++ b/dist/components/d3_rect/rect_focus.js
@@ -0,0 +1,225 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _init = require("../../helpers/init");
+var _brush = _interopRequireDefault(require("../../helpers/brush"));
+var _mount = require("../../helpers/mount");
+var _compass = require("../../helpers/compass");
+var _converter = require("../../helpers/converter");
+var _list_layout = require("../../constants/list_layout");
+const d3 = require('d3');
+class RectFocus {
+ constructor(props) {
+ const {
+ W,
+ H,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct
+ } = props;
+ this.rootKlass = '.d3Rect';
+ this.margin = {
+ t: 5,
+ b: 40,
+ l: 60,
+ r: 5
+ };
+ this.w = W - this.margin.l - this.margin.r;
+ this.h = H - this.margin.t - this.margin.b;
+ this.clickUiTargetAct = clickUiTargetAct;
+ this.selectUiSweepAct = selectUiSweepAct;
+ this.scrollUiWheelAct = scrollUiWheelAct;
+ this.brush = d3.brush();
+ this.axis = null;
+ this.thresLine = null;
+ this.grid = null;
+ this.ref = null;
+ this.ccPattern = null;
+ this.data = [];
+ this.dataPks = [];
+ this.tTrEndPts = null;
+ this.tSfPeaks = null;
+ this.root = null;
+ this.svg = null;
+ this.bars = null;
+ this.scales = (0, _init.InitScale)(this, false);
+ this.axisCall = (0, _init.InitAxisCall)(5);
+ this.pathCall = null;
+ this.tip = null;
+ this.factor = 0.125;
+ this.currentExtent = null;
+ this.layout = _list_layout.LIST_LAYOUT.MS;
+ this.isUiAddIntgSt = false;
+ this.firstIntegrationPoint = null;
+ this.setTip = this.setTip.bind(this);
+ this.setDataParams = this.setDataParams.bind(this);
+ this.create = this.create.bind(this);
+ this.update = this.update.bind(this);
+ this.setConfig = this.setConfig.bind(this);
+ this.drawBar = this.drawBar.bind(this);
+ this.drawThres = this.drawThres.bind(this);
+ this.drawGrid = this.drawGrid.bind(this);
+ this.mergedPeaks = this.mergedPeaks.bind(this);
+ this.isFirefox = typeof InstallTrigger !== 'undefined';
+ }
+ setTip() {
+ this.tip = (0, _init.InitTip)();
+ this.root.call(this.tip);
+ }
+ setDataParams(data, peaks, tTrEndPts, tSfPeaks) {
+ this.data = [...data];
+ this.dataPks = [...peaks];
+ this.tTrEndPts = tTrEndPts;
+ this.tSfPeaks = tSfPeaks;
+ }
+ updatePathCall(xt, yt) {
+ this.pathCall = d3.line().x(d => xt(d.x)).y(d => yt(d.y));
+ }
+ setConfig(sweepExtentSt) {
+ // Domain Calculate
+ let {
+ xExtent,
+ yExtent
+ } = sweepExtentSt || {
+ xExtent: false,
+ yExtent: false
+ };
+ if (!xExtent || !yExtent) {
+ const xes = d3.extent(this.data, d => d.x).sort((a, b) => a - b);
+ xExtent = {
+ xL: xes[0] - 10,
+ xU: xes[1] + 10
+ };
+ const btm = 0; // MS baseline is always 0.
+ const top = d3.max(this.data, d => d.y);
+ const height = top - btm;
+ yExtent = {
+ yL: btm - this.factor * height,
+ yU: top + this.factor * height
+ };
+ }
+ this.scales.x.domain([xExtent.xL, xExtent.xU]);
+ this.scales.y.domain([yExtent.yL, yExtent.yU]);
+
+ // rescale for zoom
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+
+ // Axis Call
+ this.axisCall.x.scale(xt);
+ this.axisCall.y.scale(yt);
+ this.currentExtent = {
+ xExtent,
+ yExtent
+ };
+ }
+ posHeight(gnd, val) {
+ const h = gnd - val;
+ return h >= 0 ? h : 0;
+ }
+ barColor(y, yRef) {
+ return y >= yRef ? 'steelblue' : '#aaa';
+ }
+ drawBar() {
+ const {
+ xt,
+ yt
+ } = (0, _compass.TfRescale)(this);
+ this.updatePathCall(xt, yt);
+ const yRef = this.tTrEndPts[0].y;
+ const bars = this.bars.selectAll('rect').data(this.data);
+ bars.exit().attr('class', 'exit').remove();
+ const gnd = yt(0);
+ bars.enter().append('rect').attr('class', 'enter-bar').attr('width', 1.5).merge(bars).attr('fill', d => this.barColor(d.y, yRef)).attr('height', d => this.posHeight(gnd, yt(d.y))).attr('id', d => `mpp${Math.round(1000 * d.x)}`).attr('transform', d => `translate(${xt(d.x)}, ${yt(d.y)})`).on('mouseover', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '1.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'blue');
+ const tipParams = {
+ d,
+ layout: this.layout
+ };
+ this.tip.show(tipParams, event.target);
+ }).on('mouseout', (event, d) => {
+ d3.select(`#mpp${Math.round(1000 * d.x)}`).attr('stroke-opacity', '1.0');
+ d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'red');
+ const tipParams = {
+ d,
+ layout: this.layout
+ };
+ this.tip.hide(tipParams, event.target);
+ });
+ }
+ drawThres() {
+ if (this.tTrEndPts.length > 0) {
+ this.thresLine.attr('d', this.pathCall(this.tTrEndPts));
+ this.thresLine.attr('visibility', 'visible');
+ } else {
+ this.thresLine.attr('visibility', 'hidden');
+ }
+ }
+ drawGrid() {
+ this.grid.x.call(this.axisCall.x.tickSize(-this.h, 0, 0)).selectAll('line').attr('stroke', '#ddd').attr('stroke-opacity', 0.6).attr('fill', 'none');
+ this.grid.y.call(this.axisCall.y.tickSize(-this.w, 0, 0)).selectAll('line').attr('stroke', '#ddd').attr('stroke-opacity', 0.6).attr('fill', 'none');
+ }
+ mergedPeaks(editPeakSt) {
+ if (!editPeakSt) return this.dataPks;
+ this.dataPks = (0, _converter.PksEdit)(this.dataPks, editPeakSt);
+ return this.dataPks;
+ }
+ create({
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiNoBrushSt
+ }) {
+ this.svg = d3.select('.d3Svg');
+ (0, _mount.MountMainFrame)(this, 'focus');
+ (0, _mount.MountClip)(this);
+ this.root = d3.select(this.rootKlass).selectAll('.focus-main');
+ this.setTip();
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks);
+ (0, _compass.MountCompass)(this);
+ this.axis = (0, _mount.MountAxis)(this);
+ [this.thresLine] = (0, _mount.MountThresLine)(this, 'green');
+ this.grid = (0, _mount.MountGrid)(this);
+ this.ref = (0, _mount.MountRef)(this);
+ this.bars = (0, _mount.MountBars)(this);
+ (0, _mount.MountAxisLabelX)(this);
+ (0, _mount.MountAxisLabelY)(this);
+ if (this.data && this.data.length > 0) {
+ this.setConfig(sweepExtentSt);
+ this.drawBar();
+ this.drawThres();
+ this.drawGrid();
+ }
+ (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt);
+ }
+ update({
+ filterSeed,
+ filterPeak,
+ tTrEndPts,
+ tSfPeaks,
+ sweepExtentSt,
+ isUiAddIntgSt,
+ isUiNoBrushSt
+ }) {
+ this.root = d3.select(this.rootKlass).selectAll('.focus-main');
+ this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks);
+ if (this.data && this.data.length > 0) {
+ this.setConfig(sweepExtentSt);
+ this.drawBar();
+ this.drawThres();
+ this.drawGrid();
+ }
+ (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt);
+ }
+}
+var _default = exports.default = RectFocus;
\ No newline at end of file
diff --git a/dist/components/forecast/comps.js b/dist/components/forecast/comps.js
new file mode 100644
index 00000000..263de551
--- /dev/null
+++ b/dist/components/forecast/comps.js
@@ -0,0 +1,239 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.sectionSvg = exports.sectionInput = exports.notToRenderAnalysis = exports.TxtLabel = exports.StatusIcon = exports.ConfidenceLabel = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactSvgFileZoomPan = _interopRequireDefault(require("@complat/react-svg-file-zoom-pan"));
+var _CheckCircleOutline = _interopRequireDefault(require("@mui/icons-material/CheckCircleOutline"));
+var _ErrorOutline = _interopRequireDefault(require("@mui/icons-material/ErrorOutline"));
+var _HighlightOff = _interopRequireDefault(require("@mui/icons-material/HighlightOff"));
+var _HelpOutline = _interopRequireDefault(require("@mui/icons-material/HelpOutline"));
+var _Help = _interopRequireDefault(require("@mui/icons-material/Help"));
+var _material = require("@mui/material");
+var _CloudOff = _interopRequireDefault(require("@mui/icons-material/CloudOff"));
+var _section_loading = _interopRequireDefault(require("./section_loading"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/function-component-definition, react/destructuring-assignment,
+max-len */
+
+const titleStyle = {
+ backgroundColor: '#f5f5f5',
+ border: '2px solid #e3e3e3',
+ borderRadius: '10px',
+ lineHeight: '200px',
+ marginBottom: 10,
+ marginTop: 10,
+ marginLeft: 40,
+ textAlign: 'center',
+ width: '70%'
+};
+const txtStyle = {
+ lineHeight: '20px'
+};
+const TxtLabel = (classes, label, extClsName = 'txt-label') => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtLabel, extClsName),
+ children: label
+});
+exports.TxtLabel = TxtLabel;
+const StatusIcon = status => {
+ switch (status) {
+ case 'accept':
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Accept"
+ }),
+ placement: "left",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CheckCircleOutline.default, {
+ style: {
+ color: '#4caf50'
+ }
+ })
+ });
+ case 'warning':
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Warning"
+ }),
+ placement: "left",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ErrorOutline.default, {
+ style: {
+ color: '#ffc107'
+ }
+ })
+ });
+ case 'reject':
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Reject"
+ }),
+ placement: "left",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightOff.default, {
+ style: {
+ color: '#e91e63'
+ }
+ })
+ });
+ case 'missing':
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Missing"
+ }),
+ placement: "left",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_HelpOutline.default, {
+ style: {
+ color: '#5d4037'
+ }
+ })
+ });
+ case 'unknown':
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Not Support"
+ }),
+ placement: "left",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Help.default, {
+ style: {
+ color: '#5d4037'
+ }
+ })
+ });
+ default:
+ return null;
+ }
+};
+exports.StatusIcon = StatusIcon;
+const ConfidenceLabel = (classes, confidence, extClsName = 'txt-label') => {
+ if (!confidence) return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: " - - "
+ });
+ const confidenceDp = parseFloat(Math.round(confidence * 100) / 100).toFixed(2);
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtLabel, extClsName),
+ children: `${confidenceDp} %`
+ });
+};
+exports.ConfidenceLabel = ConfidenceLabel;
+const sectionInput = (classes, molecule, inputFuncCb) => {
+ if (!inputFuncCb) return null;
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.inputRoot),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ container: true,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ item: true,
+ xs: 6,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TextField, {
+ fullWidth: true,
+ label: TxtLabel(classes, 'Molfile', 'txt-mol-label'),
+ margin: "normal",
+ multiline: true,
+ onChange: inputFuncCb,
+ rows: "2",
+ variant: "outlined",
+ value: molecule
+ })
+ })
+ })
+ });
+};
+exports.sectionInput = sectionInput;
+const SectionRunning = () => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ style: titleStyle,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("h2", {
+ style: txtStyle,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.CircularProgress, {
+ style: {
+ color: 'blue',
+ fontSize: 50
+ }
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ children: "The server is making predictions..."
+ })]
+ })
+});
+const SectionMissMatch = () => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ style: titleStyle,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("h2", {
+ style: txtStyle,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ErrorOutline.default, {
+ style: {
+ color: 'red',
+ fontSize: 50
+ }
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ className: "txt-predict-fail",
+ children: "Peak & Element count mismatch!"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("p", {
+ className: "txt-predict-fail",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "1"
+ }), "H multiplicity count should not be more than the proton group count. Multiplicity must be assigned manulally before predictions."]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("p", {
+ className: "txt-predict-fail",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
+ children: "13"
+ }), "C peak count should not be more than the carbon count, and solvent peaks should be excluded."]
+ })]
+ })
+});
+const SectionNoService = () => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ style: titleStyle,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("h2", {
+ style: txtStyle,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_CloudOff.default, {
+ style: {
+ color: 'red',
+ fontSize: 50
+ }
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ children: "Service is not available."
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ children: "Please try it again later."
+ })]
+ })
+});
+const SectionUnknown = () => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ style: titleStyle,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("h2", {
+ style: txtStyle,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_HelpOutline.default, {
+ style: {
+ color: 'purple',
+ fontSize: 50
+ }
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ children: "Unknown state."
+ })]
+ })
+});
+const notToRenderAnalysis = pds => {
+ if (pds.running) return /*#__PURE__*/(0, _jsxRuntime.jsx)(SectionRunning, {});
+ if (!pds.outline || !pds.outline.code) return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {});
+ if (pds.outline.code >= 500) return /*#__PURE__*/(0, _jsxRuntime.jsx)(SectionNoService, {});
+ if (pds.outline.code === 400) return /*#__PURE__*/(0, _jsxRuntime.jsx)(SectionMissMatch, {});
+ if (pds.outline.code >= 300) return /*#__PURE__*/(0, _jsxRuntime.jsx)(SectionUnknown, {});
+ return false;
+};
+exports.notToRenderAnalysis = notToRenderAnalysis;
+const sectionSvg = (classes, predictions) => {
+ const renderMsg = notToRenderAnalysis(predictions);
+ if (renderMsg) return null;
+ if (!predictions.output) return null;
+ const targetSvg = predictions.output.result[0].svgs[0];
+ if (!targetSvg) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_section_loading.default, {});
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactSvgFileZoomPan.default, {
+ svg: targetSvg,
+ duration: 300,
+ resize: true
+ });
+};
+exports.sectionSvg = sectionSvg;
\ No newline at end of file
diff --git a/dist/components/forecast/ir_comps.js b/dist/components/forecast/ir_comps.js
new file mode 100644
index 00000000..0b432458
--- /dev/null
+++ b/dist/components/forecast/ir_comps.js
@@ -0,0 +1,152 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.IrTableHeader = exports.IrTableBodyRow = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _material = require("@mui/material");
+var _CheckCircleOutline = _interopRequireDefault(require("@mui/icons-material/CheckCircleOutline"));
+var _HighlightOff = _interopRequireDefault(require("@mui/icons-material/HighlightOff"));
+var _comps = require("./comps");
+var _forecast = require("../../actions/forecast");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/function-component-definition, function-paren-newline,
+prefer-object-spread */
+
+// import SmaToSvg from '../common/chem';
+const baseSelectIrStatus = ({
+ sma,
+ status,
+ identity,
+ setIrStatusAct
+}) => {
+ const theStatus = ['accept', 'reject'].includes(status) ? status : '';
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControl, {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, {
+ value: theStatus,
+ onChange: e => {
+ setIrStatusAct({
+ predictions: {
+ sma,
+ identity,
+ value: e.target.value
+ },
+ svgs: []
+ });
+ },
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: "accept",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CheckCircleOutline.default, {
+ style: {
+ color: '#4caf50'
+ }
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: "reject",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightOff.default, {
+ style: {
+ color: '#e91e63'
+ }
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: "",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {})
+ })]
+ })
+ });
+};
+const bssMapStateToProps = (state, props) => (
+// eslint-disable-line
+{});
+const bssMapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setIrStatusAct: _forecast.setIrStatus
+}, dispatch);
+baseSelectIrStatus.propTypes = {
+ sma: _propTypes.default.string.isRequired,
+ status: _propTypes.default.string,
+ identity: _propTypes.default.string.isRequired,
+ setIrStatusAct: _propTypes.default.func.isRequired
+};
+baseSelectIrStatus.defaultProps = {
+ status: ''
+};
+const SelectIrStatus = (0, _reactRedux.connect)(bssMapStateToProps, bssMapDispatchToProps)(baseSelectIrStatus);
+const IrTableHeader = classes => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableHead, {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ children: (0, _comps.TxtLabel)(classes, 'FG SMARTS', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Machine Confidence', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Machine', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Owner', 'txt-prd-table-title')
+ })]
+ })
+});
+exports.IrTableHeader = IrTableHeader;
+const colorStyles = [{
+ backgroundColor: '#FFFF00'
+}, {
+ backgroundColor: '#87CEFA'
+}, {
+ backgroundColor: '#FFB6C1'
+}, {
+ backgroundColor: '#00FF00'
+}, {
+ backgroundColor: '#E6E6FA'
+}, {
+ backgroundColor: '#FFD700'
+}, {
+ backgroundColor: '#F0FFFF'
+}, {
+ backgroundColor: '#F5F5DC'
+}];
+const colorLabel = (classes, idx, extClsName = 'txt-label') => {
+ const style = Object.assign({}, colorStyles[idx % 8], {
+ width: 20,
+ borderRadius: 20,
+ textAlign: 'center'
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ style: style,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtLabel, extClsName),
+ children: idx + 1
+ })
+ });
+};
+const IrTableBodyRow = (classes, idx, fg) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ component: "th",
+ scope: "row",
+ children: colorLabel(classes, idx)
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ children: (0, _comps.TxtLabel)(classes, fg.sma, 'txt-prd-table-content')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.ConfidenceLabel)(classes, fg.confidence, 'txt-prd-table-content')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.StatusIcon)(fg.status)
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(SelectIrStatus, {
+ sma: fg.sma,
+ status: fg.statusOwner,
+ identity: "Owner"
+ })
+ })]
+}, `${idx}-${fg.name}`);
+exports.IrTableBodyRow = IrTableBodyRow;
\ No newline at end of file
diff --git a/dist/components/forecast/ir_viewer.js b/dist/components/forecast/ir_viewer.js
new file mode 100644
index 00000000..e1d9f482
--- /dev/null
+++ b/dist/components/forecast/ir_viewer.js
@@ -0,0 +1,117 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _styles = require("@mui/styles");
+var _material = require("@mui/material");
+var _comps = require("./comps");
+var _ir_comps = require("./ir_comps");
+var _jsxRuntime = require("react/jsx-runtime");
+const Styles = () => ({
+ root: {
+ overflowX: 'hidden',
+ overflowY: 'auto'
+ },
+ container: {
+ minHeight: '400px'
+ },
+ svgRoot: {
+ margin: '10px 40px 0px 40px',
+ height: 'calc(70vh)',
+ overflowY: 'hidden'
+ },
+ tableRoot: {
+ margin: '10px 40px 0px 40px',
+ maxHeight: 'calc(70vh)',
+ overflowY: 'scroll'
+ },
+ title: {
+ textAlign: 'left'
+ },
+ btn: {
+ marginLeft: 40
+ },
+ reference: {
+ borderTop: '1px solid #cfd8dc',
+ margin: '10px 40px 0px 40px',
+ padding: 5
+ },
+ inputRoot: {
+ margin: '10px 40px 0px 40px'
+ },
+ txtLabel: {
+ fontSize: '12px'
+ },
+ submit: {
+ margin: '0 0 0 30px',
+ width: 300
+ }
+});
+const sectionTable = (classes, pds) => {
+ const renderMsg = (0, _comps.notToRenderAnalysis)(pds);
+ if (renderMsg) return renderMsg;
+ if (!pds.output.result || !pds.output.result[0]) return null;
+ const {
+ fgs
+ } = pds.output.result[0];
+ if (!fgs) return null;
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Paper, {
+ className: classes.tableRoot,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Table, {
+ className: classes.table,
+ size: "small",
+ children: [(0, _ir_comps.IrTableHeader)(classes), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableBody, {
+ children: fgs.sort((a, b) => b.confidence - a.confidence).map((fg, idx) => (0, _ir_comps.IrTableBodyRow)(classes, idx, fg))
+ })]
+ })
+ });
+};
+const IrViewer = ({
+ // eslint-disable-line
+ classes,
+ molecule,
+ inputCb,
+ forecastSt
+}) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.root, 'card-forecast-viewer'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Grid, {
+ className: (0, _classnames.default)(classes.container),
+ container: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ item: true,
+ xs: 4,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Paper, {
+ className: classes.svgRoot,
+ children: (0, _comps.sectionSvg)(classes, forecastSt.predictions)
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ item: true,
+ xs: 8,
+ children: sectionTable(classes, forecastSt.predictions)
+ })]
+ }), (0, _comps.sectionInput)(classes, molecule, inputCb)]
+});
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ forecastSt: state.forecast
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+IrViewer.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ molecule: _propTypes.default.string.isRequired,
+ inputCb: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.bool]),
+ forecastSt: _propTypes.default.object.isRequired
+};
+IrViewer.defaultProps = {
+ inputCb: false
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(Styles))(IrViewer);
\ No newline at end of file
diff --git a/dist/components/forecast/nmr_comps.js b/dist/components/forecast/nmr_comps.js
new file mode 100644
index 00000000..3ce7da6d
--- /dev/null
+++ b/dist/components/forecast/nmr_comps.js
@@ -0,0 +1,156 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SectionReference = exports.NmrTableHeader = exports.NmrTableBodyRow = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _CheckCircleOutline = _interopRequireDefault(require("@mui/icons-material/CheckCircleOutline"));
+var _HighlightOff = _interopRequireDefault(require("@mui/icons-material/HighlightOff"));
+var _comps = require("./comps");
+var _forecast = require("../../actions/forecast");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/function-component-definition, react/destructuring-assignment */
+
+const baseSelectNmrStatus = ({
+ // eslint-disable-line
+ idx,
+ atom,
+ status,
+ identity,
+ setNmrStatusAct
+}) => {
+ const theStatus = ['accept', 'reject'].includes(status) ? status : '';
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControl, {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, {
+ value: theStatus,
+ onChange: e => {
+ setNmrStatusAct({
+ predictions: {
+ idx,
+ atom,
+ identity,
+ value: e.target.value
+ },
+ svgs: []
+ });
+ },
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: "accept",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CheckCircleOutline.default, {
+ style: {
+ color: '#4caf50'
+ }
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: "reject",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightOff.default, {
+ style: {
+ color: '#e91e63'
+ }
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
+ value: "",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {})
+ })]
+ })
+ });
+};
+const bssMapStateToProps = (state, props) => (
+// eslint-disable-line
+{});
+const bssMapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setNmrStatusAct: _forecast.setNmrStatus
+}, dispatch);
+baseSelectNmrStatus.propTypes = {
+ idx: _propTypes.default.number.isRequired,
+ atom: _propTypes.default.number.isRequired,
+ status: _propTypes.default.string,
+ identity: _propTypes.default.string.isRequired,
+ setNmrStatusAct: _propTypes.default.func.isRequired
+};
+baseSelectNmrStatus.defaultProps = {
+ status: ''
+};
+const SelectNmrStatus = (0, _reactRedux.connect)(
+// eslint-disable-line
+bssMapStateToProps, bssMapDispatchToProps)(baseSelectNmrStatus); // eslint-disable-line
+
+const numFormat = input => parseFloat(input).toFixed(2);
+const realFormat = (val, status) => {
+ if (status === 'missing') {
+ return '- - -';
+ }
+ return numFormat(val);
+};
+const NmrTableHeader = classes => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableHead, {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ children: (0, _comps.TxtLabel)(classes, 'Atom', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Prediction (ppm)', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Real (ppm)', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Diff (ppm)', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Machine', 'txt-prd-table-title')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, 'Owner', 'txt-prd-table-title')
+ })]
+ })
+});
+exports.NmrTableHeader = NmrTableHeader;
+const NmrTableBodyRow = (classes, row, idx) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ component: "th",
+ scope: "row",
+ children: (0, _comps.TxtLabel)(classes, row.atom, 'txt-prd-table-content')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, numFormat(row.prediction), 'txt-prd-table-content')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, realFormat(row.real, row.status), 'txt-prd-table-content')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.TxtLabel)(classes, realFormat(row.diff, row.status), 'txt-prd-table-content')
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: (0, _comps.StatusIcon)(row.status)
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(SelectNmrStatus, {
+ idx: idx,
+ atom: row.atom,
+ status: row.statusOwner,
+ identity: "Owner"
+ })
+ })]
+}, `${idx}-${row.atom}`);
+exports.NmrTableBodyRow = NmrTableBodyRow;
+const SectionReference = classes => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.reference),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("p", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: "NMR prediction source: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
+ href: "https://www.ncbi.nlm.nih.gov/pubmed/15464159",
+ target: "_blank",
+ rel: "noopener noreferrer",
+ children: "nmrshiftdb"
+ })]
+ })
+});
+exports.SectionReference = SectionReference;
\ No newline at end of file
diff --git a/dist/components/forecast/nmr_viewer.js b/dist/components/forecast/nmr_viewer.js
new file mode 100644
index 00000000..c397d56b
--- /dev/null
+++ b/dist/components/forecast/nmr_viewer.js
@@ -0,0 +1,114 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _styles = require("@mui/styles");
+var _material = require("@mui/material");
+var _comps = require("./comps");
+var _nmr_comps = require("./nmr_comps");
+var _jsxRuntime = require("react/jsx-runtime");
+const Styles = () => ({
+ root: {
+ overflowX: 'hidden',
+ overflowY: 'auto'
+ },
+ container: {
+ minHeight: '400px'
+ },
+ svgRoot: {
+ margin: '10px 40px 0px 40px',
+ height: 'calc(70vh)',
+ overflowY: 'hidden'
+ },
+ tableRoot: {
+ margin: '10px 40px 0px 40px',
+ maxHeight: 'calc(70vh)',
+ overflowY: 'scroll'
+ },
+ title: {
+ textAlign: 'left'
+ },
+ btn: {
+ marginLeft: 40
+ },
+ reference: {
+ borderTop: '1px solid #cfd8dc',
+ margin: '10px 40px 0px 40px',
+ padding: 5
+ },
+ inputRoot: {
+ margin: '10px 40px 0px 40px'
+ },
+ txtLabel: {
+ fontSize: '12px'
+ },
+ submit: {
+ margin: '0 0 0 30px',
+ width: 300
+ }
+});
+const sectionTable = (classes, pds) => {
+ const renderMsg = (0, _comps.notToRenderAnalysis)(pds);
+ if (renderMsg) return renderMsg;
+ const dict = pds.output.result[0];
+ if (!dict) return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {});
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Paper, {
+ className: classes.tableRoot,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Table, {
+ className: classes.table,
+ size: "small",
+ children: [(0, _nmr_comps.NmrTableHeader)(classes), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableBody, {
+ children: dict.shifts.sort((a, b) => a.atom - b.atom).map((row, idx) => (0, _nmr_comps.NmrTableBodyRow)(classes, row, idx))
+ })]
+ })
+ });
+};
+const NmrViewer = ({
+ // eslint-disable-line
+ classes,
+ molecule,
+ inputCb,
+ forecastSt
+}) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.root, 'card-forecast-viewer'),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Grid, {
+ className: (0, _classnames.default)(classes.container),
+ container: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ item: true,
+ xs: 4,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Paper, {
+ className: classes.svgRoot,
+ children: (0, _comps.sectionSvg)(classes, forecastSt.predictions)
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ item: true,
+ xs: 8,
+ children: sectionTable(classes, forecastSt.predictions)
+ })]
+ }), (0, _comps.sectionInput)(classes, molecule, inputCb), (0, _nmr_comps.SectionReference)(classes)]
+});
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ forecastSt: state.forecast
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+NmrViewer.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ molecule: _propTypes.default.string.isRequired,
+ inputCb: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.bool]),
+ forecastSt: _propTypes.default.object.isRequired
+};
+NmrViewer.defaultProps = {
+ inputCb: false
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(Styles))(NmrViewer);
\ No newline at end of file
diff --git a/dist/components/forecast/section_loading.js b/dist/components/forecast/section_loading.js
new file mode 100644
index 00000000..62d38f8d
--- /dev/null
+++ b/dist/components/forecast/section_loading.js
@@ -0,0 +1,62 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _CircularProgress = _interopRequireDefault(require("@mui/material/CircularProgress"));
+var _ErrorOutline = _interopRequireDefault(require("@mui/icons-material/ErrorOutline"));
+var _jsxRuntime = require("react/jsx-runtime");
+const styleLoading = {
+ alignItems: 'center',
+ display: 'flex',
+ height: '100%',
+ justifyContent: 'center'
+};
+class SectionLoading extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ loading: true
+ };
+ }
+ componentDidMount() {
+ setTimeout(() => this.setState({
+ loading: false
+ }), 5000);
+ }
+ renderLoading() {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ style: styleLoading,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {
+ style: {
+ color: 'blue',
+ fontSize: 50
+ }
+ })
+ });
+ }
+ renderNotFound() {
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ style: styleLoading,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ErrorOutline.default, {
+ style: {
+ color: '#ffc107',
+ fontSize: 50,
+ margin: 20
+ }
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("h3", {
+ children: "Structure Not Found"
+ })]
+ });
+ }
+ render() {
+ const {
+ loading
+ } = this.state;
+ return loading ? this.renderLoading() : this.renderNotFound();
+ }
+}
+var _default = exports.default = SectionLoading;
\ No newline at end of file
diff --git a/dist/components/forecast_viewer.js b/dist/components/forecast_viewer.js
new file mode 100644
index 00000000..cfce89e4
--- /dev/null
+++ b/dist/components/forecast_viewer.js
@@ -0,0 +1,149 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _styles = require("@mui/styles");
+var _index = _interopRequireDefault(require("./d3_line/index"));
+var _nmr_viewer = _interopRequireDefault(require("./forecast/nmr_viewer"));
+var _ir_viewer = _interopRequireDefault(require("./forecast/ir_viewer"));
+var _forecast = require("../actions/forecast");
+var _ui = require("../actions/ui");
+var _list_ui = require("../constants/list_ui");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/no-unused-prop-types */
+
+const styles = () => ({
+ root: {
+ flexGrow: 1
+ },
+ appBar: {
+ backgroundColor: '#fff',
+ boxShadow: 'none'
+ },
+ tabLabel: {
+ fontSize: '14px'
+ }
+});
+class ForecastViewer extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ this.initForecastReducer = this.initForecastReducer.bind(this);
+ }
+ componentDidMount() {
+ this.initForecastReducer();
+ }
+ componentDidUpdate(prevProps) {
+ const {
+ forecast
+ } = this.props;
+ const prevForecast = forecast;
+ const nextForecast = prevProps.forecast;
+ if (prevForecast !== nextForecast) {
+ this.initForecastReducer();
+ }
+ }
+ initForecastReducer() {
+ const {
+ forecast,
+ initForecastStatusAct,
+ setUiViewerTypeAct
+ } = this.props;
+ initForecastStatusAct(forecast);
+ if (forecast && forecast.predictions) {
+ const {
+ running,
+ refreshed
+ } = forecast.predictions;
+ if (running || refreshed) setUiViewerTypeAct(_list_ui.LIST_UI_VIEWER_TYPE.ANALYSIS);
+ }
+ }
+ render() {
+ const {
+ classes,
+ topic,
+ feature,
+ cLabel,
+ xLabel,
+ yLabel,
+ forecast,
+ isNmr,
+ isIr,
+ uiSt,
+ isXRD,
+ wavelength,
+ curveSt,
+ jcampSt
+ } = this.props;
+ const {
+ viewer
+ } = uiSt;
+ const {
+ inputCb,
+ molecule
+ } = forecast;
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ jcamps
+ } = jcampSt;
+ const comparisons = jcamps[curveIdx].others;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.root,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index.default, {
+ topic: topic,
+ feature: feature,
+ cLabel: cLabel,
+ xLabel: isXRD && wavelength ? `${xLabel}, WL=${wavelength.value} ${wavelength.unit}` : xLabel,
+ yLabel: yLabel,
+ comparisons: comparisons,
+ isHidden: viewer !== _list_ui.LIST_UI_VIEWER_TYPE.SPECTRUM
+ }), viewer === _list_ui.LIST_UI_VIEWER_TYPE.ANALYSIS && isNmr && /*#__PURE__*/(0, _jsxRuntime.jsx)(_nmr_viewer.default, {
+ molecule: molecule,
+ inputCb: inputCb
+ }), viewer === _list_ui.LIST_UI_VIEWER_TYPE.ANALYSIS && isIr && /*#__PURE__*/(0, _jsxRuntime.jsx)(_ir_viewer.default, {
+ molecule: molecule,
+ inputCb: inputCb
+ })]
+ });
+ }
+}
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ uiSt: state.ui,
+ jcampSt: state.jcamp,
+ wavelength: state.wavelength,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ initForecastStatusAct: _forecast.initForecastStatus,
+ setUiViewerTypeAct: _ui.setUiViewerType
+}, dispatch);
+ForecastViewer.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ topic: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ cLabel: _propTypes.default.string.isRequired,
+ xLabel: _propTypes.default.string.isRequired,
+ yLabel: _propTypes.default.string.isRequired,
+ forecast: _propTypes.default.object.isRequired,
+ isNmr: _propTypes.default.bool.isRequired,
+ isIr: _propTypes.default.bool.isRequired,
+ isUvvis: _propTypes.default.bool.isRequired,
+ isXRD: _propTypes.default.bool.isRequired,
+ uiSt: _propTypes.default.object.isRequired,
+ jcampSt: _propTypes.default.object.isRequired,
+ initForecastStatusAct: _propTypes.default.func.isRequired,
+ setUiViewerTypeAct: _propTypes.default.func.isRequired,
+ wavelength: _propTypes.default.object.isRequired,
+ curveSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(styles))(ForecastViewer);
\ No newline at end of file
diff --git a/dist/components/multi_jcamps_viewer.js b/dist/components/multi_jcamps_viewer.js
new file mode 100644
index 00000000..7f0dca3e
--- /dev/null
+++ b/dist/components/multi_jcamps_viewer.js
@@ -0,0 +1,223 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _Grid = _interopRequireDefault(require("@mui/material/Grid"));
+var _styles = require("@mui/styles");
+var _index = _interopRequireDefault(require("./panel/index"));
+var _cyclic_voltamery_data = _interopRequireDefault(require("./panel/cyclic_voltamery_data"));
+var _index2 = _interopRequireDefault(require("./cmd_bar/index"));
+var _index3 = _interopRequireDefault(require("./d3_multi/index"));
+var _curve = require("../actions/curve");
+var _cyclic_voltammetry = require("../actions/cyclic_voltammetry");
+var _list_layout = require("../constants/list_layout");
+var _format = _interopRequireDefault(require("../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/default-props-match-prop-types,
+react/require-default-props, react/no-unused-prop-types, react/jsx-boolean-value,
+prefer-object-spread */
+
+const styles = () => ({
+ root: {
+ flexGrow: 1
+ },
+ appBar: {
+ backgroundColor: '#fff',
+ boxShadow: 'none'
+ },
+ tabLabel: {
+ fontSize: '14px'
+ },
+ cvEditor: {
+ height: 'calc(90vh - 220px)',
+ display: 'flex',
+ flexDirection: 'column',
+ minHeight: 0,
+ overflow: 'hidden'
+ },
+ cvTopRow: {
+ flex: '1 1 auto',
+ minHeight: 0,
+ overflow: 'hidden'
+ },
+ cvViewerCol: {
+ height: '100%',
+ minHeight: 0,
+ display: 'flex',
+ flexDirection: 'column'
+ },
+ cvViewerWrap: {
+ flex: '1 1 auto',
+ minHeight: 0
+ },
+ cvPanelBelow: {
+ marginTop: 16,
+ width: '100%'
+ }
+});
+const seperatingSubLayout = (entities, featureCondition, layoutSt) => {
+ if (layoutSt === _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) {
+ return null;
+ }
+ const storedDict = {};
+ entities.forEach(entity => {
+ const {
+ feature
+ } = entity;
+ const keyValue = feature[featureCondition];
+ if (keyValue in storedDict) {
+ storedDict[keyValue].push(entity);
+ } else {
+ storedDict[keyValue] = [entity];
+ }
+ });
+ return Object.assign({}, storedDict);
+};
+class MultiJcampsViewer extends _react.default.Component {
+ // eslint-disable-line
+ render() {
+ const {
+ classes,
+ curveSt,
+ operations,
+ entityFileNames,
+ entities,
+ userManualLink,
+ molSvg,
+ exactMass,
+ layoutSt,
+ integrationSt,
+ descriptions,
+ canChangeDescription,
+ onDescriptionChanged
+ } = this.props;
+ if (!entities || entities.length === 0) return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {});
+ const separateCondition = _format.default.isGCLayout(layoutSt) ? 'yUnit' : 'xUnit';
+ const seperatedSubLayouts = seperatingSubLayout(entities, separateCondition, layoutSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const entity = entities[curveIdx];
+ const {
+ feature,
+ topic
+ } = entity;
+ const {
+ integrations
+ } = integrationSt;
+ const currentIntegration = integrations[curveIdx];
+ const isCyclicVolta = _format.default.isCyclicVoltaLayout(layoutSt);
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.root,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.default, {
+ feature: feature,
+ operations: operations,
+ editorOnly: true,
+ hideThreshold: !_format.default.isNmrLayout(layoutSt)
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)('react-spectrum-editor', isCyclicVolta && classes.cvEditor),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Grid.default, {
+ container: true,
+ className: isCyclicVolta ? classes.cvTopRow : undefined,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Grid.default, {
+ item: true,
+ xs: 9,
+ className: isCyclicVolta ? classes.cvViewerCol : undefined,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: isCyclicVolta ? classes.cvViewerWrap : undefined,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.default, {
+ entities: entities,
+ topic: topic,
+ xLabel: feature.xUnit,
+ yLabel: feature.yUnit,
+ feature: feature
+ })
+ }), isCyclicVolta ? /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: classes.cvPanelBelow,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_cyclic_voltamery_data.default, {
+ jcampIdx: curveIdx,
+ feature: feature,
+ userManualLink: userManualLink ? userManualLink.cv : undefined
+ })
+ }) : null]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Grid.default, {
+ item: true,
+ xs: 3,
+ align: "center",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.default, {
+ jcampIdx: curveIdx,
+ entityFileNames: entityFileNames,
+ userManualLink: userManualLink,
+ feature: feature,
+ molSvg: molSvg,
+ exactMass: exactMass,
+ subLayoutsInfo: seperatedSubLayouts,
+ integration: currentIntegration,
+ descriptions: descriptions,
+ canChangeDescription: canChangeDescription,
+ onDescriptionChanged: onDescriptionChanged,
+ hideCyclicVolta: isCyclicVolta
+ })
+ })]
+ })
+ })]
+ });
+ }
+}
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ curveSt: state.curve,
+ cyclicVoltaSt: state.cyclicvolta,
+ entities: state.curve.listCurves,
+ layoutSt: state.layout,
+ integrationSt: state.integration.present
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ setAllCurvesAct: _curve.setAllCurves,
+ addNewCylicVoltaPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak,
+ addCylicVoltaMaxPeakAct: _cyclic_voltammetry.addCylicVoltaMaxPeak,
+ addCylicVoltaMinPeakAct: _cyclic_voltammetry.addCylicVoltaMinPeak,
+ addCylicVoltaPeckerAct: _cyclic_voltammetry.addCylicVoltaPecker
+}, dispatch);
+MultiJcampsViewer.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ multiEntities: _propTypes.default.array.isRequired,
+ entityFileNames: _propTypes.default.array.isRequired,
+ molSvg: _propTypes.default.string.isRequired,
+ setAllCurvesAct: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ cyclicVoltaSt: _propTypes.default.object.isRequired,
+ addNewCylicVoltaPairPeakAct: _propTypes.default.func.isRequired,
+ addCylicVoltaMaxPeakAct: _propTypes.default.func.isRequired,
+ addCylicVoltaMinPeakAct: _propTypes.default.func.isRequired,
+ operations: _propTypes.default.func.isRequired,
+ userManualLink: _propTypes.default.object,
+ entities: _propTypes.default.array,
+ layoutSt: _propTypes.default.string.isRequired,
+ exactMass: _propTypes.default.string,
+ integrationSt: _propTypes.default.object.isRequired,
+ descriptions: _propTypes.default.array.isRequired,
+ canChangeDescription: _propTypes.default.bool.isRequired,
+ onDescriptionChanged: _propTypes.default.func
+};
+MultiJcampsViewer.defaultProps = {
+ multiEntities: [],
+ entityFileNames: [],
+ molSvg: '',
+ cLabel: '',
+ xLabel: '',
+ yLabel: '',
+ entities: [],
+ descriptions: [],
+ canChangeDescription: false
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(styles))(MultiJcampsViewer);
\ No newline at end of file
diff --git a/dist/components/panel/compare.js b/dist/components/panel/compare.js
new file mode 100644
index 00000000..391903d6
--- /dev/null
+++ b/dist/components/panel/compare.js
@@ -0,0 +1,272 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _reactDropzone = _interopRequireDefault(require("react-dropzone"));
+var _material = require("@mui/material");
+var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
+var _HighlightOff = _interopRequireDefault(require("@mui/icons-material/HighlightOff"));
+var _VisibilityOutlined = _interopRequireDefault(require("@mui/icons-material/VisibilityOutlined"));
+var _VisibilityOffOutlined = _interopRequireDefault(require("@mui/icons-material/VisibilityOffOutlined"));
+var _styles = require("@mui/styles");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jcamp = require("../../actions/jcamp");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable function-paren-newline, react/jsx-props-no-spreading,
+react/function-component-definition */
+
+const styles = theme => ({
+ panel: {
+ backgroundColor: '#eee',
+ display: 'table-row'
+ },
+ panelSummary: {
+ backgroundColor: '#eee',
+ height: 32
+ },
+ txtBadge: {},
+ panelDetail: {
+ backgroundColor: '#fff',
+ maxHeight: 'calc(90vh - 220px)',
+ // ROI
+ overflow: 'auto'
+ },
+ table: {
+ width: '100%'
+ },
+ tTxt: {
+ padding: 0
+ },
+ tTxtHide: {
+ color: '#D5D8DC'
+ },
+ tRow: {
+ height: 28,
+ '&:nth-of-type(even)': {
+ backgroundColor: theme.palette ? theme.palette.background.default : '#d3d3d3'
+ }
+ },
+ rmBtn: {
+ color: 'red',
+ padding: '0 5px 0 5px',
+ '&:hover': {
+ borderRadius: 12,
+ backgroundColor: 'red',
+ color: 'white'
+ }
+ },
+ showBtn: {
+ color: 'steelblue',
+ padding: '0 5px 0 5px',
+ '&:hover': {
+ borderRadius: 12,
+ backgroundColor: 'steelblue',
+ color: 'white'
+ }
+ },
+ hideBtn: {
+ color: 'gray',
+ padding: '0 5px 0 5px',
+ '&:hover': {
+ borderRadius: 12,
+ backgroundColor: 'gray',
+ color: 'white'
+ }
+ },
+ square: {
+ textAlign: 'center !important'
+ },
+ baseDD: {
+ backgroundColor: 'white',
+ border: '1px dashed black',
+ borderRadius: 5,
+ height: 26,
+ lineHeight: '26px',
+ margin: '7px 0 7px 0',
+ textAlign: 'center',
+ verticalAlign: 'middle',
+ width: '90%'
+ },
+ enableDD: {
+ border: '2px dashed #000',
+ color: '#000'
+ },
+ disableDD: {
+ border: '2px dashed #aaa',
+ color: '#aaa'
+ },
+ tpCard: {},
+ tpMoreTxt: {
+ padding: '0 0 0 60px'
+ },
+ tpLabel: {
+ fontSize: 16
+ }
+});
+const msgDefault = 'Add spectra to compare.';
+const tpHint = classes => /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.tpCard),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ className: (0, _classnames.default)(classes.tpLabel, 'txt-sv-tp'),
+ children: "- Accept *.dx, *.jdx, *.JCAMP,"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ className: (0, _classnames.default)(classes.tpLabel, 'txt-sv-tp'),
+ children: "- Max 5 spectra."
+ })]
+});
+const content = (classes, desc) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: tpHint(classes),
+ placement: "bottom",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tpLabel, 'txt-sv-tp'),
+ children: desc
+ })
+});
+const inputOthers = (classes, jcampSt) => {
+ const {
+ selectedIdx,
+ jcamps
+ } = jcampSt;
+ const selectedJcamp = jcamps[selectedIdx];
+ const {
+ addOthersCb
+ } = selectedJcamp;
+ const fileName = '';
+ const desc = fileName || msgDefault;
+ const onDrop = jcampFiles => {
+ if (!addOthersCb) return;
+ addOthersCb({
+ jcamps: jcampFiles
+ });
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactDropzone.default, {
+ className: "dropbox",
+ onDrop: onDrop,
+ children: ({
+ getRootProps,
+ getInputProps
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ ...getRootProps(),
+ className: (0, _classnames.default)(classes.baseDD),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
+ ...getInputProps()
+ }), content(classes, desc)]
+ })
+ });
+};
+const compareList = (classes, jcampSt, rmOthersOneAct, toggleShowAct) => {
+ const {
+ selectedIdx,
+ jcamps
+ } = jcampSt;
+ const selectedJcamp = jcamps[selectedIdx];
+ const {
+ others
+ } = selectedJcamp;
+ const rows = others.map((o, idx) => ({
+ idx,
+ title: o.spectra[0].title,
+ color: _format.default.compareColors(idx),
+ rmCb: () => rmOthersOneAct(idx),
+ isShow: o.show,
+ toggleShowCb: () => toggleShowAct(idx)
+ }));
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Table, {
+ className: classes.table,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableBody, {
+ children: rows.map(row => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ className: classes.tRow,
+ hover: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, 'txt-sv-panel-txt'),
+ style: {
+ backgroundColor: row.color
+ },
+ children: row.idx + 1
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt', row.isShow ? null : classes.tTxtHide),
+ children: row.title
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: [row.isShow ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_VisibilityOutlined.default, {
+ onClick: row.toggleShowCb,
+ className: classes.showBtn
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_VisibilityOffOutlined.default, {
+ onClick: row.toggleShowCb,
+ className: classes.hideBtn
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightOff.default, {
+ onClick: row.rmCb,
+ className: classes.rmBtn
+ })]
+ })]
+ }, row.idx))
+ })
+ });
+};
+const ComparePanel = ({
+ classes,
+ expand,
+ onExapnd,
+ jcampSt,
+ rmOthersOneAct,
+ toggleShowAct
+}) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, {
+ expanded: expand,
+ onChange: onExapnd,
+ disableGutters: true,
+ sx: {
+ '&.MuiAccordion-root.Mui-expanded': {
+ margin: 0
+ },
+ '&:before': {
+ display: 'none'
+ }
+ },
+ TransitionProps: {
+ unmountOnExit: true
+ } // increase Accordion performance
+ ,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.AccordionSummary, {
+ expandIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandMore.default, {}),
+ className: (0, _classnames.default)(classes.panelSummary),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
+ className: "txt-panel-header",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'),
+ children: "Spectra Comparisons"
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), inputOthers(classes, jcampSt), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.panelDetail),
+ children: compareList(classes, jcampSt, rmOthersOneAct, toggleShowAct)
+ })]
+});
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ jcampSt: state.jcamp
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ rmOthersOneAct: _jcamp.rmOthersOne,
+ toggleShowAct: _jcamp.toggleShow
+}, dispatch);
+ComparePanel.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ expand: _propTypes.default.bool.isRequired,
+ onExapnd: _propTypes.default.func.isRequired,
+ jcampSt: _propTypes.default.object.isRequired,
+ rmOthersOneAct: _propTypes.default.func.isRequired,
+ toggleShowAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(ComparePanel));
\ No newline at end of file
diff --git a/dist/components/panel/cyclic_voltamery_data.js b/dist/components/panel/cyclic_voltamery_data.js
new file mode 100644
index 00000000..9024bda0
--- /dev/null
+++ b/dist/components/panel/cyclic_voltamery_data.js
@@ -0,0 +1,467 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireWildcard(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _ExpandLess = _interopRequireDefault(require("@mui/icons-material/ExpandLess"));
+var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
+var _AddCircleOutline = _interopRequireDefault(require("@mui/icons-material/AddCircleOutline"));
+var _RemoveCircle = _interopRequireDefault(require("@mui/icons-material/RemoveCircle"));
+var _Info = _interopRequireDefault(require("@mui/icons-material/Info"));
+var _Help = _interopRequireDefault(require("@mui/icons-material/Help"));
+var _styles = require("@mui/styles");
+var _material = require("@mui/material");
+var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry");
+var _ui = require("../../actions/ui");
+var _list_ui = require("../../constants/list_ui");
+var _chem = require("../../helpers/chem");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
+/* eslint-disable function-paren-newline, react/require-default-props,
+react/no-unused-prop-types, react/jsx-closing-tag-location, max-len, react/jsx-one-expression-per-line,
+react/jsx-indent, react/no-unescaped-entities, react/jsx-wrap-multilines, camelcase, no-shadow,
+arrow-body-style, react/function-component-definition */
+
+const MAX_VISIBLE_ROWS = 6;
+const ROW_HEIGHT_PX = 28;
+const HEADER_HEIGHT_PX = 24;
+const EXPANDED_HEIGHT = HEADER_HEIGHT_PX + MAX_VISIBLE_ROWS * ROW_HEIGHT_PX;
+const styles = () => ({
+ panel: {
+ backgroundColor: '#f7f7f7',
+ border: '1px solid #e6e6e6',
+ borderRadius: 8,
+ overflow: 'hidden'
+ },
+ panelHeader: {
+ backgroundColor: '#eee',
+ padding: '4px 8px',
+ display: 'flex',
+ alignItems: 'center'
+ },
+ panelActions: {
+ marginLeft: 'auto',
+ display: 'flex',
+ alignItems: 'center',
+ gap: 8
+ },
+ howToWrap: {
+ display: 'inline-flex',
+ alignItems: 'center',
+ gap: 4
+ },
+ toggleBtn: {
+ padding: 0
+ },
+ table: {
+ width: '100%',
+ overflowWrap: 'anywhere',
+ fontSize: '11px !important'
+ },
+ tableWrap: {
+ padding: '3px 6px 5px',
+ height: 'auto',
+ maxHeight: EXPANDED_HEIGHT,
+ overflowY: 'auto',
+ overflowX: 'hidden',
+ transition: 'max-height 200ms ease'
+ },
+ tableWrapCollapsed: {
+ maxHeight: 0,
+ padding: '0 5px',
+ overflow: 'hidden'
+ },
+ tableHeadRow: {
+ backgroundColor: '#f5f5f5'
+ },
+ tableHeadCell: {
+ fontWeight: 600,
+ color: '#333',
+ fontSize: '11px !important'
+ },
+ tableBodyRow: {
+ '&:nth-of-type(even)': {
+ backgroundColor: '#fafafa'
+ }
+ },
+ td: {
+ wordWrap: 'break-all',
+ fontSize: '14px !important'
+ },
+ cellSelected: {
+ backgroundColor: '#2196f3',
+ color: '#fff',
+ fontSize: '13px !important'
+ },
+ btnRemove: {
+ color: 'red'
+ },
+ btnAddRow: {
+ color: 'green'
+ },
+ tTxt: {
+ padding: '5px 2px',
+ lineHeight: 1.2,
+ verticalAlign: 'top',
+ fontSize: '11px !important'
+ },
+ infoIcon: {
+ width: '15px',
+ height: '16px'
+ },
+ txtToolTip: {
+ lineHeight: 'normal !important',
+ fontSize: '14px !important'
+ },
+ rowRoot: {
+ border: '1px solid #e6e6e6',
+ borderRadius: 6,
+ minHeight: 40,
+ lineHeight: 1.4,
+ padding: '10px 16px',
+ textAlign: 'left'
+ },
+ rowOdd: {
+ backgroundColor: '#fff',
+ textOverflow: 'clip',
+ whiteSpace: 'normal'
+ },
+ rowEven: {
+ backgroundColor: '#fafafa',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap'
+ },
+ cvModeWarning: {
+ color: 'red',
+ marginLeft: 12
+ }
+});
+const CyclicVoltammetryPanel = ({
+ classes,
+ cyclicVotaSt,
+ feature,
+ addNewPairPeakAct,
+ setWorkWithMaxPeakAct,
+ selectPairPeakAct,
+ removePairPeakAct,
+ selectRefPeaksAct,
+ sweepTypeSt,
+ setUiSweepTypeAct,
+ jcampIdx,
+ userManualLink
+}) => {
+ const [isExpanded, setIsExpanded] = (0, _react.useState)(false);
+ const {
+ spectraList
+ } = cyclicVotaSt;
+ const spectra = spectraList[jcampIdx];
+ let list = [];
+ if (spectra !== undefined) {
+ list = spectra.list;
+ }
+ const formatCurrent = (y, feature, cyclicVotaSt) => {
+ const baseY = feature && feature.yUnit ? String(feature.yUnit) : 'A';
+ const isMilli = /mA/i.test(baseY);
+ const useDensity = cyclicVotaSt && cyclicVotaSt.useCurrentDensity;
+ const rawArea = (cyclicVotaSt && cyclicVotaSt.areaValue === '' ? 1.0 : cyclicVotaSt?.areaValue) || 1.0;
+ const areaUnit = cyclicVotaSt && cyclicVotaSt.areaUnit ? cyclicVotaSt.areaUnit : 'cm²';
+ const safeArea = rawArea > 0 ? rawArea : 1.0;
+ let val = y;
+ let unit = isMilli ? 'mA' : 'A';
+ if (useDensity) {
+ val = y / safeArea;
+ unit = `${unit}/${areaUnit}`;
+ }
+ if (isMilli) {
+ val *= 1000.0;
+ }
+ return `${parseFloat(val).toExponential(2)} ${unit}`;
+ };
+ const selectCell = (idx, isMax) => {
+ setWorkWithMaxPeakAct({
+ isMax,
+ jcampIdx
+ });
+ selectPairPeakAct({
+ index: idx,
+ jcampIdx
+ });
+ if (sweepTypeSt === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MAX_PEAK || sweepTypeSt === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK) {
+ if (isMax) {
+ setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MAX_PEAK, jcampIdx);
+ } else {
+ setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK, jcampIdx);
+ }
+ } else if (sweepTypeSt === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK || sweepTypeSt === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK) {
+ if (isMax) {
+ setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK, jcampIdx);
+ } else {
+ setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK, jcampIdx);
+ }
+ }
+ };
+ const changeCheckRefPeaks = (idx, event) => {
+ selectRefPeaksAct({
+ index: idx,
+ jcampIdx,
+ checked: event.target.checked
+ });
+ };
+ const getDelta = data => {
+ return data.max && data.min ? _format.default.strNumberFixedLength((0, _chem.GetCyclicVoltaPeakSeparate)(data.max.x, data.min.x) * 1000, 3) : 'nd';
+ };
+ const getRatio = (feature, data) => {
+ const featureData = feature.data[0];
+ const idx = featureData.x.indexOf(feature.maxX);
+ const y_pecker = data.pecker ? data.pecker.y : featureData.y[idx];
+ return data.max && data.min ? _format.default.strNumberFixedLength((0, _chem.GetCyclicVoltaRatio)(data.max.y, data.min.y, y_pecker), 3) : 'nd';
+ };
+ const rows = list.map((o, idx) => ({
+ idx,
+ max: o.max ? `E: ${_format.default.strNumberFixedLength(parseFloat(o.max.x), 3)} V,\nI: ${formatCurrent(o.max.y, feature, cyclicVotaSt)}` : 'nd',
+ min: o.min ? `E: ${_format.default.strNumberFixedLength(parseFloat(o.min.x), 3)} V,\nI: ${formatCurrent(o.min.y, feature, cyclicVotaSt)}` : 'nd',
+ pecker: o.pecker ? `${formatCurrent(o.pecker.y, feature, cyclicVotaSt)}` : 'nd',
+ delta: `${getDelta(o)} mV`,
+ ratio: getRatio(feature, o),
+ e12: typeof o.e12 === 'number' ? `${_format.default.strNumberFixedLength(o.e12, 3)} V` : 'nd',
+ isRef: o.isRef,
+ onClickMax: () => selectCell(idx, true),
+ onClickMin: () => selectCell(idx, false),
+ remove: () => removePairPeakAct({
+ index: idx,
+ jcampIdx
+ }),
+ onCheckRefChanged: e => changeCheckRefPeaks(idx, e)
+ }));
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.panel,
+ "data-testid": "PanelVoltammetry",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.panelHeader,
+ role: "button",
+ tabIndex: 0,
+ onClick: () => setIsExpanded(prev => !prev),
+ onKeyDown: event => {
+ if (event.key === 'Enter' || event.key === ' ') {
+ event.preventDefault();
+ setIsExpanded(prev => !prev);
+ }
+ },
+ "aria-expanded": isExpanded,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Typography, {
+ className: "txt-panel-header",
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'),
+ children: "Voltammetry data"
+ }), ' - ', /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ children: ["Mode: ", cyclicVotaSt.useCurrentDensity ? 'Current Density' : 'Current']
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: classes.cvModeWarning,
+ children: "WE-ECSA must be set when switching to Current Density."
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.panelActions,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtToolTip),
+ children: "Click here to open the User manual document"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: classes.howToWrap,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
+ target: "_blank",
+ rel: "noopener noreferrer",
+ href: userManualLink,
+ children: "How-To"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Help.default, {
+ className: (0, _classnames.default)(classes.infoIcon)
+ })]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.IconButton, {
+ size: "small",
+ className: classes.toggleBtn,
+ onClick: event => {
+ event.stopPropagation();
+ setIsExpanded(prev => !prev);
+ },
+ "aria-label": isExpanded ? 'Collapse table' : 'Expand table',
+ children: isExpanded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandLess.default, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandMore.default, {})
+ })]
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.tableWrap, !isExpanded && classes.tableWrapCollapsed),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Table, {
+ className: classes.table,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableHead, {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ className: classes.tableHeadRow,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: "Ref"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: "Anodic"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: "Cathodic"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: ["I ", /*#__PURE__*/(0, _jsxRuntime.jsx)("sub", {
+ children: "\u03BB0"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsxs)("p", {
+ className: (0, _classnames.default)(classes.txtToolTip),
+ children: ["Baseline correction value for I ratio ", /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), "(a.k.a y value of pecker)"]
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Info.default, {
+ className: (0, _classnames.default)(classes.infoIcon)
+ })
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: ["I ratio", /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.txtToolTip),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
+ children: "Nicholson's method"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {
+ children: "NICHOLSON, Rl S. Semiempirical Procedure for Measuring with Stationary Electrode Polarography Rates of Chemical Reactions Involving the Product of Electron Transfer. Analytical Chemistry, 1966, 38. Jg., Nr. 10, S. 1406-1406. https://doi.org/10.1021/ac60242a030"
+ })]
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Info.default, {
+ className: (0, _classnames.default)(classes.infoIcon)
+ })
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: ["E", /*#__PURE__*/(0, _jsxRuntime.jsx)("sub", {
+ children: "1/2"
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: ["\u0394E", /*#__PURE__*/(0, _jsxRuntime.jsx)("sub", {
+ children: "p"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtToolTip),
+ children: "| Epa - Epc |"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Info.default, {
+ className: (0, _classnames.default)(classes.infoIcon)
+ })
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.tableHeadCell, classes.square, 'txt-sv-panel-txt'),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_AddCircleOutline.default, {
+ onClick: () => addNewPairPeakAct(jcampIdx),
+ className: (0, _classnames.default)(classes.btnAddRow)
+ })
+ })]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableBody, {
+ children: rows.map(row => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ className: classes.tableBodyRow,
+ hover: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, 'txt-sv-panel-txt'),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Checkbox, {
+ size: "small",
+ checked: row.isRef,
+ onChange: row.onCheckRefChanged,
+ sx: {
+ padding: 0
+ }
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, spectra.isWorkMaxPeak && spectra.selectedIdx === row.idx ? classes.cellSelected : 'txt-sv-panel-txt'),
+ onClick: row.onClickMax,
+ children: row.max.split('\n').map((s, index) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.default.Fragment, {
+ children: [s, /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {})]
+ }, index))
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, !spectra.isWorkMaxPeak && spectra.selectedIdx === row.idx ? classes.cellSelected : 'txt-sv-panel-txt'),
+ onClick: row.onClickMin,
+ children: row.min.split('\n').map((s, index) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.default.Fragment, {
+ children: [s, /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {})]
+ }, index))
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, 'txt-sv-panel-txt'),
+ children: row.pecker
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, 'txt-sv-panel-txt'),
+ children: row.ratio
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, 'txt-sv-panel-txt'),
+ children: row.e12
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, 'txt-sv-panel-txt'),
+ children: row.delta
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "left",
+ className: (0, _classnames.default)(classes.tTxt, classes.square, 'txt-sv-panel-txt'),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RemoveCircle.default, {
+ className: (0, _classnames.default)(classes.btnRemove),
+ onClick: row.remove
+ })
+ })]
+ }, row.idx))
+ })]
+ })
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ cyclicVotaSt: state.cyclicvolta,
+ sweepTypeSt: state.ui.sweepType
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ addNewPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak,
+ setWorkWithMaxPeakAct: _cyclic_voltammetry.setWorkWithMaxPeak,
+ selectPairPeakAct: _cyclic_voltammetry.selectPairPeak,
+ removePairPeakAct: _cyclic_voltammetry.removeCylicVoltaPairPeak,
+ selectRefPeaksAct: _cyclic_voltammetry.selectRefPeaks,
+ setUiSweepTypeAct: _ui.setUiSweepType
+}, dispatch);
+CyclicVoltammetryPanel.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ cyclicVotaSt: _propTypes.default.object.isRequired,
+ addNewPairPeakAct: _propTypes.default.func.isRequired,
+ setWorkWithMaxPeakAct: _propTypes.default.func.isRequired,
+ selectPairPeakAct: _propTypes.default.func.isRequired,
+ removePairPeakAct: _propTypes.default.func.isRequired,
+ selectRefPeaksAct: _propTypes.default.func.isRequired,
+ setUiSweepTypeAct: _propTypes.default.func.isRequired,
+ sweepTypeSt: _propTypes.default.string.isRequired,
+ userManualLink: _propTypes.default.string,
+ jcampIdx: _propTypes.default.number
+};
+CyclicVoltammetryPanel.defaultProps = {
+ jcampIdx: 0
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(CyclicVoltammetryPanel));
\ No newline at end of file
diff --git a/dist/components/panel/graph_selection.js b/dist/components/panel/graph_selection.js
new file mode 100644
index 00000000..5ab8adf3
--- /dev/null
+++ b/dist/components/panel/graph_selection.js
@@ -0,0 +1,260 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireWildcard(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
+var _styles = require("@mui/styles");
+var _material = require("@mui/material");
+var _curve = require("../../actions/curve");
+var _list_layout = require("../../constants/list_layout");
+var _jsxRuntime = require("react/jsx-runtime");
+function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
+/* eslint-disable react/function-component-definition, function-paren-newline,
+react/require-default-props, react/no-unused-prop-types */
+
+const styles = () => ({
+ panelSummary: {
+ backgroundColor: '#eee',
+ height: 22
+ },
+ curve: {
+ width: '100%'
+ },
+ line: {
+ height: '2px',
+ borderWidth: '0',
+ margin: '0'
+ },
+ curveDefault: {
+ backgroundColor: '#fff',
+ fontSize: '0.8em',
+ margin: '0',
+ padding: '10px 2px 2px 10px',
+ maxWidth: '95%',
+ overflowWrap: 'anywhere'
+ },
+ curveSelected: {
+ backgroundColor: '#2196f3',
+ fontSize: '0.8em',
+ color: '#fff',
+ padding: '10px 2px 2px 10px',
+ maxWidth: '95%',
+ overflowWrap: 'anywhere'
+ }
+});
+const GraphSelectionPanel = ({
+ classes,
+ curveSt,
+ entityFileNames,
+ subLayoutsInfo,
+ layoutSt,
+ selectCurveAct,
+ toggleShowAllCurveAct
+}) => {
+ let subLayoutValues = [];
+ if (subLayoutsInfo) {
+ subLayoutValues = Object.keys(subLayoutsInfo);
+ }
+ const [selectedSubLayout, setSelectedSublayout] = (0, _react.useState)(subLayoutValues[0]);
+ (0, _react.useEffect)(() => {
+ setSelectedSublayout(subLayoutValues[0]);
+ }, subLayoutValues);
+ if (!curveSt) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {});
+ }
+ const {
+ curveIdx,
+ listCurves,
+ isShowAllCurve
+ } = curveSt;
+ if (!listCurves) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {});
+ }
+ const onChange = idx => {
+ selectCurveAct(idx);
+ };
+ const onChangeTabSubLayout = (event, newValue) => {
+ setSelectedSublayout(newValue);
+ };
+ const onChangeSwitch = event => {
+ toggleShowAllCurveAct(event.target.checked);
+ };
+ let itemsSubLayout = [];
+ if (selectedSubLayout && subLayoutValues.length > 1) {
+ const subLayout = subLayoutsInfo[selectedSubLayout];
+ try {
+ itemsSubLayout = subLayout.map((spectra, idx) => {
+ const spectraIdx = spectra.curveIdx;
+ const {
+ color
+ } = spectra;
+ let filename = '';
+ if (entityFileNames && spectraIdx < entityFileNames.length) {
+ filename = entityFileNames[spectraIdx];
+ }
+ return {
+ name: `${idx + 1}.`,
+ idx: spectraIdx,
+ color,
+ filename
+ };
+ });
+ } catch (e) {
+ console.log(e); //eslint-disable-line
+ }
+ }
+ const items = listCurves.map((spectra, idx) => {
+ const {
+ color
+ } = spectra;
+ let filename = '';
+ if (entityFileNames && idx < entityFileNames.length) {
+ filename = entityFileNames[idx];
+ }
+ return {
+ name: `${idx + 1}.`,
+ idx,
+ color,
+ filename
+ };
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, {
+ "data-testid": "GraphSelectionPanel",
+ disableGutters: true,
+ sx: {
+ '&.MuiAccordion-root.Mui-expanded': {
+ margin: 0
+ },
+ '&:before': {
+ display: 'none'
+ }
+ },
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.AccordionSummary, {
+ expandIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandMore.default, {}),
+ className: (0, _classnames.default)(classes.panelSummary),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
+ className: "txt-panel-header",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'),
+ children: "Graph selection"
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), layoutSt === _list_layout.LIST_LAYOUT.AIF ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControlLabel, {
+ control: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Switch, {
+ checked: isShowAllCurve,
+ onChange: onChangeSwitch
+ }),
+ label: "Show all curves"
+ }) : null, subLayoutValues && subLayoutValues.length > 1 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tabs, {
+ value: selectedSubLayout,
+ onChange: onChangeTabSubLayout,
+ children: subLayoutValues.map((subLayout, i) => {
+ let subLayoutName = '';
+ switch (subLayout.toUpperCase()) {
+ case 'G/MOL':
+ subLayoutName = 'MWD';
+ break;
+ case 'MILLILITERS':
+ subLayoutName = 'ELU';
+ break;
+ case 'INTENSITY':
+ subLayoutName = 'Chromatogram';
+ break;
+ case 'DEGREES CELSIUS':
+ subLayoutName = 'Temperature';
+ break;
+ default:
+ break;
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tab, {
+ value: subLayout,
+ label: subLayoutName
+ }, i);
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.List, {
+ children: itemsSubLayout.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.ListItem, {
+ onClick: () => onChange(item.idx),
+ className: (0, _classnames.default)(item.idx === curveIdx ? classes.curveSelected : classes.curveDefault) // eslint-disable-line
+ ,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.curve),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("i", {
+ children: item.name
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ style: {
+ float: 'right',
+ width: '95%'
+ },
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("hr", {
+ className: (0, _classnames.default)(classes.line),
+ style: {
+ backgroundColor: item.color
+ }
+ }), item.filename !== '' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ children: ["File: ", item.filename]
+ }) : null // eslint-disable-line
+ ]
+ })]
+ })
+ }, item.idx))
+ })]
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.List, {
+ children: items.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.ListItem, {
+ onClick: () => onChange(item.idx),
+ className: (0, _classnames.default)(item.idx === curveIdx ? classes.curveSelected : classes.curveDefault) // eslint-disable-line
+ ,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ className: (0, _classnames.default)(classes.curve),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("i", {
+ children: item.name
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ style: {
+ float: 'right',
+ width: '95%'
+ },
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("hr", {
+ className: (0, _classnames.default)(classes.line),
+ style: {
+ backgroundColor: item.color
+ }
+ }), item.filename !== '' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
+ children: ["File: ", item.filename]
+ }) : null // eslint-disable-line
+ ]
+ })]
+ })
+ }, item.idx))
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ selectCurveAct: _curve.selectCurve,
+ toggleShowAllCurveAct: _curve.toggleShowAllCurves
+}, dispatch);
+GraphSelectionPanel.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ expand: _propTypes.default.bool.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ onExapnd: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ selectCurveAct: _propTypes.default.func.isRequired,
+ entityFileNames: _propTypes.default.array.isRequired,
+ subLayoutsInfo: _propTypes.default.array,
+ toggleShowAllCurveAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(GraphSelectionPanel));
\ No newline at end of file
diff --git a/dist/components/panel/index.js b/dist/components/panel/index.js
new file mode 100644
index 00000000..66cbcca9
--- /dev/null
+++ b/dist/components/panel/index.js
@@ -0,0 +1,172 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _styles = require("@mui/material/styles");
+var _withStyles = _interopRequireDefault(require("@mui/styles/withStyles"));
+var _info = _interopRequireDefault(require("./info"));
+var _peaks = _interopRequireDefault(require("./peaks"));
+var _compare = _interopRequireDefault(require("./compare"));
+var _multiplicity = _interopRequireDefault(require("./multiplicity"));
+var _cyclic_voltamery_data = _interopRequireDefault(require("./cyclic_voltamery_data"));
+var _graph_selection = _interopRequireDefault(require("./graph_selection"));
+var _cfg = _interopRequireDefault(require("../../helpers/cfg"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/prop-types, react/require-default-props */
+
+const theme = (0, _styles.createTheme)({
+ typography: {
+ useNextVariants: true
+ },
+ palette: {
+ background: {
+ default: '#D3D3D3'
+ }
+ }
+});
+const styles = () => ({
+ panels: {
+ maxHeight: 'calc(90vh - 220px)',
+ // ROI
+ display: 'table',
+ overflowX: 'hidden',
+ overflowY: 'auto',
+ margin: '5px 0 0 0',
+ padding: '0 0 0 0',
+ width: '100%'
+ }
+});
+class PanelViewer extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ expand: 'info'
+ };
+ this.onExapnd = this.onExapnd.bind(this);
+ this.handleDescriptionChanged = this.handleDescriptionChanged.bind(this);
+ }
+ handleDescriptionChanged(content, delta, source, editor) {
+ if (source === 'user') {
+ const contentChanged = editor.getContents();
+ this.props.onDescriptionChanged(contentChanged); // eslint-disable-line
+ }
+ }
+ onExapnd(input) {
+ const {
+ expand
+ } = this.state;
+ const nextExpand = input === expand ? '' : input;
+ this.setState({
+ expand: nextExpand
+ });
+ }
+ render() {
+ const {
+ expand
+ } = this.state;
+ const {
+ classes,
+ feature,
+ integration,
+ editorOnly,
+ molSvg,
+ descriptions,
+ layoutSt,
+ canChangeDescription,
+ jcampIdx,
+ entityFileNames,
+ curveSt,
+ userManualLink,
+ subLayoutsInfo,
+ exactMass,
+ hideCyclicVolta
+ } = this.props;
+ const onExapndInfo = () => this.onExapnd('info');
+ const onExapndPeak = () => this.onExapnd('peak');
+ const onExapndMpy = () => this.onExapnd('mpy');
+ const onExapndCompare = () => this.onExapnd('compare');
+ const onExapndCyclicVolta = () => this.onExapnd('cyclicvolta');
+ const onExapndGraphSelection = () => this.onExapnd('graph');
+ const {
+ listCurves
+ } = curveSt;
+ const hideGraphSelection = listCurves === false || listCurves === undefined;
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.panels),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.StyledEngineProvider, {
+ injectFirst: true,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.ThemeProvider, {
+ theme: theme,
+ children: [hideGraphSelection ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_graph_selection.default, {
+ jcampIdx: jcampIdx,
+ entityFileNames: entityFileNames,
+ expand: expand === 'graph',
+ onExapnd: onExapndGraphSelection,
+ subLayoutsInfo: subLayoutsInfo
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_info.default, {
+ feature: feature,
+ integration: integration,
+ editorOnly: editorOnly,
+ expand: expand === 'info',
+ molSvg: molSvg,
+ exactMass: exactMass,
+ onExapnd: onExapndInfo,
+ descriptions: descriptions,
+ canChangeDescription: canChangeDescription,
+ onDescriptionChanged: this.handleDescriptionChanged
+ }), _cfg.default.hidePanelPeak(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_peaks.default, {
+ expand: expand === 'peak',
+ onExapnd: onExapndPeak
+ }), _cfg.default.hidePanelMpy(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, {
+ expand: expand === 'mpy',
+ onExapnd: onExapndMpy
+ }), _cfg.default.hidePanelCompare(layoutSt) || listCurves.length > 1 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_compare.default, {
+ expand: expand === 'compare',
+ onExapnd: onExapndCompare
+ }), _cfg.default.hidePanelCyclicVolta(layoutSt) || hideCyclicVolta ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_cyclic_voltamery_data.default, {
+ jcampIdx: jcampIdx,
+ feature: feature,
+ expand: expand === 'cyclicvolta',
+ onExapnd: onExapndCyclicVolta,
+ userManualLink: userManualLink ? userManualLink.cv : undefined
+ })]
+ })
+ })
+ });
+ }
+}
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+PanelViewer.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ integration: _propTypes.default.object.isRequired,
+ editorOnly: _propTypes.default.bool.isRequired,
+ molSvg: _propTypes.default.string.isRequired,
+ descriptions: _propTypes.default.array.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ canChangeDescription: _propTypes.default.bool.isRequired,
+ onDescriptionChanged: _propTypes.default.func,
+ entityFileNames: _propTypes.default.array,
+ userManualLink: _propTypes.default.object,
+ curveSt: _propTypes.default.object.isRequired,
+ subLayoutsInfo: _propTypes.default.object,
+ exactMass: _propTypes.default.string,
+ hideCyclicVolta: _propTypes.default.bool
+};
+var _default = exports.default = (0, _reactRedux.connect)(
+// eslint-disable-line
+mapStateToProps, mapDispatchToProps)((0, _withStyles.default)(styles)(PanelViewer)); // eslint-disable-line
\ No newline at end of file
diff --git a/dist/components/panel/info.js b/dist/components/panel/info.js
new file mode 100644
index 00000000..72928355
--- /dev/null
+++ b/dist/components/panel/info.js
@@ -0,0 +1,521 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _reactSvgFileZoomPan = _interopRequireDefault(require("@complat/react-svg-file-zoom-pan"));
+var _reactQuill = _interopRequireDefault(require("react-quill"));
+var _material = require("@mui/material");
+var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
+var _styles = require("@mui/styles");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _meta = require("../../actions/meta");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable no-mixed-operators, react/function-component-definition,
+react/require-default-props, max-len */
+
+const styles = () => ({
+ chip: {
+ margin: '1px 0 1px 0'
+ },
+ panel: {
+ backgroundColor: '#eee',
+ display: 'table-row'
+ },
+ panelSummary: {
+ backgroundColor: '#eee',
+ height: 32
+ },
+ subSectionHeader: {
+ backgroundColor: '#eee',
+ height: 32,
+ lineHeight: '32px',
+ paddingLeft: 10,
+ textAlign: 'left',
+ fontWeight: 'bold',
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica',
+ borderTop: '1px solid #dcdcdc',
+ color: 'rgba(0, 0, 0, 0.87)'
+ },
+ panelDetail: {
+ backgroundColor: '#fff',
+ maxHeight: 'calc(90vh - 220px)',
+ // ROI
+ overflow: 'auto'
+ },
+ table: {
+ width: 'auto'
+ },
+ rowRoot: {
+ border: '1px solid #eee',
+ height: 36,
+ lineHeight: '36px',
+ overflow: 'hidden',
+ paddingLeft: 24,
+ textAlign: 'left'
+ },
+ rowOdd: {
+ backgroundColor: '#fff',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap'
+ },
+ rowEven: {
+ backgroundColor: '#fafafa',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap'
+ },
+ rowOddSim: {
+ backgroundColor: '#fff',
+ height: 108,
+ lineHeight: '24px',
+ overflowY: 'hidden',
+ overflowWrap: 'word-break'
+ },
+ tHead: {
+ fontWeight: 'bold',
+ float: 'left',
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica'
+ },
+ tTxt: {
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica',
+ marginRight: 3
+ },
+ quill: {
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica',
+ textAlign: 'left'
+ },
+ quillContainer: {
+ margin: '10px 10px',
+ backgroundColor: '#fff',
+ '& .ql-container': {
+ border: 'none'
+ },
+ '& .ql-editor': {
+ minHeight: '60px'
+ },
+ '& .ql-editor.ql-blank::before': {
+ fontStyle: 'normal',
+ color: 'rgba(0, 0, 0, 0.54)'
+ }
+ }
+});
+const simTitle = () => 'Simulated signals from NMRshiftDB';
+const simContent = nmrSimPeaks => nmrSimPeaks && nmrSimPeaks.sort((a, b) => a - b).join(', ');
+const normalizeQuillValue = val => {
+ if (!val) return '';
+ if (val === '
' || val === '') return '';
+ return val;
+};
+const chemSubStyle = {
+ fontSize: '0.85em',
+ position: 'relative',
+ top: '0.24em',
+ lineHeight: 1
+};
+const renderReadableSubscript = (txt = '') => {
+ if (typeof txt !== 'string') return txt;
+ const regex = /([A-Za-z])(\d+)/g;
+ if (!regex.test(txt)) return txt;
+ regex.lastIndex = 0;
+ const parts = [];
+ let cursor = 0;
+ let match = regex.exec(txt);
+ while (match) {
+ const [raw, prefix, digits] = match;
+ const at = match.index;
+ if (at > cursor) parts.push(txt.slice(cursor, at));
+ parts.push(prefix);
+ parts.push(/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ style: chemSubStyle,
+ children: digits
+ }, `${at}-${digits}`));
+ cursor = at + raw.length;
+ match = regex.exec(txt);
+ }
+ if (cursor < txt.length) parts.push(txt.slice(cursor));
+ return parts;
+};
+const handleDescriptionChanged = (content, delta, source, editor, onDescriptionChanged) => {
+ if (!onDescriptionChanged) return;
+ onDescriptionChanged(normalizeQuillValue(content), delta, source, editor);
+};
+const aucValue = integration => {
+ if (!integration) {
+ return '';
+ }
+ const values = [];
+ const stackIntegration = integration.stack;
+ if (Array.isArray(stackIntegration)) {
+ let sumVal = 0.0;
+ stackIntegration.forEach(inte => {
+ if (inte.absoluteArea) {
+ sumVal += inte.absoluteArea;
+ }
+ });
+ sumVal = sumVal.toFixed(2);
+ stackIntegration.forEach(inte => {
+ if (inte.absoluteArea) {
+ const areaVal = inte.absoluteArea.toFixed(2);
+ const percent = (areaVal * 100 / sumVal).toFixed(2);
+ const valStr = areaVal + " (" + percent + "%)"; // eslint-disable-line
+ values.push(valStr);
+ }
+ });
+ }
+ return values.join(', ');
+};
+const SECData = ({
+ classes,
+ layout,
+ detector,
+ secData
+}) => {
+ if (_format.default.isSECLayout(layout) && secData) {
+ const {
+ d,
+ mn,
+ mp,
+ mw
+ } = secData;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOdd),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "Detector: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: detector
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowEven),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "D: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: d
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOdd),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "MN: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: mn
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowEven),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "MP: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: mp
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOdd),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "MW: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: mw
+ })]
+ })]
+ });
+ }
+ return null;
+};
+SECData.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layout: _propTypes.default.string.isRequired,
+ detector: _propTypes.default.object.isRequired,
+ secData: _propTypes.default.object.isRequired
+};
+const DSCData = ({
+ classes,
+ layout,
+ dscMetaData,
+ updateAction
+}) => {
+ if (_format.default.isDSCLayout(layout) && dscMetaData !== undefined) {
+ const {
+ meltingPoint,
+ tg
+ } = dscMetaData;
+ const onChange = e => {
+ const {
+ name,
+ value
+ } = e.target;
+ const dataToUpdate = {
+ meltingPoint,
+ tg
+ };
+ dataToUpdate[name] = value;
+ updateAction(dataToUpdate);
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOdd),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "Melting Point: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
+ type: "text",
+ name: "meltingPoint",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ value: meltingPoint,
+ onChange: onChange
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowEven),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "TG: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
+ type: "text",
+ name: "tg",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ value: tg,
+ onChange: onChange
+ })]
+ })]
+ });
+ }
+ return null;
+};
+DSCData.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ layout: _propTypes.default.string.isRequired,
+ dscMetaData: _propTypes.default.object.isRequired,
+ updateAction: _propTypes.default.func.isRequired
+};
+const InfoPanel = ({
+ classes,
+ expand,
+ feature,
+ integration,
+ editorOnly,
+ molSvg,
+ descriptions,
+ layoutSt,
+ simulationSt,
+ shiftSt,
+ curveSt,
+ exactMass,
+ onExapnd,
+ canChangeDescription,
+ onDescriptionChanged,
+ detectorSt,
+ metaSt,
+ updateDSCMetaDataAct
+}) => {
+ if (!feature) return null;
+ const {
+ title,
+ observeFrequency,
+ solventName,
+ secData
+ } = feature;
+ const {
+ dscMetaData
+ } = metaSt;
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ curves
+ } = detectorSt;
+ const getSelectedDetectorForCurve = (_detectorSt, targetCurveIdx) => {
+ const targetCurve = curves.find(curve => curve.curveIdx === targetCurveIdx);
+ return targetCurve ? targetCurve.selectedDetector.name : '';
+ };
+ let selectedDetector = getSelectedDetectorForCurve(detectorSt, curveIdx);
+
+ // default detector from jcamp
+ if (!selectedDetector && feature.detector) {
+ selectedDetector = feature.detector;
+ }
+ const {
+ shifts
+ } = shiftSt;
+ const selectedShift = shifts[curveIdx];
+ let showSolvName = solventName;
+ if (selectedShift !== undefined) {
+ const shiftName = selectedShift.ref.name;
+ showSolvName = shiftName === '- - -' ? solventName : shiftName;
+ }
+ let originStack = null;
+ if (integration) {
+ originStack = integration.originStack; // eslint-disable-line
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, {
+ "data-testid": "PanelInfo",
+ expanded: expand,
+ onChange: onExapnd,
+ disableGutters: true,
+ sx: {
+ '&.MuiAccordion-root.Mui-expanded': {
+ margin: 0
+ },
+ '&:before': {
+ display: 'none'
+ }
+ },
+ TransitionProps: {
+ unmountOnExit: true
+ } // increase Accordion performance
+ ,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.AccordionSummary, {
+ expandIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandMore.default, {}),
+ className: (0, _classnames.default)(classes.panelSummary),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
+ className: "txt-panel-header",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'),
+ children: "Info"
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.panelDetail),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOdd),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "Title : "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: title
+ })]
+ }), _format.default.isNmrLayout(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowEven),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "Freq : "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: `${parseInt(observeFrequency, 10)} MHz` || ' - '
+ })]
+ }) : null, _format.default.isNmrLayout(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOdd),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "Solv : "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: renderReadableSubscript(showSolvName)
+ })]
+ }) : null, _format.default.isMsLayout(layoutSt) && exactMass ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOdd),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "Exact mass: "
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: `${parseFloat(exactMass).toFixed(6)} g/mol`
+ })]
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(SECData, {
+ classes: classes,
+ layout: layoutSt,
+ detector: selectedDetector,
+ secData: secData
+ }), !molSvg ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactSvgFileZoomPan.default, {
+ svg: molSvg,
+ duration: 300,
+ resize: true
+ }), _format.default.isHplcUvVisLayout(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOddSim),
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tHead, 'txt-sv-panel-txt'),
+ children: "Area under curve (AUC):"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tTxtSim, 'txt-sv-panel-txt'),
+ children: aucValue(integration)
+ })]
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(DSCData, {
+ classes: classes,
+ layout: layoutSt,
+ dscMetaData: dscMetaData,
+ updateAction: updateDSCMetaDataAct
+ }), !_format.default.isCyclicVoltaLayout(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: classes.subSectionHeader,
+ children: "Content"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: classes.quillContainer,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactQuill.default, {
+ className: (0, _classnames.default)(classes.quill, 'card-sv-quill'),
+ value: normalizeQuillValue(descriptions),
+ placeholder: canChangeDescription ? 'Peaks will be written here...' : undefined,
+ readOnly: !canChangeDescription,
+ modules: {
+ toolbar: false
+ },
+ onChange: (content, delta, source, editor) => handleDescriptionChanged(content, delta, source, editor, onDescriptionChanged)
+ })
+ })]
+ }) : null, !editorOnly && _format.default.isNmrLayout(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: classes.subSectionHeader,
+ children: simTitle()
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.rowRoot, classes.rowOddSim),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.tTxt, classes.tTxtSim, 'txt-sv-panel-txt'),
+ children: simContent(simulationSt.nmrSimPeaks)
+ })
+ })]
+ }) : null]
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout,
+ simulationSt: state.simulation,
+ shiftSt: state.shift,
+ curveSt: state.curve,
+ detectorSt: state.detector,
+ metaSt: state.meta
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ updateDSCMetaDataAct: _meta.updateDSCMetaData
+}, dispatch);
+InfoPanel.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ expand: _propTypes.default.bool.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ integration: _propTypes.default.object.isRequired,
+ editorOnly: _propTypes.default.bool.isRequired,
+ molSvg: _propTypes.default.string.isRequired,
+ descriptions: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.array]).isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ simulationSt: _propTypes.default.array.isRequired,
+ shiftSt: _propTypes.default.object.isRequired,
+ curveSt: _propTypes.default.object.isRequired,
+ onExapnd: _propTypes.default.func.isRequired,
+ canChangeDescription: _propTypes.default.bool.isRequired,
+ onDescriptionChanged: _propTypes.default.func,
+ exactMass: _propTypes.default.string,
+ detectorSt: _propTypes.default.object.isRequired,
+ metaSt: _propTypes.default.object.isRequired,
+ updateDSCMetaDataAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(
+// eslint-disable-line
+mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(InfoPanel)); // eslint-disable-line
\ No newline at end of file
diff --git a/dist/components/panel/multiplicity.js b/dist/components/panel/multiplicity.js
new file mode 100644
index 00000000..52d50227
--- /dev/null
+++ b/dist/components/panel/multiplicity.js
@@ -0,0 +1,311 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
+var _HighlightOff = _interopRequireDefault(require("@mui/icons-material/HighlightOff"));
+var _styles = require("@mui/styles");
+var _RefreshOutlined = _interopRequireDefault(require("@mui/icons-material/RefreshOutlined"));
+var _multiplicity = require("../../actions/multiplicity");
+var _multiplicity_select = _interopRequireDefault(require("./multiplicity_select"));
+var _multiplicity_coupling = _interopRequireDefault(require("./multiplicity_coupling"));
+var _multiplicity_calc = require("../../helpers/multiplicity_calc");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable function-paren-newline,
+function-call-argument-newline, react/function-component-definition */
+
+const styles = theme => ({
+ panel: {
+ backgroundColor: '#eee',
+ display: 'table-row'
+ },
+ panelSummary: {
+ backgroundColor: '#eee',
+ height: 32
+ },
+ txtBadge: {},
+ panelDetail: {
+ backgroundColor: '#fff',
+ maxHeight: 'calc(90vh - 220px)',
+ // ROI
+ overflow: 'auto'
+ },
+ table: {
+ width: '100%'
+ },
+ tRowHeadPos: {
+ backgroundColor: '#2196f3',
+ height: 32
+ },
+ tRowHeadNeg: {
+ backgroundColor: '#fa004f',
+ height: 32
+ },
+ tTxtHead: {
+ color: 'white',
+ padding: '4px 0 4px 5px'
+ },
+ tTxtHeadXY: {
+ color: 'white',
+ padding: '4px 0 4px 90px'
+ },
+ tTxt: {
+ padding: 0
+ },
+ tRow: {
+ height: 28,
+ '&:nth-of-type(even)': {
+ backgroundColor: theme.palette ? theme.palette.background.default : '#d3d3d3'
+ }
+ },
+ rmBtn: {
+ color: 'red',
+ '&:hover': {
+ borderRadius: 12,
+ backgroundColor: 'red',
+ color: 'white'
+ }
+ },
+ moCard: {
+ textAlign: 'left'
+ },
+ moCardHead: {
+ backgroundColor: '#999',
+ color: 'white'
+ },
+ moExtId: {
+ border: '2px solid white',
+ borderRadius: 12,
+ color: 'white',
+ margin: '0 5px 0 5px',
+ padding: '0 5px 0 5px'
+ },
+ moExtTxt: {
+ margin: '0 5px 0 5x',
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica'
+ },
+ moSelect: {
+ margin: '0 5x 0 5px',
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica'
+ },
+ moCBox: {
+ marginLeft: 24,
+ padding: '4px 0 4px 4px'
+ },
+ btnRf: {
+ color: '#fff',
+ float: 'right',
+ minWidth: 40,
+ right: 15
+ }
+});
+const cBoxStyle = () => ({
+ root: {
+ color: 'white',
+ '&$checked': {
+ color: 'white'
+ }
+ },
+ checked: {}
+});
+const MUCheckbox = (0, _styles.withStyles)(cBoxStyle)(_material.Checkbox);
+const createData = (idx, xExtent, peaks, shift, smExtext, mpyType, js, onClick, onRefresh) => ({
+ idx: idx + 1,
+ xExtent,
+ onClick,
+ onRefresh,
+ peaks,
+ center: (0, _multiplicity_calc.calcMpyCenter)(peaks, shift, mpyType),
+ jStr: (0, _multiplicity_calc.calcMpyJStr)(js),
+ mpyType,
+ isCheck: smExtext.xL === xExtent.xL && smExtext.xU === xExtent.xU
+});
+const pkList = (classes, row, shift, digits, rmMpyPeakByPanelAct) => row.peaks.map(pk => {
+ const {
+ xExtent
+ } = row;
+ const cb = () => rmMpyPeakByPanelAct({
+ peak: pk,
+ xExtent
+ });
+ const rmBtn = /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightOff.default, {
+ onClick: cb,
+ className: classes.rmBtn
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ className: classes.tRow,
+ hover: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: `(${(pk.x - shift).toFixed(digits)}, ${pk.y.toExponential(2)})`
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: rmBtn
+ })]
+ }, pk.x);
+});
+const refreshBtn = (classes, onRefresh) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
+ placement: "left",
+ title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-sv-tp",
+ children: "Calculate Multiplicity"
+ }),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ className: classes.btnRf,
+ onClick: onRefresh,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RefreshOutlined.default, {})
+ })
+});
+const mpyList = (classes, digits, multiplicitySt, curveSt, clickMpyOneAct, rmMpyPeakByPanelAct, resetMpyOneAct) => {
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = multiplicitySt;
+ let selectedMulti = multiplicities[curveIdx];
+ if (selectedMulti === undefined) {
+ selectedMulti = {
+ stack: [],
+ shift: 0,
+ smExtext: false,
+ edited: false
+ };
+ }
+ const {
+ stack,
+ shift,
+ smExtext
+ } = selectedMulti;
+ const rows = stack.map((k, idx) => {
+ const {
+ peaks,
+ xExtent,
+ mpyType,
+ js
+ } = k;
+ const onRefresh = () => resetMpyOneAct(xExtent);
+ const onClick = e => {
+ e.stopPropagation();
+ e.preventDefault();
+ const payload = {
+ curveIdx,
+ payloadData: xExtent
+ };
+ clickMpyOneAct(payload);
+ };
+ return createData(idx, xExtent, peaks, shift, smExtext, mpyType, js, onClick, onRefresh);
+ });
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ children: rows.map(row => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.moCard,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ className: classes.moCardHead,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(MUCheckbox, {
+ className: classes.moCBox,
+ checked: row.isCheck,
+ onChange: row.onClick
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.moExtTxt, classes.moExtId, 'txt-sv-panel-head'),
+ children: row.idx
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.moExtTxt, 'txt-sv-panel-head'),
+ children: `${row.center.toFixed(3)} (ppm)`
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.moSelect, 'txt-sv-panel-head'),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity_select.default, {
+ target: row
+ })
+ }), refreshBtn(classes, row.onRefresh)]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity_coupling.default, {
+ row: row
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Table, {
+ className: classes.table,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableBody, {
+ children: pkList(classes, row, shift, digits, rmMpyPeakByPanelAct)
+ })
+ })]
+ }, row.idx))
+ });
+};
+const MultiplicityPanel = ({
+ classes,
+ expand,
+ onExapnd,
+ multiplicitySt,
+ curveSt,
+ clickMpyOneAct,
+ rmMpyPeakByPanelAct,
+ resetMpyOneAct
+}) => {
+ const digits = 4;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, {
+ expanded: expand,
+ onChange: onExapnd,
+ disableGutters: true,
+ sx: {
+ '&.MuiAccordion-root.Mui-expanded': {
+ margin: 0
+ },
+ '&:before': {
+ display: 'none'
+ }
+ },
+ TransitionProps: {
+ unmountOnExit: true
+ } // increase Accordion performance
+ ,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.AccordionSummary, {
+ expandIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandMore.default, {}),
+ className: (0, _classnames.default)(classes.panelSummary),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
+ className: "txt-panel-header",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'),
+ children: "Multiplicity"
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.panelDetail),
+ children: mpyList(classes, digits, multiplicitySt, curveSt, clickMpyOneAct, rmMpyPeakByPanelAct, resetMpyOneAct)
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ integrationSt: state.integration.present,
+ multiplicitySt: state.multiplicity.present,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ clickMpyOneAct: _multiplicity.clickMpyOne,
+ rmMpyPeakByPanelAct: _multiplicity.rmMpyPeakByPanel,
+ resetMpyOneAct: _multiplicity.resetMpyOne
+}, dispatch);
+MultiplicityPanel.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ expand: _propTypes.default.bool.isRequired,
+ onExapnd: _propTypes.default.func.isRequired,
+ multiplicitySt: _propTypes.default.object.isRequired,
+ clickMpyOneAct: _propTypes.default.func.isRequired,
+ rmMpyPeakByPanelAct: _propTypes.default.func.isRequired,
+ resetMpyOneAct: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(MultiplicityPanel));
\ No newline at end of file
diff --git a/dist/components/panel/multiplicity_coupling.js b/dist/components/panel/multiplicity_coupling.js
new file mode 100644
index 00000000..e245ceee
--- /dev/null
+++ b/dist/components/panel/multiplicity_coupling.js
@@ -0,0 +1,139 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _classnames = _interopRequireDefault(require("classnames"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _styles = require("@mui/styles");
+var _material = require("@mui/material");
+var _multiplicity = require("../../actions/multiplicity");
+var _jsxRuntime = require("react/jsx-runtime");
+const styles = () => ({
+ jDiv: {
+ height: 28
+ },
+ jTxt: {
+ margin: '0 5px 4px 60px'
+ },
+ moExtTxt: {
+ margin: '0 5px 0 5x',
+ fontSize: '0.8rem',
+ fontFamily: 'Helvetica'
+ },
+ txtField: {
+ width: 260,
+ margin: '0 3px 0 3px'
+ },
+ txtInput: {
+ color: 'white',
+ fontSize: '0.9rem',
+ fontFamily: 'Helvetica',
+ height: 24
+ }
+});
+const txtJ = () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputAdornment, {
+ position: "start",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-cmd-j",
+ children: "J\xA0="
+ })
+});
+const txtHz = () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputAdornment, {
+ position: "end",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: "txt-cmd-hz",
+ children: "Hz"
+ })
+});
+class MpyCoupling extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ focus: false,
+ tmpVal: false
+ };
+ this.onFocus = this.onFocus.bind(this);
+ this.onBlur = this.onBlur.bind(this);
+ this.onChange = this.onChange.bind(this);
+ }
+ onFocus() {
+ this.setState({
+ focus: true
+ });
+ }
+ onBlur() {
+ const {
+ row,
+ updateMpyJAct
+ } = this.props;
+ const {
+ tmpVal
+ } = this.state;
+ const {
+ xExtent
+ } = row;
+ this.setState({
+ focus: false,
+ tmpVal: false
+ });
+ updateMpyJAct({
+ xExtent,
+ value: tmpVal
+ });
+ }
+ onChange(e) {
+ this.setState({
+ tmpVal: e.target.value
+ });
+ }
+ render() {
+ const {
+ classes,
+ row
+ } = this.props;
+ const {
+ focus,
+ tmpVal
+ } = this.state;
+ const value = focus && (tmpVal || tmpVal === '') ? tmpVal : row.jStr;
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.jDiv),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.moExtTxt, classes.jTxt, 'txt-sv-panel-head'),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TextField, {
+ className: (0, _classnames.default)(classes.txtField, 'txt-cmd-field'),
+ placeholder: "-",
+ value: value,
+ margin: "none",
+ InputProps: {
+ startAdornment: txtJ(),
+ endAdornment: txtHz(),
+ className: (0, _classnames.default)(classes.txtInput, 'txt-sv-input-label')
+ },
+ onChange: this.onChange,
+ onFocus: this.onFocus,
+ onBlur: this.onBlur,
+ variant: "outlined"
+ })
+ })
+ });
+ }
+}
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ updateMpyJAct: _multiplicity.updateMpyJ
+}, dispatch);
+MpyCoupling.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ row: _propTypes.default.object.isRequired,
+ updateMpyJAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(MpyCoupling));
\ No newline at end of file
diff --git a/dist/components/panel/multiplicity_select.js b/dist/components/panel/multiplicity_select.js
new file mode 100644
index 00000000..056ae028
--- /dev/null
+++ b/dist/components/panel/multiplicity_select.js
@@ -0,0 +1,88 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _styles = require("@mui/styles");
+var _multiplicity = require("../../actions/multiplicity");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/function-component-definition */
+
+const Styles = () => ({
+ formControl: {
+ minWidth: 50,
+ margin: '2px 3px 0 3px'
+ },
+ txtField: {
+ width: 120,
+ margin: '3px 3px 3px 3px'
+ },
+ txtInput: {
+ height: 24,
+ fontSize: '0.9rem',
+ fontFamily: 'Helvetica',
+ color: 'white'
+ }
+});
+const MpySelect = ({
+ classes,
+ target,
+ selectMpyTypeAct
+}) => {
+ const {
+ mpyType,
+ xExtent
+ } = target;
+ const onBlur = e => selectMpyTypeAct({
+ xExtent,
+ mpyType: e.target.value
+ });
+ const onChange = e => selectMpyTypeAct({
+ xExtent,
+ mpyType: e.target.value
+ });
+ const onEnterPress = e => {
+ if (e.key === 'Enter') {
+ selectMpyTypeAct({
+ xExtent,
+ mpyType: e.target.value
+ });
+ }
+ };
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControl, {
+ className: (0, _classnames.default)(classes.formControl),
+ variant: "outlined",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TextField, {
+ className: (0, _classnames.default)(classes.txtField, 'txt-cmd-field'),
+ value: mpyType,
+ margin: "none",
+ variant: "outlined",
+ InputProps: {
+ className: (0, _classnames.default)(classes.txtInput, 'txt-sv-input-label')
+ },
+ onChange: onChange,
+ onBlur: onBlur,
+ onKeyPress: onEnterPress
+ })
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ selectMpyTypeAct: _multiplicity.selectMpyType
+}, dispatch);
+MpySelect.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ target: _propTypes.default.object.isRequired,
+ selectMpyTypeAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(Styles)(MpySelect));
\ No newline at end of file
diff --git a/dist/components/panel/peaks.js b/dist/components/panel/peaks.js
new file mode 100644
index 00000000..4513c8f0
--- /dev/null
+++ b/dist/components/panel/peaks.js
@@ -0,0 +1,240 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _classnames = _interopRequireDefault(require("classnames"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _material = require("@mui/material");
+var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
+var _HighlightOff = _interopRequireDefault(require("@mui/icons-material/HighlightOff"));
+var _styles = require("@mui/styles");
+var _chem = require("../../helpers/chem");
+var _edit_peak = require("../../actions/edit_peak");
+var _format = _interopRequireDefault(require("../../helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable react/function-component-definition, no-unused-vars */
+
+const styles = theme => ({
+ chip: {
+ margin: '1px 0 1px 0'
+ },
+ panel: {
+ backgroundColor: '#eee',
+ display: 'table-row'
+ },
+ panelSummary: {
+ backgroundColor: '#eee',
+ height: 32
+ },
+ txtBadge: {},
+ panelDetail: {
+ backgroundColor: '#fff',
+ maxHeight: 'calc(90vh - 220px)',
+ // ROI
+ overflow: 'auto'
+ },
+ table: {
+ width: '100%'
+ },
+ tRowHeadPos: {
+ backgroundColor: '#999',
+ height: 32
+ },
+ tRowHeadNeg: {
+ backgroundColor: '#999',
+ height: 32
+ },
+ tTxtHead: {
+ color: 'white',
+ padding: '5px 5px 5px 5px'
+ },
+ tTxtHeadXY: {
+ color: 'white',
+ padding: '4px 0 4px 90px'
+ },
+ tTxt: {
+ padding: '4px 0 4px 0'
+ },
+ tRow: {
+ height: 28,
+ '&:nth-of-type(even)': {
+ backgroundColor: theme.palette ? theme.palette.background.default : '#d3d3d3'
+ }
+ },
+ rmBtn: {
+ color: 'red',
+ '&:hover': {
+ borderRadius: 12,
+ backgroundColor: 'red',
+ color: 'white'
+ }
+ }
+});
+const createData = (classes, idx, x, y, cb, digits) => ({
+ idx: idx + 1,
+ x: x.toFixed(digits),
+ y,
+ rmBtn: /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightOff.default, {
+ onClick: cb,
+ className: classes.rmBtn
+ })
+});
+const peakList = (peaks, digits, cbAct, classes, isPos) => {
+ const rows = peaks.map((pp, idx) => {
+ const onDelete = () => cbAct(pp);
+ return createData(classes, idx, pp.x, pp.y, onDelete, digits);
+ });
+ const rowKlass = isPos ? classes.tRowHeadPos : classes.tRowHeadNeg;
+ const headTxt = isPos ? 'P+' : 'P-';
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Table, {
+ className: classes.table,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableHead, {
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ className: rowKlass,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxtHead, 'txt-sv-panel-head'),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {
+ children: headTxt
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxtHeadXY, 'txt-sv-panel-head'),
+ children: "X"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxtHeadXY, 'txt-sv-panel-head'),
+ children: "Y"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxtHead, 'txt-sv-panel-head'),
+ children: "-"
+ })]
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableBody, {
+ children: rows.map(row => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.TableRow, {
+ className: classes.tRow,
+ hover: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: row.idx
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: row.x
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: row.y.toExponential(2)
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.TableCell, {
+ align: "right",
+ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'),
+ children: row.rmBtn
+ })]
+ }, row.idx))
+ })]
+ });
+};
+const PeakPanel = ({
+ editPeakSt,
+ layoutSt,
+ classes,
+ expand,
+ onExapnd,
+ rmFromPosListAct,
+ rmFromNegListAct,
+ curveSt
+}) => {
+ const {
+ curveIdx,
+ listCurves
+ } = curveSt;
+ const {
+ peaks
+ } = editPeakSt;
+ if (curveIdx >= peaks.length) {
+ return null;
+ }
+ const selectedEditPeaks = peaks[curveIdx];
+ if (!selectedEditPeaks) {
+ return null;
+ }
+ const {
+ pos,
+ neg
+ } = selectedEditPeaks;
+ const selectedCurve = listCurves[curveIdx];
+ if (!selectedCurve) {
+ return null;
+ }
+ const {
+ feature
+ } = selectedCurve;
+ const currentPeakOfCurve = (0, _chem.Convert2Peak)(feature);
+ const filteredArray = currentPeakOfCurve.filter(element => neg.includes(element));
+ const peaksData = [].concat(filteredArray).concat(pos);
+ const digits = _format.default.isEmWaveLayout(layoutSt) ? 0 : 4;
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, {
+ "data-testid": "PeaksPanelInfo",
+ expanded: expand,
+ onChange: onExapnd,
+ disableGutters: true,
+ sx: {
+ '&.MuiAccordion-root.Mui-expanded': {
+ margin: 0
+ },
+ '&:before': {
+ display: 'none'
+ }
+ },
+ TransitionProps: {
+ unmountOnExit: true
+ } // increase Accordion performance
+ ,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.AccordionSummary, {
+ expandIcon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandMore.default, {}),
+ className: (0, _classnames.default)(classes.panelSummary),
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
+ className: "txt-panel-header",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'),
+ children: "Peaks"
+ })
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: (0, _classnames.default)(classes.panelDetail),
+ children: peakList(peaksData, digits, rmFromPosListAct, classes, true)
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ editPeakSt: state.editPeak.present,
+ layoutSt: state.layout,
+ curveSt: state.curve
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ rmFromPosListAct: _edit_peak.rmFromPosList,
+ rmFromNegListAct: _edit_peak.rmFromNegList
+}, dispatch);
+PeakPanel.propTypes = {
+ classes: _propTypes.default.object.isRequired,
+ expand: _propTypes.default.bool.isRequired,
+ editPeakSt: _propTypes.default.object.isRequired,
+ layoutSt: _propTypes.default.string.isRequired,
+ onExapnd: _propTypes.default.func.isRequired,
+ rmFromPosListAct: _propTypes.default.func.isRequired,
+ rmFromNegListAct: _propTypes.default.func.isRequired,
+ curveSt: _propTypes.default.object.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(
+// eslint-disable-line
+mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(PeakPanel)); // eslint-disable-line
\ No newline at end of file
diff --git a/dist/constants/action_type.js b/dist/constants/action_type.js
new file mode 100644
index 00000000..820cb066
--- /dev/null
+++ b/dist/constants/action_type.js
@@ -0,0 +1,154 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.XRD = exports.UI = exports.THRESHOLD = exports.SUBMIT = exports.STATUS = exports.SIMULATION = exports.SHIFT = exports.SEC = exports.SCAN = exports.MULTIPLICITY = exports.META = exports.MANAGER = exports.LAYOUT = exports.JCAMP = exports.INTEGRATION = exports.FORECAST = exports.EDITPEAK = exports.CYCLIC_VOLTA_METRY = exports.CURVE = exports.AXES = void 0;
+const THRESHOLD = exports.THRESHOLD = {
+ UPDATE_VALUE: 'THRESHOLD_UPDATE_VALUE',
+ RESET_VALUE: 'THRESHOLD_RESET_VALUE',
+ TOGGLE_ISEDIT: 'THRESHOLD_TOGGLE_ISEDIT',
+ UPDATE_UPPER_VALUE: 'THRESHOLD_UPDATE_UPPER_VALUE',
+ UPDATE_LOWER_VALUE: 'THRESHOLD_UPDATE_LOWER_VALUE'
+};
+const EDITPEAK = exports.EDITPEAK = {
+ ADD_POSITIVE: 'ADD_TO_POSITIVE_EDITPEAK_LIST',
+ ADD_NEGATIVE: 'ADD_TO_NEGATIVE_EDITPEAK_LIST',
+ RM_NEGATIVE: 'RM_FROM_NEGATIVE_EDITPEAK_LIST',
+ RM_POSITIVE: 'RM_FROM_POSITIVE_EDITPEAK_LIST',
+ SHIFT: 'EDITPEAK_SHIFT',
+ CLEAR_ALL: 'EDITPEAK_CLEAR_ALL'
+};
+const STATUS = exports.STATUS = {
+ TOGGLEBTNSUBMIT: 'TOGGLE_BTN_SUBMIT',
+ TOGGLEBTNALL: 'TOGGLE_BTN_ALL',
+ ENABLEBTNALL: 'ENABLE_BTN_ALL'
+};
+const MANAGER = exports.MANAGER = {
+ RESETALL: 'RESET_ALL',
+ RESETSHIFT: 'RESET_SHIFT',
+ RESET_INIT_COMMON: 'RESET_INIT_COMMON',
+ RESET_INIT_NMR: 'RESET_INIT_NMR',
+ RESET_INIT_MS: 'RESET_INIT_MS',
+ RESET_INIT_COMMON_WITH_INTERGATION: 'RESET_INIT_COMMON_WITH_INTERGATION',
+ RESET_DETECTOR: 'RESET_DETECTOR',
+ RESET_MULTIPLICITY: 'RESET_MULTIPLICITY'
+};
+const LAYOUT = exports.LAYOUT = {
+ UPDATE: 'UPDATE_LAYOUT'
+};
+const SHIFT = exports.SHIFT = {
+ SET_REF: 'SHIFT_SET_REF',
+ SET_PEAK: 'SHIFT_SET_PEAK',
+ RM_PEAK: 'SHIFT_RM_PEAK'
+};
+const SCAN = exports.SCAN = {
+ SET_TARGET: 'SCAN_SET_TARGET',
+ RESET_TARGET: 'SCAN_RESET_TARGET',
+ TOGGLE_ISAUTO: 'SCAN_TOGGLE_ISAUTO'
+};
+const UI = exports.UI = {
+ CLICK_TARGET: 'UI_CLICK_TARGET',
+ VIEWER: {
+ SET_TYPE: 'UI_VIEWER_SET_TYPE'
+ },
+ SWEEP: {
+ SET_TYPE: 'UI_SWEEP_SET_TYPE',
+ SELECT: 'UI_SWEEP_SELECT',
+ SELECT_ZOOMIN: 'UI_SWEEP_SELECT_ZOOMIN',
+ SELECT_ZOOMRESET: 'UI_SWEEP_SELECT_ZOOMRESET',
+ SELECT_INTEGRATION: 'UI_SWEEP_SELECT_INTEGRATION',
+ SELECT_MULTIPLICITY: 'UI_SWEEP_SELECT_MULTIPLICITY',
+ SELECT_MULTIPLICITY_RDC: 'UI_SWEEP_SELECT_MULTIPLICITY_RDC'
+ },
+ WHEEL: {
+ SCROLL: 'UI_WHEEL_SCROLL'
+ }
+};
+const FORECAST = exports.FORECAST = {
+ INIT_STATUS: 'FORECAST_INIT_STATUS',
+ SET_IR_STATUS: 'FORECAST_SET_IR_STATUS',
+ SET_NMR_STATUS: 'FORECAST_SET_NMR_STATUS',
+ CLEAR_STATUS: 'FORECAST_CLEAR_STATUS'
+};
+const SUBMIT = exports.SUBMIT = {
+ TOGGLE_IS_ASCEND: 'SUBMIT_TOGGLE_IS_ASCEND',
+ TOGGLE_IS_INTENSITY: 'SUBMIT_TOGGLE_IS_INTENSITY',
+ UPDATE_OPERATION: 'SUBMIT_UPDATE_OPERATION',
+ UPDATE_DECIMAL: 'SUBMIT_UPDATE_DECIMAL'
+};
+const INTEGRATION = exports.INTEGRATION = {
+ RM_ONE: 'INTEGRATION_RM_ONE',
+ SET_REF: 'INTEGRATION_SET_REF',
+ SET_FKR: 'INTEGRATION_SET_FKR',
+ RESET_ALL_RDC: 'INTEGRATION_RESET_ALL_RDC',
+ CLEAR_ALL: 'INTEGRATION_CLEAR_ALL',
+ SWEEP: 'INTEGRATION_SWEEP',
+ SPLIT: 'INTEGRATION_SPLIT'
+};
+const SIMULATION = exports.SIMULATION = {
+ RESET_ALL_RDC: 'SIMULATION_RESET_ALL_RDC'
+};
+const MULTIPLICITY = exports.MULTIPLICITY = {
+ ONE_CLICK: 'MULTIPLICITY_ONE_CLICK',
+ ONE_CLICK_BY_UI: 'MULTIPLICITY_ONE_CLICK_BY_UI',
+ PEAK_RM_BY_PANEL: 'MULTIPLICITY_PEAK_RM_BY_PANEL',
+ PEAK_RM_BY_PANEL_RDC: 'MULTIPLICITY_PEAK_RM_BY_PANEL_RDC',
+ PEAK_ADD_BY_UI_SAG: 'MULTIPLICITY_PEAK_ADD_BY_UI_SAG',
+ PEAK_ADD_BY_UI_RDC: 'MULTIPLICITY_PEAK_ADD_BY_UI_RDC',
+ PEAK_RM_BY_UI: 'MULTIPLICITY_PEAK_RM_BY_UI',
+ PEAK_RM_BY_UI_RDC: 'MULTIPLICITY_PEAK_RM_BY_UI_RDC',
+ TYPE_SELECT: 'MULTIPLICITY_TYPE_SELECT',
+ TYPE_SELECT_RDC: 'MULTIPLICITY_TYPE_SELECT_RDC',
+ RESET_ALL_RDC: 'MULTIPLICITY_RESET_ALL_RDC',
+ RESET_ONE: 'MULTIPLICITY_RESET_ONE',
+ RESET_ONE_RDC: 'MULTIPLICITY_RESET_ONE_RDC',
+ UPDATE_J: 'MULTIPLICITY_UPDATE_J',
+ CLEAR_ALL: 'MULTIPLICITY_CLEAR_ALL'
+};
+const META = exports.META = {
+ UPDATE_PEAKS: 'META_UPDATE_PEAKS',
+ UPDATE_PEAKS_RDC: 'META_UPDATE_PEAKS_RDC',
+ UPDATE_META_DATA: 'UPDATE_META_DATA',
+ UPDATE_META_DATA_RDC: 'UPDATE_META_DATA_RDC'
+};
+const JCAMP = exports.JCAMP = {
+ ADD_OTHERS: 'JCAMP_ADD_OTHERS',
+ RM_OTHERS_ONE: 'JCAMP_RM_OTHERS_ONE',
+ TOGGLE_SHOW: 'JCAMP_TOGGLE_SHOW',
+ CLEAR_ALL: 'JCAMP_CLEAR_ALL'
+};
+const XRD = exports.XRD = {
+ UPDATE_WAVE_LENGTH: 'UPDATE_WAVE_LENGTH'
+};
+const CYCLIC_VOLTA_METRY = exports.CYCLIC_VOLTA_METRY = {
+ ADD_PAIR_PEAKS: 'ADD_PAIR_PEAKS',
+ REMOVE_PAIR_PEAKS: 'REMOVE_PAIR_PEAKS',
+ ADD_MAX_PEAK: 'ADD_MAX_PEAK',
+ REMOVE_MAX_PEAK: 'REMOVE_MAX_PEAK',
+ ADD_MIN_PEAK: 'ADD_MIN_PEAK',
+ REMOVE_MIN_PEAK: 'REMOVE_MIN_PEAK',
+ SELECT_PAIR_PEAK: 'SELECT_PAIR_PEAK',
+ WORK_WITH_MAX_PEAK: 'WORK_WITH_MAX_PEAK',
+ ADD_PECKER: 'ADD_PECKER',
+ REMOVE_PECKER: 'REMOVE_PECKER',
+ RESETALL: 'RESETALL_VOLTA_METRY',
+ SET_REF: 'VOLTA_METRY_SET_REF',
+ SELECT_REF_PEAK: 'SELECT_REF_PEAK',
+ SET_FACTOR: 'CYCLIC_VOLTA_METRY_SET_FACTOR',
+ SET_AREA_VALUE: 'CYCLIC_VOLTA_METRY_SET_AREA_VALUE',
+ SET_AREA_UNIT: 'CYCLIC_VOLTA_METRY_SET_AREA_UNIT',
+ TOGGLE_DENSITY: 'CYCLIC_VOLTA_METRY_TOGGLE_DENSITY'
+};
+const CURVE = exports.CURVE = {
+ SELECT_WORKING_CURVE: 'SELECT_WORKING_CURVE',
+ SET_ALL_CURVES: 'SET_ALL_CURVES',
+ SET_SHOULD_SHOW_ALL_CURVES: 'SET_SHOULD_SHOW_ALL_CURVES'
+};
+const AXES = exports.AXES = {
+ UPDATE_X_AXIS: 'UPDATE_X_AXIS',
+ UPDATE_Y_AXIS: 'UPDATE_Y_AXIS'
+};
+const SEC = exports.SEC = {
+ UPDATE_DETECTOR: 'UPDATE_DETECTOR'
+};
\ No newline at end of file
diff --git a/dist/constants/list_axes.js b/dist/constants/list_axes.js
new file mode 100644
index 00000000..0936a991
--- /dev/null
+++ b/dist/constants/list_axes.js
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.LIST_AXES = void 0;
+var _list_layout = require("./list_layout");
+const optionsAxisX = {
+ [_list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY]: ['', 'Voltage in V', 'Voltage vs Ref in V', 'Potential in V', 'Potential vs Ref in V']
+};
+const optionsAxisY = {
+ [_list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY]: ['', 'Current in A', 'Current in mA']
+};
+const LIST_AXES = exports.LIST_AXES = {
+ x: optionsAxisX,
+ y: optionsAxisY
+};
\ No newline at end of file
diff --git a/dist/constants/list_detectors.js b/dist/constants/list_detectors.js
new file mode 100644
index 00000000..fcbda7ec
--- /dev/null
+++ b/dist/constants/list_detectors.js
@@ -0,0 +1,15 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.LIST_DETECTORS = void 0;
+const rI = {
+ name: 'Refractive index',
+ label: 'RI'
+};
+const uV = {
+ name: 'Ultraviolet',
+ label: 'UV'
+};
+const LIST_DETECTORS = exports.LIST_DETECTORS = [rI, uV];
\ No newline at end of file
diff --git a/dist/constants/list_layout.js b/dist/constants/list_layout.js
new file mode 100644
index 00000000..cf5830ed
--- /dev/null
+++ b/dist/constants/list_layout.js
@@ -0,0 +1,31 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.LIST_LAYOUT = void 0;
+const LIST_LAYOUT = exports.LIST_LAYOUT = {
+ PLAIN: 'PLAIN',
+ IR: 'IR',
+ RAMAN: 'RAMAN',
+ UVVIS: 'UV/VIS',
+ H1: '1H',
+ C13: '13C',
+ F19: '19F',
+ P31: '31P',
+ N15: '15N',
+ Si29: '29Si',
+ MS: 'MS',
+ TGA: 'THERMOGRAVIMETRIC ANALYSIS',
+ XRD: 'X-RAY DIFFRACTION',
+ HPLC_UVVIS: 'HPLC UV/VIS',
+ CYCLIC_VOLTAMMETRY: 'CYCLIC VOLTAMMETRY',
+ CDS: 'CIRCULAR DICHROISM SPECTROSCOPY',
+ SEC: 'SIZE EXCLUSION CHROMATOGRAPHY',
+ AIF: 'AIF',
+ EMISSIONS: 'Emissions',
+ DLS_ACF: 'DLS ACF',
+ DLS_INTENSITY: 'DLS intensity',
+ DSC: 'DIFFERENTIAL SCANNING CALORIMETRY',
+ GC: 'GAS CHROMATOGRAPHY'
+};
\ No newline at end of file
diff --git a/dist/constants/list_shift.js b/dist/constants/list_shift.js
new file mode 100644
index 00000000..63eaf99d
--- /dev/null
+++ b/dist/constants/list_shift.js
@@ -0,0 +1,421 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.getListShift = exports.LIST_SHIFT_31P = exports.LIST_SHIFT_29Si = exports.LIST_SHIFT_1H = exports.LIST_SHIFT_19F = exports.LIST_SHIFT_15N = exports.LIST_SHIFT_13C = void 0;
+var _list_layout = require("./list_layout");
+/* eslint-disable camelcase */
+
+const noReference = {
+ name: '- - -',
+ value: 0.0,
+ label: false
+};
+const cActicAcidD4Sept = {
+ name: 'Acetic acid-d4 (sept)',
+ value: 20.0,
+ label: 'Acetic acid-d4'
+};
+const cActicAcidD4S = {
+ name: 'Acetic acid-d4 (s)',
+ value: 178.990,
+ label: 'Acetic acid-d4'
+};
+const cAcetoneD6Sep = {
+ name: 'Acetone-d6 (sep)',
+ value: 29.640,
+ label: 'Acetone-d6',
+ nsdb: 'Acetone-D6 ((CD3)2CO)'
+};
+const cAcetoneD6Broad = {
+ name: 'Acetone-d6 (broad)',
+ value: 206.260,
+ label: 'Acetone-d6',
+ nsdb: 'Acetone-D6 ((CD3)2CO)'
+};
+const cAcetonitrileD3Sep = {
+ name: 'Acetonitrile-d3 (sep)',
+ value: 1.32,
+ label: 'Acetonitrile-d3',
+ nsdb: 'Acetonitrile-D3(CD3CN)'
+};
+const cAcetonitrileD3S = {
+ name: 'Acetonitrile-d3 (s)',
+ value: 118.26,
+ label: 'Acetonitrile-d3',
+ nsdb: 'Acetonitrile-D3(CD3CN)'
+};
+const cBenzeneT = {
+ name: 'Benzene (t)',
+ value: 128.060,
+ label: 'Benzene-d6',
+ nsdb: 'Benzene-D6 (C6D6)'
+};
+const cChloroformDT = {
+ name: 'Chloroform-d (t)',
+ value: 77.16,
+ label: 'CDCl$3',
+ nsdb: 'Chloroform-D1 (CDCl3)'
+};
+const cCyclohexaneD12Quin = {
+ name: 'Cyclohexane-d12 (quin)',
+ value: 26.430,
+ label: 'C$6D$1$2'
+};
+const cDichloromethaneD2Quin = {
+ name: 'Dichloromethane-d2 (quin)',
+ value: 53.84,
+ label: 'CD$2Cl$2'
+};
+const cDmfD7Sep1 = {
+ name: 'DMF-d7 (sep)-1',
+ value: 29.76,
+ label: 'DMF-d7'
+};
+const cDmfD7Sep2 = {
+ name: 'DMF-d7 (sep)-2',
+ value: 34.89,
+ label: 'DMF-d7'
+};
+const cDmfD7T3 = {
+ name: 'DMF-d7 (t)-3',
+ value: 163.15,
+ label: 'DMF-d7'
+};
+const cDioxaneD8Quin = {
+ name: 'Dioxane-d8 (quin)',
+ value: 66.660,
+ label: 'Dioxane-d8'
+};
+const cDmsoD6 = {
+ name: 'DMSO-d6',
+ value: 39.52,
+ label: 'DMSO-d6',
+ nsdb: 'Dimethylsulphoxide-D6 (DMSO-D6, C2D6SO)'
+};
+const cEthanolD6Sep = {
+ name: 'Ethanol-d6 (sep)',
+ value: 17.3,
+ label: 'Ethanol-d6'
+};
+const cEthanolD6Quin = {
+ name: 'Ethanol-d6 (quin)',
+ value: 56.96,
+ label: 'Ethanol-d6'
+};
+const cMethanolD4Sep = {
+ name: 'Methanol-d4 (sep)',
+ value: 49.00,
+ label: 'Methanol-d4',
+ nsdb: 'Methanol-D4 (CD3OD)'
+};
+const cPyridineD5T1 = {
+ name: 'Pyridine-d5 (t)-1',
+ value: 123.87,
+ label: 'Pyridine-d5',
+ nsdb: 'Pyridin-D5 (C5D5N)'
+};
+const cPyridineD5T2 = {
+ name: 'Pyridine-d5 (t)-2',
+ value: 135.91,
+ label: 'Pyridine-d5',
+ nsdb: 'Pyridin-D5 (C5D5N)'
+};
+const cPyridineD5T3 = {
+ name: 'Pyridine-d5 (t)-3',
+ value: 150.35,
+ label: 'Pyridine-d5',
+ nsdb: 'Pyridin-D5 (C5D5N)'
+};
+const cThfD8Quin1 = {
+ name: 'THF-d8 (quin)-1',
+ value: 25.37,
+ label: 'THF-d8 ',
+ nsdb: 'Tetrahydrofuran-D8 (THF-D8, C4D4O)'
+};
+const cThfD8Quin2 = {
+ name: 'THF-d8 (quin)-2',
+ value: 67.57,
+ label: 'THF-d8 ',
+ nsdb: 'Tetrahydrofuran-D8 (THF-D8, C4D4O)'
+};
+const cTmsS = {
+ name: 'TMS (s)',
+ value: 0.00,
+ label: 'TMS'
+};
+const cTolueneD8Sep1 = {
+ name: 'Toluene-d8 (sep)-1',
+ value: 20.4,
+ label: 'Toluene-d8'
+};
+const cTolueneD8T2 = {
+ name: 'Toluene-d8 (t)-2',
+ value: 125.49,
+ label: 'Toluene-d8'
+};
+const cTolueneD8T3 = {
+ name: 'Toluene-d8 (t)-3',
+ value: 128.33,
+ label: 'Toluene-d8'
+};
+const cTolueneD8T4 = {
+ name: 'Toluene-d8 (t)-4',
+ value: 129.24,
+ label: 'Toluene-d8'
+};
+const cTolueneD8T5 = {
+ name: 'Toluene-d8 (s)-5',
+ value: 137.86,
+ label: 'Toluene-d8'
+};
+const cTfaDQ1 = {
+ name: 'TFA-d (q)-1',
+ value: 116.60,
+ label: 'TFA-d'
+};
+const cTfaDQ2 = {
+ name: 'TFA-d (q)-2',
+ value: 164.20,
+ label: 'TFA-d'
+};
+const cTrifluoroethanolD3Quin = {
+ name: 'Trifluoroethanol-d3 (quin)',
+ value: 61.80,
+ label: 'Trifluoroethanol-d3'
+};
+const cTrifluoroethanolD3Broad = {
+ name: 'Trifluoroethanol-d3 (broad)',
+ value: 126.28,
+ label: 'Trifluoroethanol-d3'
+};
+const cC6D5Cl1 = {
+ name: 'C6D5Cl (s)',
+ value: 134.19,
+ label: 'C6D5Cl'
+};
+const cC6D5Cl2 = {
+ name: 'C6D5Cl (t)-1',
+ value: 129.26,
+ label: 'C6D5Cl'
+};
+const cC6D5Cl3 = {
+ name: 'C6D5Cl (t)-2',
+ value: 128.25,
+ label: 'C6D5Cl'
+};
+const cC6D5Cl4 = {
+ name: 'C6D5Cl (t)-3',
+ value: 125.96,
+ label: 'C6D5Cl'
+};
+const LIST_SHIFT_13C = exports.LIST_SHIFT_13C = [noReference, cActicAcidD4Sept, cActicAcidD4S, cAcetoneD6Sep, cAcetoneD6Broad, cAcetonitrileD3Sep, cAcetonitrileD3S, cBenzeneT, cChloroformDT, cCyclohexaneD12Quin, cDichloromethaneD2Quin, cDmfD7Sep1, cDmfD7Sep2, cDmfD7T3, cDioxaneD8Quin, cDmsoD6, cEthanolD6Sep, cEthanolD6Quin, cMethanolD4Sep, cPyridineD5T1, cPyridineD5T2, cPyridineD5T3, cThfD8Quin1, cThfD8Quin2, cTmsS, cTolueneD8Sep1, cTolueneD8T2, cTolueneD8T3, cTolueneD8T4, cTolueneD8T5, cTfaDQ1, cTfaDQ2, cTrifluoroethanolD3Quin, cTrifluoroethanolD3Broad, cC6D5Cl1, cC6D5Cl2, cC6D5Cl3, cC6D5Cl4];
+const hActicAcidD4Quin = {
+ name: 'Acetic acid-d4 (quin)',
+ value: 2.04,
+ label: 'Acetic acid-d4'
+};
+const hActicAcidD4S = {
+ name: 'Acetic acid-d4 (s)',
+ value: 11.65,
+ label: 'Acetic acid-d4'
+};
+const hAcetoneD6Quin = {
+ name: 'Acetone-d6 (quin)',
+ value: 2.05,
+ label: 'Acetone-d6',
+ nsdb: 'Acetone-D6 ((CD3)2CO)'
+};
+const hAcetonitrileD3Qquin = {
+ name: 'Acetonitrile-d3 (quin)',
+ value: 1.94,
+ label: 'Acetonitrile-d3',
+ nsdb: 'Acetonitrile-D3(CD3CN)'
+};
+const hBenzeneS = {
+ name: 'Benzene (s)',
+ value: 7.16,
+ label: 'Benzene-d6',
+ nsdb: 'Benzene-D6 (C6D6)'
+};
+const hChloroformDS = {
+ name: 'Chloroform-d (s)',
+ value: 7.26,
+ label: 'CDCl$3',
+ nsdb: 'Chloroform-D1 (CDCl3)'
+};
+const hCyclohexaneD12S = {
+ name: 'Cyclohexane-d12 (s)',
+ value: 1.38,
+ label: 'C$6D$1$2'
+};
+const hDeuteriumOxideS = {
+ name: 'D2O (s)',
+ value: 4.79,
+ label: 'D$2O',
+ nsdb: 'Deuteriumoxide (D2O)'
+};
+const hDichloroethaneD4S = {
+ name: 'Dichloroethane-d4 (s)',
+ value: 3.72,
+ label: 'Dichloroethane-d4'
+};
+const hDichloromethaneD2T = {
+ name: 'Dichloromethane-d2 (t)',
+ value: 5.32,
+ label: 'CD2Cl2',
+ nsdb: 'Methylenchloride-D2 (CD2Cl2)'
+};
+const hDMFD7Quin1 = {
+ name: 'DMF-d7 (quin)-1',
+ value: 2.75,
+ label: 'DMF-d7'
+};
+const hDMFD7Quin2 = {
+ name: 'DMF-d7 (quin)-2',
+ value: 2.92,
+ label: 'DMF-d7'
+};
+const hDMFD7Broad3 = {
+ name: 'DMF-d7 (broad)-3',
+ value: 8.03,
+ label: 'DMF-d7'
+};
+const hDioxaneD8Broad = {
+ name: 'Dioxane-d8 (broad)',
+ value: 3.53,
+ label: 'Dioxane-d8'
+};
+const hDMSOD6Quin = {
+ name: 'DMSO-d6 (quin)',
+ value: 2.50,
+ label: 'DMSO-d6',
+ nsdb: 'Dimethylsulphoxide-D6 (DMSO-D6, C2D6SO)'
+};
+const hEthanolD6Broad1 = {
+ name: 'Ethanol-d6 (broad)-1',
+ value: 1.11,
+ label: 'Ethanol-d6'
+};
+const hEthanolD6S2 = {
+ name: 'Ethanol-d6 (s)-2',
+ value: 3.56,
+ label: 'Ethanol-d6'
+};
+const hEthanolD6S3 = {
+ name: 'Ethanol-d6 (s)-3',
+ value: 5.29,
+ label: 'Ethanol-d6'
+};
+const hMethanolD4Quin = {
+ name: 'Methanol-d4 (quin)',
+ value: 3.31,
+ label: 'Methanol-d4',
+ nsdb: 'Methanol-D4 (CD3OD)'
+};
+const hMethanolD4S = {
+ name: 'Methanol-d4 (s)',
+ value: 4.87,
+ label: 'Methanol-d4',
+ nsdb: 'Methanol-D4 (CD3OD)'
+};
+const hNitromethaneD3S = {
+ name: 'Nitromethane-d3 (s)',
+ value: 4.33,
+ label: 'Nitromethane-d3'
+};
+const hPyridineD5Broad1 = {
+ name: 'Pyridine-d5 (broad)-1',
+ value: 7.22,
+ label: 'Pyridine-d5',
+ nsdb: 'Pyridin-D5 (C5D5N)'
+};
+const hPyridineD5Broad2 = {
+ name: 'Pyridine-d5 (broad)-2',
+ value: 7.58,
+ label: 'Pyridine-d5',
+ nsdb: 'Pyridin-D5 (C5D5N)'
+};
+const hPyridineD5Broad3 = {
+ name: 'Pyridine-d5 (broad)-3',
+ value: 8.74,
+ label: 'Pyridine-d5',
+ nsdb: 'Pyridin-D5 (C5D5N)'
+};
+const hTHFD8S1 = {
+ name: 'THF-d8 (s)-1',
+ value: 1.73,
+ label: 'THF-d8',
+ nsdb: 'Tetrahydrofuran-D8 (THF-D8, C4D4O)'
+};
+const hTHFD8S2 = {
+ name: 'THF-d8 (s)-2',
+ value: 3.58,
+ label: 'THF-d8',
+ nsdb: 'Tetrahydrofuran-D8 (THF-D8, C4D4O)'
+};
+const hTMSS = {
+ name: 'TMS (s)',
+ value: 0.0,
+ label: 'TMS'
+};
+const hTolueneD8Quin = {
+ name: 'Toluene-d8 (quin)-1',
+ value: 2.09,
+ label: 'Toluene-d8'
+};
+const hTolueneD8Boad2 = {
+ name: 'Toluene-d8 (boad)-2',
+ value: 6.98,
+ label: 'Toluene-d8'
+};
+const hTolueneD8S3 = {
+ name: 'Toluene-d8 (s)-3',
+ value: 7.00,
+ label: 'Toluene-d8'
+};
+const hTolueneD8Broad4 = {
+ name: 'Toluene-d8 (broad)-4',
+ value: 7.09,
+ label: 'Toluene-d8'
+};
+const hTFADS = {
+ name: 'TFA-d (s)',
+ value: 11.5,
+ label: 'TFA-d'
+};
+const hTrifluoroethanolD31 = {
+ name: 'Trifluoroethanol-d3-1',
+ value: 3.88,
+ label: 'Trifluoroethanol-d3'
+};
+const hTrifluoroethanolD32 = {
+ name: 'Trifluoroethanol-d3-2',
+ value: 5.02,
+ label: 'Trifluoroethanol-d3'
+};
+const LIST_SHIFT_1H = exports.LIST_SHIFT_1H = [noReference, hActicAcidD4Quin, hActicAcidD4S, hAcetoneD6Quin, hAcetonitrileD3Qquin, hBenzeneS, hChloroformDS, hCyclohexaneD12S, hDeuteriumOxideS, hDichloroethaneD4S, hDichloromethaneD2T, hDMFD7Quin1, hDMFD7Quin2, hDMFD7Broad3, hDioxaneD8Broad, hDMSOD6Quin, hEthanolD6Broad1, hEthanolD6S2, hEthanolD6S3, hMethanolD4Quin, hMethanolD4S, hNitromethaneD3S, hPyridineD5Broad1, hPyridineD5Broad2, hPyridineD5Broad3, hTHFD8S1, hTHFD8S2, hTMSS, hTolueneD8Quin, hTolueneD8Boad2, hTolueneD8S3, hTolueneD8Broad4, hTFADS, hTrifluoroethanolD31, hTrifluoroethanolD32];
+const LIST_SHIFT_19F = exports.LIST_SHIFT_19F = [noReference, hActicAcidD4Quin, hActicAcidD4S, hAcetoneD6Quin, hAcetonitrileD3Qquin, hBenzeneS, hChloroformDS, hCyclohexaneD12S, hDeuteriumOxideS, hDichloroethaneD4S, hDichloromethaneD2T, hDMFD7Quin1, hDMFD7Quin2, hDMFD7Broad3, hDioxaneD8Broad, hDMSOD6Quin, hEthanolD6Broad1, hEthanolD6S2, hEthanolD6S3, hMethanolD4Quin, hMethanolD4S, hNitromethaneD3S, hPyridineD5Broad1, hPyridineD5Broad2, hPyridineD5Broad3, hTHFD8S1, hTHFD8S2, hTMSS, hTolueneD8Quin, hTolueneD8Boad2, hTolueneD8S3, hTolueneD8Broad4, hTFADS, hTrifluoroethanolD31, hTrifluoroethanolD32];
+const LIST_SHIFT_31P = exports.LIST_SHIFT_31P = [noReference, hActicAcidD4Quin, hActicAcidD4S, hAcetoneD6Quin, hAcetonitrileD3Qquin, hBenzeneS, hChloroformDS, hCyclohexaneD12S, hDeuteriumOxideS, hDichloroethaneD4S, hDichloromethaneD2T, hDMFD7Quin1, hDMFD7Quin2, hDMFD7Broad3, hDioxaneD8Broad, hDMSOD6Quin, hEthanolD6Broad1, hEthanolD6S2, hEthanolD6S3, hMethanolD4Quin, hMethanolD4S, hNitromethaneD3S, hPyridineD5Broad1, hPyridineD5Broad2, hPyridineD5Broad3, hTHFD8S1, hTHFD8S2, hTMSS, hTolueneD8Quin, hTolueneD8Boad2, hTolueneD8S3, hTolueneD8Broad4, hTFADS, hTrifluoroethanolD31, hTrifluoroethanolD32];
+const LIST_SHIFT_15N = exports.LIST_SHIFT_15N = [noReference, hActicAcidD4Quin, hActicAcidD4S, hAcetoneD6Quin, hAcetonitrileD3Qquin, hBenzeneS, hChloroformDS, hCyclohexaneD12S, hDeuteriumOxideS, hDichloroethaneD4S, hDichloromethaneD2T, hDMFD7Quin1, hDMFD7Quin2, hDMFD7Broad3, hDioxaneD8Broad, hDMSOD6Quin, hEthanolD6Broad1, hEthanolD6S2, hEthanolD6S3, hMethanolD4Quin, hMethanolD4S, hNitromethaneD3S, hPyridineD5Broad1, hPyridineD5Broad2, hPyridineD5Broad3, hTHFD8S1, hTHFD8S2, hTMSS, hTolueneD8Quin, hTolueneD8Boad2, hTolueneD8S3, hTolueneD8Broad4, hTFADS, hTrifluoroethanolD31, hTrifluoroethanolD32];
+const LIST_SHIFT_29Si = exports.LIST_SHIFT_29Si = [noReference, hActicAcidD4Quin, hActicAcidD4S, hAcetoneD6Quin, hAcetonitrileD3Qquin, hBenzeneS, hChloroformDS, hCyclohexaneD12S, hDeuteriumOxideS, hDichloroethaneD4S, hDichloromethaneD2T, hDMFD7Quin1, hDMFD7Quin2, hDMFD7Broad3, hDioxaneD8Broad, hDMSOD6Quin, hEthanolD6Broad1, hEthanolD6S2, hEthanolD6S3, hMethanolD4Quin, hMethanolD4S, hNitromethaneD3S, hPyridineD5Broad1, hPyridineD5Broad2, hPyridineD5Broad3, hTHFD8S1, hTHFD8S2, hTMSS, hTolueneD8Quin, hTolueneD8Boad2, hTolueneD8S3, hTolueneD8Broad4, hTFADS, hTrifluoroethanolD31, hTrifluoroethanolD32];
+const getListShift = layoutSt => {
+ switch (layoutSt) {
+ case _list_layout.LIST_LAYOUT.H1:
+ return LIST_SHIFT_1H;
+ case _list_layout.LIST_LAYOUT.C13:
+ return LIST_SHIFT_13C;
+ case _list_layout.LIST_LAYOUT.F19:
+ return LIST_SHIFT_19F;
+ case _list_layout.LIST_LAYOUT.P31:
+ return LIST_SHIFT_31P;
+ case _list_layout.LIST_LAYOUT.N15:
+ return LIST_SHIFT_15N;
+ case _list_layout.LIST_LAYOUT.Si29:
+ return LIST_SHIFT_29Si;
+ default:
+ return [];
+ }
+};
+exports.getListShift = getListShift;
\ No newline at end of file
diff --git a/dist/constants/list_ui.js b/dist/constants/list_ui.js
new file mode 100644
index 00000000..2eb5549d
--- /dev/null
+++ b/dist/constants/list_ui.js
@@ -0,0 +1,36 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.LIST_UI_VIEWER_TYPE = exports.LIST_UI_SWEEP_TYPE = exports.LIST_NON_BRUSH_TYPES = void 0;
+const LIST_UI_VIEWER_TYPE = exports.LIST_UI_VIEWER_TYPE = {
+ SPECTRUM: 'spectrum',
+ ANALYSIS: 'analysis'
+};
+const LIST_UI_SWEEP_TYPE = exports.LIST_UI_SWEEP_TYPE = {
+ ZOOMIN: 'zoom in',
+ ZOOMRESET: 'zoom reset',
+ INTEGRATION_ADD: 'integration add',
+ INTEGRATION_RM: 'integration remove',
+ INTEGRATION_REF: 'integration reference',
+ INTEGRATION_SET_REF: 'integration set ref',
+ INTEGRATION_SPLIT: 'integration split',
+ MULTIPLICITY_SWEEP_ADD: 'multiplicity sweep add',
+ MULTIPLICITY_ONE_CLICK: 'multiplicity one click',
+ MULTIPLICITY_ONE_RM: 'multiplicity one remove',
+ MULTIPLICITY_PEAK_ADD: 'multiplicity peak add',
+ MULTIPLICITY_PEAK_RM: 'multiplicity peak remove',
+ MULTIPLICITY_ALL_CLEAR: 'multiplicity all clear',
+ PEAK_ADD: 'peak add',
+ PEAK_DELETE: 'peak delete',
+ ANCHOR_SHIFT: 'anchor shift',
+ CYCLIC_VOLTA_ADD_MAX_PEAK: 'cyclic voltammetry add max peak',
+ CYCLIC_VOLTA_RM_MAX_PEAK: 'cyclic voltammetry remove max peak',
+ CYCLIC_VOLTA_ADD_MIN_PEAK: 'cyclic voltammetry add min peak',
+ CYCLIC_VOLTA_RM_MIN_PEAK: 'cyclic voltammetry remove min peak',
+ CYCLIC_VOLTA_ADD_PECKER: 'cyclic voltammetry add pecker',
+ CYCLIC_VOLTA_RM_PECKER: 'cyclic voltammetry remove pecker',
+ CYCLIC_VOLTA_SET_REF: 'cyclic voltammetry set ref'
+};
+const LIST_NON_BRUSH_TYPES = exports.LIST_NON_BRUSH_TYPES = [LIST_UI_SWEEP_TYPE.PEAK_ADD, LIST_UI_SWEEP_TYPE.PEAK_DELETE, LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT, LIST_UI_SWEEP_TYPE.INTEGRATION_RM, LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF, LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_ADD, LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_RM, LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_CLICK, LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_RM, LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MAX_PEAK, LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK, LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK, LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK, LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_PECKER, LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_PECKER, LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_SET_REF];
\ No newline at end of file
diff --git a/dist/constants/list_wavelength.js b/dist/constants/list_wavelength.js
new file mode 100644
index 00000000..2643b05d
--- /dev/null
+++ b/dist/constants/list_wavelength.js
@@ -0,0 +1,31 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.LIST_WAVE_LENGTH = void 0;
+const CuKalpha = {
+ name: 'CuKalpha',
+ value: 0.15406,
+ label: 'Cu K\u03B1',
+ unit: 'nm'
+};
+const Fe = {
+ name: 'Fe',
+ value: 0.19373,
+ label: 'Fe',
+ unit: 'nm'
+};
+const Co = {
+ name: 'Co',
+ value: 0.17902,
+ label: 'Co',
+ unit: 'nm'
+};
+const MoKalpha = {
+ name: 'MoKalpha',
+ value: 0.07107,
+ label: 'Mo K\u03B1',
+ unit: 'nm'
+};
+const LIST_WAVE_LENGTH = exports.LIST_WAVE_LENGTH = [CuKalpha, Fe, Co, MoKalpha];
\ No newline at end of file
diff --git a/dist/fn.js b/dist/fn.js
new file mode 100644
index 00000000..348a8fe8
--- /dev/null
+++ b/dist/fn.js
@@ -0,0 +1,23 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _format = _interopRequireDefault(require("./helpers/format"));
+var _chem = require("./helpers/chem");
+var _converter = require("./helpers/converter");
+var _multiplicity_calc = require("./helpers/multiplicity_calc");
+var _carbonFeatures = require("./helpers/carbonFeatures");
+var _list_layout = require("./constants/list_layout");
+/* eslint-disable prefer-object-spread */
+
+const FN = Object.assign({}, _format.default, {
+ ExtractJcamp: _chem.ExtractJcamp,
+ ToXY: _converter.ToXY,
+ LIST_LAYOUT: _list_layout.LIST_LAYOUT,
+ CalcMpyCenter: _multiplicity_calc.calcMpyCenter,
+ CarbonFeatures: _carbonFeatures.carbonFeatures
+});
+var _default = exports.default = FN;
\ No newline at end of file
diff --git a/dist/helpers/brush.js b/dist/helpers/brush.js
new file mode 100644
index 00000000..03994697
--- /dev/null
+++ b/dist/helpers/brush.js
@@ -0,0 +1,116 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _compass = require("./compass");
+var _integration_draft = require("./integration_draft.js");
+var _sweep = require("./sweep.js");
+/* eslint-disable prefer-object-spread */
+
+// eslint-disable-line import/extensions
+// eslint-disable-line import/extensions
+
+const d3 = require('d3');
+const selectBrushLayer = (focus, selector) => {
+ const svg = focus.svg || d3.select('.d3Svg');
+ return svg.selectAll(selector);
+};
+const wheeled = (focus, event) => {
+ const {
+ currentExtent,
+ scrollUiWheelAct
+ } = focus;
+ // WORKAROUND: firefox wheel compatibilty
+ const wheelEvent = focus.isFirefox ? -event.deltaY : event.wheelDelta; // eslint-disable-line
+ const direction = wheelEvent > 0;
+ scrollUiWheelAct(Object.assign({}, currentExtent, {
+ direction
+ }));
+};
+const brushed = (focus, isUiAddIntgSt, event) => {
+ const {
+ selectUiSweepAct,
+ data,
+ dataPks,
+ brush,
+ brushX,
+ w,
+ h,
+ scales
+ } = focus;
+ const selection = event.selection && event.selection.reverse();
+ if (!selection) return;
+ let xes = [w, 0].map(scales.x.invert).sort((a, b) => a - b);
+ let yes = [h, 0].map(scales.y.invert).sort((a, b) => a - b);
+ let xExtent = {
+ xL: xes[0],
+ xU: xes[1]
+ };
+ let yExtent = {
+ yL: yes[0],
+ yU: yes[1]
+ };
+ if (isUiAddIntgSt) {
+ const payload = (0, _sweep.buildSweepPayloadFromXBounds)(focus, scales.x.invert(selection[0]), scales.x.invert(selection[1]));
+ selectUiSweepAct(payload);
+ if (brushX) {
+ selectBrushLayer(focus, '.brushX').call(brushX.move, null);
+ }
+ return;
+ }
+ const [begPt, endPt] = selection;
+ xes = [begPt[0], endPt[0]].map(scales.x.invert).sort((a, b) => a - b);
+ yes = [begPt[1], endPt[1]].map(scales.y.invert).sort((a, b) => a - b);
+ xExtent = {
+ xL: xes[0],
+ xU: xes[1]
+ };
+ yExtent = {
+ yL: yes[0],
+ yU: yes[1]
+ };
+ selectUiSweepAct({
+ xExtent,
+ yExtent,
+ data,
+ dataPks
+ });
+ selectBrushLayer(focus, '.brush').call(brush.move, null);
+};
+const MountBrush = (focus, isUiAddIntgSt, isUiNoBrushSt) => {
+ const {
+ root,
+ svg,
+ brush,
+ w,
+ h
+ } = focus;
+ svg.selectAll('.brush').remove();
+ svg.selectAll('.brushX').remove();
+ Object.assign(focus, {
+ isUiAddIntgSt
+ });
+ const {
+ firstIntegrationPoint,
+ data,
+ jcampIdx
+ } = focus;
+ const isSameIntegrationDraft = firstIntegrationPoint && firstIntegrationPoint.jcampIdx === jcampIdx && firstIntegrationPoint.dataLength === data.length;
+ if (!isUiAddIntgSt || firstIntegrationPoint && !isSameIntegrationDraft) {
+ (0, _integration_draft.clearPendingIntegrationDraft)();
+ Object.assign(focus, {
+ firstIntegrationPoint: null
+ });
+ (0, _compass.clearIntegrationPreview)(focus);
+ }
+ const brushedCb = event => brushed(focus, isUiAddIntgSt, event);
+ const wheeledCb = event => wheeled(focus, event);
+ if (isUiNoBrushSt && !isUiAddIntgSt) {
+ brush.handleSize(10).extent([[0, 0], [w, h]]).on('end', brushedCb);
+ root.append('g').attr('class', 'brush').on('mousemove', event => (0, _compass.MouseMove)(event, focus)).call(brush);
+ }
+ svg.on('wheel', wheeledCb);
+};
+var _default = exports.default = MountBrush;
\ No newline at end of file
diff --git a/dist/helpers/calc.js b/dist/helpers/calc.js
new file mode 100644
index 00000000..664ffdf8
--- /dev/null
+++ b/dist/helpers/calc.js
@@ -0,0 +1,15 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.calcSlope = exports.almostEqual = void 0;
+const almostEqual = (a, b) => Math.abs(a - b) < 0.00000001 * Math.abs(a + b);
+exports.almostEqual = almostEqual;
+const calcSlope = (x1, y1, x2, y2) => {
+ if (x2 === x1) {
+ return 0;
+ }
+ return (y2 - y1) / (x2 - x1);
+};
+exports.calcSlope = calcSlope;
\ No newline at end of file
diff --git a/dist/helpers/carbonFeatures.js b/dist/helpers/carbonFeatures.js
new file mode 100644
index 00000000..3c97f566
--- /dev/null
+++ b/dist/helpers/carbonFeatures.js
@@ -0,0 +1,51 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.carbonFeatures = void 0;
+var _multiplicity_calc = require("./multiplicity_calc");
+const carbonFeatures = (peaksEdit, multiplicitySt) => {
+ const {
+ selectedIdx,
+ multiplicities
+ } = multiplicitySt;
+ const selectedMultiplicity = multiplicities[selectedIdx];
+ const {
+ stack,
+ shift
+ } = selectedMultiplicity;
+ const nmrMpyCenters = stack.map(stk => {
+ // eslint-disable-line
+ return {
+ x: (0, _multiplicity_calc.calcMpyCenter)(stk.peaks, shift, stk.mpyType),
+ y: 0
+ };
+ });
+ let targetIdxs = [];
+ stack.forEach(stk => {
+ // find peak idxs to be removed
+ stk.peaks.forEach(p => {
+ let targetIdx = -1;
+ let minDiff = 999999999;
+ peaksEdit.forEach((pe, idx) => {
+ const xDiff = Math.abs(pe.x - p.x);
+ if (xDiff < minDiff) {
+ targetIdx = idx;
+ minDiff = xDiff;
+ }
+ });
+ targetIdxs = [...targetIdxs, targetIdx];
+ });
+ });
+ let features = [...nmrMpyCenters];
+ peaksEdit.forEach((pe, idx) => {
+ if (targetIdxs.indexOf(idx) < 0) {
+ features = [...features, pe];
+ }
+ });
+ return features;
+};
+
+// eslint-disable-line
+exports.carbonFeatures = carbonFeatures;
\ No newline at end of file
diff --git a/dist/helpers/cfg.js b/dist/helpers/cfg.js
new file mode 100644
index 00000000..4cc3b51c
--- /dev/null
+++ b/dist/helpers/cfg.js
@@ -0,0 +1,64 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _format = _interopRequireDefault(require("./format"));
+const btnCmdAnaViewer = layoutSt => _format.default.isMsLayout(layoutSt) || _format.default.isRamanLayout(layoutSt) || _format.default.is19FLayout(layoutSt) || _format.default.isUvVisLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt) || _format.default.isTGALayout(layoutSt) || _format.default.isDSCLayout(layoutSt) || _format.default.isXRDLayout(layoutSt) || _format.default.is31PLayout(layoutSt) || _format.default.is15NLayout(layoutSt) || _format.default.is29SiLayout(layoutSt) || _format.default.isCyclicVoltaLayout(layoutSt) || _format.default.isCDSLayout(layoutSt) || _format.default.isSECLayout(layoutSt) || _format.default.isGCLayout(layoutSt);
+const hideCmdAnaViewer = () => false;
+const btnCmdAddPeak = layoutSt => _format.default.isMsLayout(layoutSt);
+const btnCmdRmPeak = layoutSt => _format.default.isMsLayout(layoutSt);
+const btnCmdSetRef = layoutSt => !_format.default.isNmrLayout(layoutSt); // eslint-disable-line
+
+const btnCmdIntg = layoutSt => !(_format.default.isNmrLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt)); // eslint-disable-line
+
+const btnCmdMpy = layoutSt => !_format.default.isNmrLayout(layoutSt);
+const btnCmdMpyPeak = (layoutSt, mpySt, curveIdx = 0) => {
+ const {
+ multiplicities
+ } = mpySt;
+ let smExtextVal = false;
+ if (multiplicities) {
+ const selectedMultiplicity = multiplicities[curveIdx];
+ if (selectedMultiplicity) {
+ const {
+ smExtext
+ } = selectedMultiplicity;
+ smExtextVal = smExtext;
+ }
+ }
+ return btnCmdMpy(layoutSt) || !smExtextVal;
+};
+const hideCmdThres = layoutSt => _format.default.isMsLayout(layoutSt);
+const btnCmdThres = thresVal => !thresVal;
+
+// const hidePanelPeak = layoutSt => Format.isMsLayout(layoutSt);
+const hidePanelPeak = layoutSt => !_format.default.isSECLayout(layoutSt); // eslint-disable-line
+
+const hidePanelMpy = layoutSt => !_format.default.isNmrLayout(layoutSt);
+const hidePanelCompare = layoutSt => !(_format.default.isIrLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt) || _format.default.isXRDLayout(layoutSt)); // eslint-disable-line
+
+const hideSolvent = layoutSt => !_format.default.isNmrLayout(layoutSt);
+const showTwoThreshold = layoutSt => _format.default.isCyclicVoltaLayout(layoutSt);
+const hidePanelCyclicVolta = layoutSt => !_format.default.isCyclicVoltaLayout(layoutSt);
+const Config = {
+ btnCmdAnaViewer,
+ hideCmdAnaViewer,
+ btnCmdAddPeak,
+ btnCmdRmPeak,
+ btnCmdSetRef,
+ btnCmdIntg,
+ btnCmdMpy,
+ btnCmdMpyPeak,
+ hideCmdThres,
+ btnCmdThres,
+ hidePanelPeak,
+ hidePanelMpy,
+ hidePanelCompare,
+ hideSolvent,
+ showTwoThreshold,
+ hidePanelCyclicVolta
+};
+var _default = exports.default = Config;
\ No newline at end of file
diff --git a/dist/helpers/chem.js b/dist/helpers/chem.js
new file mode 100644
index 00000000..65dd81ef
--- /dev/null
+++ b/dist/helpers/chem.js
@@ -0,0 +1,935 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.convertTopic = exports.Topic2Seed = exports.ToThresEndPts = exports.ToShiftPeaks = exports.ToFrequency = exports.GetCyclicVoltaShiftOffset = exports.GetCyclicVoltaRatio = exports.GetCyclicVoltaPreviousShift = exports.GetCyclicVoltaPeakSeparate = exports.GetComparisons = exports.Feature2Peak = exports.Feature2MaxMinPeak = exports.ExtractJcamp = exports.Convert2Thres = exports.Convert2Scan = exports.Convert2Peak = exports.Convert2MaxMinPeak = exports.Convert2DValue = void 0;
+var _jcampconverter = _interopRequireDefault(require("jcampconverter"));
+var _reselect = require("reselect");
+var _shift = require("./shift");
+var _cfg = _interopRequireDefault(require("./cfg"));
+var _format = _interopRequireDefault(require("./format"));
+var _list_layout = require("../constants/list_layout");
+var _integration = require("./integration");
+/* eslint-disable
+no-mixed-operators, react/function-component-definition,
+prefer-object-spread, camelcase, no-plusplus, prefer-destructuring,
+max-len */
+
+const getTopic = (_, props) => props.topic;
+const getFeature = (_, props) => props.feature;
+const getLayout = (state, _) => state.layout; // eslint-disable-line
+
+const GetCyclicVoltaShiftOffset = (volammetryData = null, curveIdx = 0) => {
+ if (!volammetryData) return 0.0;
+ const {
+ spectraList
+ } = volammetryData;
+ const spectra = spectraList[curveIdx];
+ if (!spectra) return 0.0;
+ const {
+ shift
+ } = spectra;
+ const {
+ ref,
+ val
+ } = shift;
+ if (!ref) return 0.0;
+ const {
+ e12
+ } = ref;
+ return e12 - val;
+};
+exports.GetCyclicVoltaShiftOffset = GetCyclicVoltaShiftOffset;
+const getShiftOffset = (state, _) => {
+ // eslint-disable-line
+ const {
+ curve,
+ layout,
+ cyclicvolta
+ } = state;
+ const {
+ curveIdx
+ } = curve;
+ if (layout === _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY && cyclicvolta) {
+ return GetCyclicVoltaShiftOffset(cyclicvolta, curveIdx);
+ }
+ const {
+ shift
+ } = state;
+ const {
+ shifts
+ } = shift;
+ const selectedShift = shifts[curveIdx];
+ if (!selectedShift) {
+ return 0.0;
+ }
+ const {
+ ref,
+ peak
+ } = selectedShift;
+ return (0, _shift.FromManualToOffset)(ref, peak);
+};
+const calcXYK = (xs, ys, maxY, offset) => {
+ const sp = [];
+ let k = 0;
+ for (let i = 0; i < ys.length; i += 1) {
+ // no-downsample
+ const x = xs[i] - offset;
+ const y = ys[i];
+ const cy = y / maxY;
+ if (cy > 0.0) {
+ k += cy;
+ }
+ sp.push({
+ x,
+ y,
+ k
+ });
+ }
+ return sp;
+};
+const calcXY = (xs, ys, maxY, offset) => {
+ const sp = [];
+ for (let i = 0; i < ys.length; i += 1) {
+ // no-downsample
+ const x = xs[i] - offset;
+ const y = ys[i];
+ sp.push({
+ x,
+ y
+ });
+ }
+ return sp;
+};
+const convertTopic = (topic, layout, feature, offset) => {
+ const {
+ maxY
+ } = feature;
+ const xs = topic.x;
+ const ys = topic.y;
+ const isItgDisable = _cfg.default.btnCmdIntg(layout);
+ if (!isItgDisable) return calcXYK(xs, ys, maxY, offset);
+ return calcXY(xs, ys, maxY, offset);
+};
+exports.convertTopic = convertTopic;
+const Topic2Seed = exports.Topic2Seed = (0, _reselect.createSelector)(getTopic, getLayout, getFeature, getShiftOffset, convertTopic);
+const getOthers = (_, props) => props.comparisons;
+const calcRescaleXY = (xs, ys, minY, maxY, show) => {
+ const sp = [];
+ if (xs.length < 1) return sp;
+ const [lowerY, upperY] = [Math.min(...ys), Math.max(...ys)];
+ const faktor = (maxY - minY) / (upperY - lowerY);
+ for (let i = 0; i < ys.length; i += 2) {
+ // downsample
+ const x = xs[i];
+ const y = (ys[i] - lowerY) * faktor + minY;
+ sp.push({
+ x,
+ y
+ });
+ }
+ return {
+ data: sp,
+ show
+ };
+};
+const convertComparisons = (layout, comparisons, feature) => {
+ const {
+ minY,
+ maxY
+ } = feature;
+ if (!comparisons || !(_format.default.isIrLayout(layout) || _format.default.isHplcUvVisLayout(layout) || _format.default.isXRDLayout(layout))) return [];
+ return comparisons.map(c => {
+ const {
+ spectra,
+ show
+ } = c;
+ const topic = spectra[0].data[0];
+ const xs = topic.x;
+ const ys = topic.y;
+ return calcRescaleXY(xs, ys, minY, maxY, show);
+ });
+};
+const GetComparisons = exports.GetComparisons = (0, _reselect.createSelector)(getLayout, getOthers, getFeature, convertComparisons);
+const convertFrequency = (layout, feature) => {
+ if (['1H', '13C', '19F', '31P', '15N', '29Si'].indexOf(layout) < 0) return false;
+ const {
+ observeFrequency
+ } = feature;
+ const freq = Array.isArray(observeFrequency) ? observeFrequency[0] : observeFrequency;
+ return parseFloat(freq) || false;
+};
+const ToFrequency = exports.ToFrequency = (0, _reselect.createSelector)(getLayout, getFeature, convertFrequency);
+const getThreshold = state => state.threshold ? state.threshold.list[state.curve.curveIdx].value * 1.0 : false;
+const Convert2Peak = (feature, threshold, offset, upThreshold = false, lowThreshold = false) => {
+ const peak = [];
+ if (!feature || !feature.data) return peak;
+ const data = feature.data[0];
+ const {
+ maxY,
+ peakUp,
+ thresRef,
+ minY,
+ upperThres,
+ lowerThres,
+ operation
+ } = feature;
+ const {
+ layout
+ } = operation;
+
+ // if (!Format.isSECLayout(layout) && (upperThres || lowerThres)) {
+ if ((_format.default.isCyclicVoltaLayout(layout) || _format.default.isCDSLayout(layout)) && (upperThres || lowerThres)) {
+ let upperThresVal = upThreshold || upperThres;
+ if (!upperThresVal) {
+ upperThresVal = 1.0;
+ }
+ let lowerThresVal = lowThreshold || lowerThres;
+ if (!lowerThresVal) {
+ lowerThresVal = 1.0;
+ }
+ const yUpperThres = parseFloat(upperThresVal) / 100.0 * maxY;
+ const yLowerThres = parseFloat(lowerThresVal) / 100.0 * minY;
+ const corrOffset = offset || 0.0;
+ for (let i = 0; i < data.y.length; i += 1) {
+ const y = data.y[i];
+ const overUpperThres = y >= yUpperThres;
+ const belowThres = y <= yLowerThres;
+ if (overUpperThres || belowThres) {
+ const x = data.x[i] - corrOffset;
+ peak.push({
+ x,
+ y
+ });
+ }
+ }
+ return peak;
+ }
+ const thresVal = threshold || thresRef;
+ const yThres = Number.parseFloat((thresVal * maxY / 100.0).toFixed(10));
+ const corrOffset = offset || 0.0;
+ for (let i = 0; i < data.y.length; i += 1) {
+ const y = data.y[i];
+ const overThres = peakUp && Math.abs(y) >= yThres || !peakUp && Math.abs(y) <= yThres;
+ if (overThres) {
+ const x = data.x[i] - corrOffset;
+ peak.push({
+ x,
+ y
+ });
+ }
+ }
+ return peak;
+};
+exports.Convert2Peak = Convert2Peak;
+const Feature2Peak = exports.Feature2Peak = (0, _reselect.createSelector)(getFeature, getThreshold, getShiftOffset, Convert2Peak);
+const Convert2MaxMinPeak = (layout, feature, offset) => {
+ // eslint-disable-line
+ const peaks = {
+ max: [],
+ min: [],
+ pecker: [],
+ refIndex: -1
+ };
+ if (!_format.default.isCyclicVoltaLayout(layout) || !feature || !feature.data) return null; // eslint-disable-line
+ // const data = feature.data[0]; // eslint-disable-line
+ const {
+ volammetryData
+ } = feature;
+ if (volammetryData && volammetryData.length > 0) {
+ const maxArr = volammetryData.map(peakData => {
+ // peaks.refIndex = peakData.isRef === true ? idx : -1;
+ if (peakData.max.x === '') return null;
+ return {
+ x: Number(peakData.max.x),
+ y: Number(peakData.max.y)
+ };
+ });
+ const minArr = volammetryData.map(peakData => {
+ if (peakData.min.x === '') return null;
+ return {
+ x: Number(peakData.min.x),
+ y: Number(peakData.min.y)
+ };
+ });
+ const peckerArr = volammetryData.map(peakData => {
+ if (peakData.pecker.x === '') return null;
+ return {
+ x: Number(peakData.pecker.x),
+ y: Number(peakData.pecker.y)
+ };
+ });
+ const refIndex = volammetryData.findIndex(peakData => peakData.isRef === true);
+ peaks.max = maxArr;
+ peaks.min = minArr;
+ peaks.pecker = peckerArr;
+ peaks.refIndex = refIndex;
+ return peaks;
+ }
+ return peaks;
+};
+exports.Convert2MaxMinPeak = Convert2MaxMinPeak;
+const Feature2MaxMinPeak = exports.Feature2MaxMinPeak = (0, _reselect.createSelector)(getLayout, getFeature, getShiftOffset, Convert2MaxMinPeak);
+const convertThresEndPts = (feature, threshold) => {
+ const {
+ maxY,
+ maxX,
+ minX,
+ thresRef
+ } = feature;
+ const thresVal = threshold || thresRef || 0;
+ if (!thresVal || !feature.data) return [];
+ const yThres = thresVal * maxY / 100.0;
+ const endPts = [{
+ x: minX - 200,
+ y: yThres
+ }, {
+ x: maxX + 200,
+ y: yThres
+ }];
+ return endPts;
+};
+const ToThresEndPts = exports.ToThresEndPts = (0, _reselect.createSelector)(getFeature, getThreshold, convertThresEndPts);
+const getShiftPeak = state => {
+ const {
+ curve,
+ shift
+ } = state;
+ const {
+ curveIdx
+ } = curve;
+ const {
+ shifts
+ } = shift;
+ const selectedShift = shifts[curveIdx];
+ if (!selectedShift) {
+ return false;
+ }
+ return selectedShift.peak;
+};
+const convertSfPeaks = (peak, offset) => {
+ if (!peak || !peak.x) return [];
+ return [{
+ x: peak.x - offset,
+ y: peak.y
+ }];
+};
+const ToShiftPeaks = exports.ToShiftPeaks = (0, _reselect.createSelector)(getShiftPeak, getShiftOffset, convertSfPeaks);
+
+// - - - - - - - - - - - - - - - - - - - - - -
+// ExtractJcamp
+// - - - - - - - - - - - - - - - - - - - - - -
+const readLayout = jcamp => {
+ const {
+ xType,
+ spectra
+ } = jcamp;
+ if (xType && _format.default.isNmrLayout(xType)) return xType;
+ const {
+ dataType
+ } = spectra[0];
+ if (dataType) {
+ if (dataType.includes('INFRARED SPECTRUM')) {
+ return _list_layout.LIST_LAYOUT.IR;
+ }
+ if (dataType.includes('RAMAN SPECTRUM')) {
+ return _list_layout.LIST_LAYOUT.RAMAN;
+ }
+ if (dataType.includes('UV/VIS SPECTRUM')) {
+ if (dataType.includes('HPLC')) {
+ return _list_layout.LIST_LAYOUT.HPLC_UVVIS;
+ }
+ return _list_layout.LIST_LAYOUT.UVVIS;
+ }
+ if (dataType.includes('THERMOGRAVIMETRIC ANALYSIS')) {
+ return _list_layout.LIST_LAYOUT.TGA;
+ }
+ if (dataType.includes('DIFFERENTIAL SCANNING CALORIMETRY')) {
+ return _list_layout.LIST_LAYOUT.DSC;
+ }
+ if (dataType.includes('X-RAY DIFFRACTION')) {
+ return _list_layout.LIST_LAYOUT.XRD;
+ }
+ if (dataType.includes('MASS SPECTRUM')) {
+ return _list_layout.LIST_LAYOUT.MS;
+ }
+ if (dataType.includes('CYCLIC VOLTAMMETRY')) {
+ return _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY;
+ }
+ if (dataType.includes('CIRCULAR DICHROISM SPECTROSCOPY')) {
+ return _list_layout.LIST_LAYOUT.CDS;
+ }
+ if (dataType.includes('SIZE EXCLUSION CHROMATOGRAPHY')) {
+ return _list_layout.LIST_LAYOUT.SEC;
+ }
+ if (dataType.includes('GAS CHROMATOGRAPHY')) {
+ return _list_layout.LIST_LAYOUT.GC;
+ }
+ if (dataType.includes('SORPTION-DESORPTION MEASUREMENT')) {
+ return _list_layout.LIST_LAYOUT.AIF;
+ }
+ if (dataType.includes('Emissions')) {
+ return _list_layout.LIST_LAYOUT.EMISSIONS;
+ }
+ if (dataType.includes('DLS ACF')) {
+ return _list_layout.LIST_LAYOUT.DLS_ACF;
+ }
+ if (dataType.includes('DLS intensity')) {
+ return _list_layout.LIST_LAYOUT.DLS_INTENSITY;
+ }
+ }
+ return false;
+};
+const extrSpectraShare = (spectra, layout) => spectra.map(s => Object.assign({
+ layout
+}, s)).filter(r => r != null);
+const extrSpectraMs = (jcamp, layout) => {
+ const scanCount = jcamp.info.$CSSCANCOUNT || 1;
+ const spc = extrSpectraShare(jcamp.spectra.slice(0, scanCount), layout);
+ let spectra = spc || [];
+ if (jcamp.info.UNITS && jcamp.info.SYMBOL) {
+ const units = jcamp.info.UNITS.split(',');
+ const symbol = jcamp.info.SYMBOL.split(',');
+ let xUnit = null;
+ let yUnit = null;
+ symbol.forEach((sym, idx) => {
+ const currSymbol = sym.replace(' ', '').toLowerCase();
+ if (currSymbol === 'x') {
+ xUnit = units[idx].trim();
+ } else if (currSymbol === 'y') {
+ yUnit = units[idx].trim();
+ }
+ });
+ spectra = spectra.map(sp => {
+ const spectrum = sp;
+ if (xUnit) {
+ spectrum.xUnit = xUnit;
+ }
+ if (yUnit) {
+ spectrum.yUnit = yUnit;
+ }
+ return spectrum;
+ });
+ }
+ return spectra;
+};
+const extrSpectraNi = (jcamp, layout) => {
+ const categorys = jcamp.info.$CSCATEGORY || ['SPECTRUM'];
+ const targetIdx = categorys.indexOf('SPECTRUM');
+ const spectrum = extrSpectraShare(jcamp.spectra, layout)[targetIdx];
+ return [spectrum] || [jcamp.spectra[0]];
+};
+const calcThresRef = (s, peakUp) => {
+ const ys = s && s.data[0].y;
+ if (!ys) return null;
+ const ref = peakUp ? Math.min(...ys.map(a => Math.abs(a))) : Math.max(...ys);
+ return peakUp ? Math.floor(ref * 100 * 100 / s.maxY) / 100 : Math.ceil(ref * 100 * 100 / s.maxY) / 100;
+};
+const calcUpperThres = s => {
+ const ys = s && s.data[0].y;
+ if (!ys) return null;
+ const ref = Math.max(...ys);
+ return Math.floor(ref * 100 * 100 / s.maxY) / 100;
+};
+const calcLowerThres = s => {
+ const ys = s && s.data[0].y;
+ if (!ys) return null;
+ const ref = Math.min(...ys);
+ return Math.ceil(ref * 100 * 100 / s.minY) / 100;
+};
+const extractShift = (s, jcamp) => {
+ const shift = {
+ selectX: false,
+ solventName: false,
+ solventValue: false
+ };
+ if (!s) return shift;
+ if (s && s.sampleDescription) {
+ const desc = s.sampleDescription;
+ const info = desc.split(/;|=/);
+ return {
+ selectX: parseFloat(info[1]),
+ solventName: info[3],
+ solventValue: parseFloat(info[5])
+ };
+ }
+ return {
+ selectX: parseFloat(jcamp.info.$CSSOLVENTX) || false,
+ solventName: jcamp.info.$CSSOLVENTNAME || false,
+ solventValue: parseFloat(jcamp.info.$CSSOLVENTVALUE) || false
+ };
+};
+const extractVoltammetryData = jcamp => {
+ const {
+ info
+ } = jcamp;
+ if (!info.$CSCYCLICVOLTAMMETRYDATA) return null;
+ const regx = /[^0-9.,E,e,-]/g;
+ const rawData = info.$CSCYCLICVOLTAMMETRYDATA.split('\n');
+ const peakStack = rawData.map(line => {
+ const splittedLine = line.replace(regx, '').split(',');
+ const isRef = splittedLine.length > 8 && splittedLine[8] === '1';
+ return {
+ max: {
+ x: splittedLine[0],
+ y: splittedLine[1]
+ },
+ min: {
+ x: splittedLine[2],
+ y: splittedLine[3]
+ },
+ ratio: splittedLine[4],
+ delta: splittedLine[5],
+ pecker: {
+ x: splittedLine[6],
+ y: splittedLine[7]
+ },
+ isRef
+ };
+ });
+ return peakStack;
+};
+const buildPeakFeature = (jcamp, layout, peakUp, s, thresRef, upperThres = false, lowerThres = false) => {
+ // eslint-disable-line
+ const {
+ xType,
+ info
+ } = jcamp;
+ const subTyp = xType ? ` - ${xType}` : '';
+ return Object.assign({
+ typ: s.dataType + subTyp,
+ peakUp,
+ thresRef,
+ scanCount: +info.$CSSCANCOUNT,
+ scanAutoTarget: +info.$CSSCANAUTOTARGET,
+ scanEditTarget: +info.$CSSCANEDITTARGET,
+ shift: extractShift(s, jcamp),
+ operation: {
+ layout,
+ nucleus: xType || ''
+ },
+ observeFrequency: info['.OBSERVEFREQUENCY'],
+ solventName: info['.SOLVENTNAME'],
+ upperThres,
+ lowerThres,
+ volammetryData: extractVoltammetryData(jcamp),
+ scanRate: +info.$CSSCANRATE || 0.1,
+ weAreaValue: info.$CSWEAREAVALUE || '',
+ weAreaUnit: info.$CSWEAREAUNIT || '',
+ currentMode: info.$CSCURRENTMODE || ''
+ }, s);
+};
+const maxArray = arr => {
+ let len = arr.length;
+ let max = -Infinity;
+ while (len--) {
+ max = arr[len] > max ? arr[len] : max;
+ }
+ return max;
+};
+const calcIntgRefArea = (spectra, stack) => {
+ if (stack.length === 0) return 1;
+ const data = spectra[0].data[0];
+ const xs = data.x;
+ const ys = data.y;
+ const maxY = maxArray(ys);
+ const xyk = calcXYK(xs, ys, maxY, 0);
+ const {
+ xL,
+ xU,
+ area
+ } = stack[0];
+ const rawArea = (0, _integration.getArea)(xL, xU, xyk);
+ const raw2realRatio = rawArea / area;
+ return {
+ raw2realRatio
+ };
+};
+const buildIntegFeature = (jcamp, spectra) => {
+ const {
+ $OBSERVEDINTEGRALS,
+ $OBSERVEDMULTIPLETS
+ } = jcamp.info;
+ const regx = /[^0-9.,-]/g;
+ let stack = [];
+ if ($OBSERVEDINTEGRALS) {
+ const its = $OBSERVEDINTEGRALS.split('\n').slice(1);
+ const itStack = its.map(t => {
+ const ts = t.replace(regx, '').split(',');
+ return {
+ xL: parseFloat(ts[0]),
+ xU: parseFloat(ts[1]),
+ area: parseFloat(ts[2]),
+ absoluteArea: parseFloat(ts[3])
+ };
+ });
+ stack = [...stack, ...itStack];
+ }
+ if ($OBSERVEDMULTIPLETS) {
+ const mps = $OBSERVEDMULTIPLETS.split('\n');
+ const mpStack = mps.map(m => {
+ const ms = m.replace(regx, '').split(',');
+ return {
+ xL: parseFloat(ms[1]),
+ xU: parseFloat(ms[2]),
+ area: parseFloat(ms[4])
+ };
+ });
+ stack = [...stack, ...mpStack];
+ }
+ const {
+ raw2realRatio
+ } = calcIntgRefArea(spectra, stack);
+ const mStack = stack.map(st => Object.assign({}, st, {
+ area: st.area * raw2realRatio
+ }));
+ return {
+ refArea: raw2realRatio,
+ refFactor: 1,
+ shift: 0,
+ stack: mStack,
+ originStack: stack
+ };
+};
+
+/*
+const range = (head, tail, length) => {
+ const actTail = tail || length - 1;
+ return (
+ Array(actTail - head + 1).fill().map((_, idx) => head + idx)
+ );
+};
+*/
+
+const buildSimFeature = jcamp => {
+ const {
+ $CSSIMULATIONPEAKS
+ } = jcamp.info;
+ let nmrSimPeaks = $CSSIMULATIONPEAKS ? $CSSIMULATIONPEAKS.split('\n') : [];
+ nmrSimPeaks = nmrSimPeaks.map(x => parseFloat(x).toFixed(2));
+ return {
+ nmrSimPeaks
+ };
+};
+const buildMpyFeature = jcamp => {
+ const {
+ $OBSERVEDMULTIPLETS,
+ $OBSERVEDMULTIPLETSPEAKS
+ } = jcamp.info;
+ const regx = /[^A-Za-z0-9.,-]/g;
+ const regxNum = /[^0-9.]/g;
+ let stack = [];
+ if (!$OBSERVEDMULTIPLETSPEAKS) return {
+ stack: []
+ };
+ const allPeaks = $OBSERVEDMULTIPLETSPEAKS.split('\n').map(p => p.replace(regx, '').split(','));
+ if ($OBSERVEDMULTIPLETS) {
+ const mp = $OBSERVEDMULTIPLETS.split('\n');
+ const mpStack = mp.map(m => {
+ const ms = m.replace(regx, '').split(',');
+ const idx = ms[0];
+ let ys = [];
+ const peaks = allPeaks.map(p => {
+ if (p[0] === idx) {
+ ys = [...ys, parseFloat(p[2])];
+ return {
+ x: parseFloat(p[1]),
+ y: parseFloat(p[2])
+ };
+ }
+ return null;
+ }).filter(r => r != null);
+ let js = m.split(',');
+ js = js[js.length - 1].split(' ').map(j => parseFloat(j.replace(regxNum, ''))).filter(Boolean);
+ return {
+ js,
+ mpyType: ms[6],
+ xExtent: {
+ xL: parseFloat(ms[1]),
+ xU: parseFloat(ms[2])
+ },
+ yExtent: {
+ yL: Math.min(...ys),
+ yU: Math.max(...ys)
+ },
+ peaks
+ };
+ });
+ stack = [...stack, ...mpStack];
+ }
+ return {
+ stack,
+ shift: 0,
+ smExtext: false
+ };
+};
+const isPeakTable = s => s.dataType && (s.dataType.includes('PEAKTABLE') || s.dataType.includes('PEAK ASSIGNMENTS'));
+const extrFeaturesNi = (jcamp, layout, peakUp, spectra) => {
+ const nfs = {};
+ const category = jcamp.info.$CSCATEGORY;
+ if (category) {
+ const idxEditPeak = category.indexOf('EDIT_PEAK');
+ if (idxEditPeak >= 0) {
+ const sEP = jcamp.spectra[idxEditPeak];
+ const thresRef = calcThresRef(sEP, peakUp);
+ nfs.editPeak = buildPeakFeature(jcamp, layout, peakUp, sEP, thresRef);
+ }
+ const idxAutoPeak = category.indexOf('AUTO_PEAK');
+ if (idxAutoPeak >= 0) {
+ const sAP = jcamp.spectra[idxAutoPeak];
+ const thresRef = calcThresRef(sAP, peakUp);
+ nfs.autoPeak = buildPeakFeature(jcamp, layout, peakUp, sAP, thresRef);
+ }
+ nfs.integration = buildIntegFeature(jcamp, spectra);
+ nfs.multiplicity = buildMpyFeature(jcamp);
+ nfs.simulation = buildSimFeature(jcamp);
+ return nfs;
+ }
+
+ // workaround for legacy design
+ const features = jcamp.spectra.map(s => {
+ const thresRef = calcThresRef(s, peakUp);
+ return isPeakTable(s) ? buildPeakFeature(jcamp, layout, peakUp, s, thresRef) : null;
+ }).filter(r => r != null);
+ const integration = buildIntegFeature(jcamp, spectra);
+ const multiplicity = buildMpyFeature(jcamp);
+ const simulation = buildSimFeature(jcamp);
+ return {
+ editPeak: features[0],
+ autoPeak: features[1],
+ integration,
+ multiplicity,
+ simulation
+ };
+};
+const getBoundary = s => {
+ const {
+ x,
+ y
+ } = s.data[0];
+ const maxX = Math.max(...x);
+ const minX = Math.min(...x);
+ const maxY = Math.max(...y);
+ const minY = Math.min(...y);
+ return {
+ maxX,
+ minX,
+ maxY,
+ minY
+ };
+};
+const extrFeaturesXrd = (jcamp, layout, peakUp) => {
+ const base = jcamp.spectra[0];
+ const features = jcamp.spectra.map(s => {
+ const upperThres = _format.default.isXRDLayout(layout) ? 100 : calcUpperThres(s);
+ const lowerThres = _format.default.isXRDLayout(layout) ? 100 : calcLowerThres(s);
+ const cpo = buildPeakFeature(jcamp, layout, peakUp, s, 100, upperThres, lowerThres);
+ const bnd = getBoundary(s);
+ return Object.assign({}, base, cpo, bnd);
+ }).filter(r => r != null);
+ const category = jcamp.info.$CSCATEGORY;
+ if (category) {
+ const idxEditPeak = category.indexOf('EDIT_PEAK');
+ if (idxEditPeak >= 0) {
+ const sEP = jcamp.spectra[idxEditPeak];
+ const thresRef = calcThresRef(sEP, peakUp);
+ features.editPeak = buildPeakFeature(jcamp, layout, peakUp, sEP, thresRef);
+ }
+ const idxAutoPeak = category.indexOf('AUTO_PEAK');
+ if (idxAutoPeak >= 0) {
+ const sAP = jcamp.spectra[idxAutoPeak];
+ const thresRef = calcThresRef(sAP, peakUp);
+ features.autoPeak = buildPeakFeature(jcamp, layout, peakUp, sAP, thresRef);
+ }
+ }
+ return features;
+};
+const extrFeaturesCylicVolta = (jcamp, layout, peakUp) => {
+ const base = jcamp.spectra[0];
+ const features = jcamp.spectra.map(s => {
+ const upperThres = _format.default.isXRDLayout(layout) ? 100 : calcUpperThres(s);
+ const lowerThres = _format.default.isXRDLayout(layout) ? 100 : calcLowerThres(s);
+ const cpo = buildPeakFeature(jcamp, layout, peakUp, s, 100, upperThres, lowerThres);
+ const bnd = getBoundary(s);
+ let detector = '';
+ let secData = null;
+ if (_format.default.isSECLayout(layout)) {
+ const {
+ info
+ } = jcamp;
+ detector = info.$DETECTOR ? info.$DETECTOR : '';
+ const {
+ D,
+ MN,
+ MP,
+ MW
+ } = info;
+ secData = {
+ d: D,
+ mn: MN,
+ mp: MP,
+ mw: MW
+ };
+ }
+ return Object.assign({}, base, cpo, bnd, {
+ detector,
+ secData
+ });
+ }).filter(r => r != null);
+ return features;
+};
+const extrFeaturesMs = (jcamp, layout, peakUp) => {
+ // const nfs = {};
+ // const category = jcamp.info.$CSCATEGORY;
+ // const scanCount = parseInt(jcamp.info.$CSSCANCOUNT, 10) - 1;
+ // if (category) {
+ // const idxEditPeak = category.indexOf('EDIT_PEAK');
+ // if (idxEditPeak >= 0) {
+ // const sEP = jcamp.spectra[idxEditPeak + scanCount];
+ // const thresRef = calcThresRef(sEP, peakUp);
+ // nfs.editPeak = buildPeakFeature(jcamp, layout, peakUp, sEP, thresRef);
+ // }
+ // const idxAutoPeak = category.indexOf('AUTO_PEAK');
+ // if (idxAutoPeak >= 0) {
+ // const sAP = jcamp.spectra[idxAutoPeak + scanCount];
+ // const thresRef = calcThresRef(sAP, peakUp);
+ // nfs.autoPeak = buildPeakFeature(jcamp, layout, peakUp, sAP, thresRef);
+ // }
+ // return nfs;
+ // }
+ // // workaround for legacy design
+ const thresRef = jcamp.info && jcamp.info.$CSTHRESHOLD * 100 || 5;
+ const base = jcamp.spectra[0];
+ const features = jcamp.spectra.map(s => {
+ const cpo = buildPeakFeature(jcamp, layout, peakUp, s, +thresRef.toFixed(4));
+ const bnd = getBoundary(s);
+ return Object.assign({}, base, cpo, bnd);
+ }).filter(r => r != null);
+ return features;
+};
+const extractTemperature = jcamp => {
+ if ('$CSAUTOMETADATA' in jcamp.info) {
+ const match = jcamp.info.$CSAUTOMETADATA.match(/TEMPERATURE=([\d.]+)/);
+ if (match !== null) {
+ const temperature = match[1];
+ return temperature;
+ }
+ }
+ return 'xxx';
+};
+const ExtractJcamp = source => {
+ const jcamp = _jcampconverter.default.convert(source, {
+ xy: true,
+ keepRecordsRegExp: /(\$CSTHRESHOLD|\$CSSCANAUTOTARGET|\$CSSCANEDITTARGET|\$CSSCANCOUNT|\$CSSOLVENTNAME|\$CSSOLVENTVALUE|\$CSSOLVENTX|\$CSCATEGORY|\$CSITAREA|\$CSITFACTOR|\$OBSERVEDINTEGRALS|\$OBSERVEDMULTIPLETS|\$OBSERVEDMULTIPLETSPEAKS|\.SOLVENTNAME|\.OBSERVEFREQUENCY|\$CSSIMULATIONPEAKS|\$CSUPPERTHRESHOLD|\$CSLOWERTHRESHOLD|\$CSCYCLICVOLTAMMETRYDATA|UNITS|SYMBOL|\$CSAUTOMETADATA|\$DETECTOR|MN|MW|D|MP|MELTINGPOINT|TG|\$CSSCANRATE|\$CSSPECTRUMDIRECTION|\$CSWEAREAVALUE|\$CSWEAREAUNIT|\$CSCURRENTMODE)/ // eslint-disable-line
+ });
+ const layout = readLayout(jcamp);
+ const peakUp = !_format.default.isIrLayout(layout);
+ const spectra = _format.default.isMsLayout(layout) ? extrSpectraMs(jcamp, layout) : extrSpectraNi(jcamp, layout);
+ let features = {};
+ if (_format.default.isMsLayout(layout)) {
+ features = extrFeaturesMs(jcamp, layout, peakUp);
+ } else if (_format.default.isXRDLayout(layout)) {
+ features = extrFeaturesXrd(jcamp, layout, peakUp);
+ const temperature = extractTemperature(jcamp);
+ return {
+ spectra,
+ features,
+ layout,
+ temperature
+ };
+ } else if (_format.default.isCyclicVoltaLayout(layout) || _format.default.isSECLayout(layout) || _format.default.isAIFLayout(layout) || _format.default.isCDSLayout(layout) || _format.default.isGCLayout(layout)) {
+ features = extrFeaturesCylicVolta(jcamp, layout, peakUp);
+ } else {
+ features = extrFeaturesNi(jcamp, layout, peakUp, spectra);
+ if (_format.default.isDSCLayout(layout)) {
+ const {
+ info
+ } = jcamp;
+ const {
+ MELTINGPOINT,
+ TG
+ } = info;
+ const dscMetaData = {
+ meltingPoint: MELTINGPOINT,
+ tg: TG
+ };
+ features = Object.assign({}, features, {
+ dscMetaData
+ });
+ }
+ }
+ // const features = Format.isMsLayout(layout)
+ // ? extrFeaturesMs(jcamp, layout, peakUp)
+ // : ((Format.isXRDLayout(layout) || Format.isCyclicVoltaLayout(layout))
+ // ? extrFeaturesXrd(jcamp, layout, peakUp) : extrFeaturesNi(jcamp, layout, peakUp, spectra));
+
+ return {
+ spectra,
+ features,
+ layout
+ };
+};
+exports.ExtractJcamp = ExtractJcamp;
+const Convert2Scan = (feature, scanSt) => {
+ const {
+ scanAutoTarget,
+ scanEditTarget
+ } = feature;
+ const {
+ target,
+ isAuto
+ } = scanSt;
+ const hasEdit = !!scanEditTarget;
+ const defaultIdx = isAuto || !hasEdit ? scanAutoTarget : scanEditTarget;
+ return target || defaultIdx;
+};
+exports.Convert2Scan = Convert2Scan;
+const Convert2Thres = (feature, thresSt) => {
+ const value = thresSt.value || feature.thresRef;
+ return value;
+};
+exports.Convert2Thres = Convert2Thres;
+const Convert2DValue = (doubleTheta, lambda = 0.15406, isRadian = true) => {
+ let theta = doubleTheta / 2;
+ if (isRadian) {
+ theta = theta / 180 * Math.PI;
+ }
+ const sinTheta = Math.sin(theta);
+ const dValue = lambda / (2 * sinTheta);
+ return dValue;
+};
+exports.Convert2DValue = Convert2DValue;
+const GetCyclicVoltaRatio = (y_max_peak, y_min_peak, y_pecker) => {
+ const firstExpr = Math.abs(y_min_peak) / Math.abs(y_max_peak);
+ const secondExpr = 0.485 * Math.abs(y_pecker) / Math.abs(y_max_peak);
+ const ratio = firstExpr + secondExpr + 0.086;
+ return ratio;
+};
+exports.GetCyclicVoltaRatio = GetCyclicVoltaRatio;
+const GetCyclicVoltaPeakSeparate = (x_max_peak, x_min_peak) => {
+ const delta = Math.abs(x_max_peak - x_min_peak);
+ return delta;
+};
+exports.GetCyclicVoltaPeakSeparate = GetCyclicVoltaPeakSeparate;
+const GetCyclicVoltaPreviousShift = (cyclicVolta, curveIdx) => {
+ if (!cyclicVolta) {
+ return 0.0;
+ }
+ const {
+ spectraList
+ } = cyclicVolta;
+ if (spectraList.length <= curveIdx) {
+ return 0.0;
+ }
+ const {
+ shift,
+ hasRefPeak
+ } = spectraList[curveIdx];
+ const {
+ prevValue
+ } = shift;
+ return hasRefPeak ? prevValue : -prevValue;
+};
+exports.GetCyclicVoltaPreviousShift = GetCyclicVoltaPreviousShift;
\ No newline at end of file
diff --git a/dist/helpers/compass.js b/dist/helpers/compass.js
new file mode 100644
index 00000000..502bb9b3
--- /dev/null
+++ b/dist/helpers/compass.js
@@ -0,0 +1,271 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.getCurvePointFromEvent = exports.clearIntegrationPreview = exports.TfRescale = exports.MouseMove = exports.MountCompass = exports.ClickCompass = void 0;
+var _format = _interopRequireDefault(require("./format"));
+var _chem = require("./chem");
+var _sweep = require("./sweep.js");
+var _integration_draft = require("./integration_draft.js");
+var _integration_split = require("./integration_split");
+// eslint-disable-line import/extensions
+
+// eslint-disable-line import/extensions
+
+const d3 = require('d3');
+const TfRescale = focus => {
+ const xt = focus.scales.x;
+ const yt = focus.scales.y;
+ return {
+ xt,
+ yt
+ };
+};
+exports.TfRescale = TfRescale;
+const fetchPt = (event, focus, xt) => {
+ const rawMouseX = d3.pointer(event, focus.root.node())[0];
+ const mouseX = xt.invert(rawMouseX);
+ const bisectDate = d3.bisector(d => +d.x).left;
+ const dt = focus.data;
+ const ls = dt.length;
+ const sortData = ls > 0 && dt[0].x > dt[ls - 1].x ? [...dt].reverse() : dt;
+ const idx = bisectDate(sortData, +mouseX);
+ return sortData[Math.min(idx, ls - 1)];
+};
+const fetchFreePt = (event, focus, xt, yt) => {
+ const rawMouseX = d3.pointer(event, focus.root.node())[0];
+ const rawMouseY = d3.pointer(event, focus.root.node())[1];
+ const mouseX = xt.invert(rawMouseX);
+ const mouseY = yt.invert(rawMouseY);
+ const distance2 = (x1, x2, y1, y2) => {
+ const dx = x1 - x2;
+ const dy = y1 - y2;
+ return dx * dx + dy * dy;
+ };
+ let minDistance = Number.MAX_VALUE;
+ const dt = focus.data;
+ let selectPoint = null;
+ dt.forEach(pt => {
+ const distance = distance2(pt.x, mouseX, pt.y, mouseY);
+ if (minDistance > distance) {
+ minDistance = distance;
+ selectPoint = pt;
+ }
+ });
+ return selectPoint;
+};
+const clearIntegrationPreview = focus => {
+ if (!focus || !focus.root) return;
+ focus.root.select('.integration-preview-line').remove();
+};
+exports.clearIntegrationPreview = clearIntegrationPreview;
+const drawIntegrationPreview = (focus, firstPoint, nextPoint) => {
+ if (!firstPoint || !nextPoint) return;
+ const {
+ xt,
+ yt
+ } = TfRescale(focus);
+ const preview = focus.root.select('.integration-preview');
+ const line = preview.selectAll('.integration-preview-line').data([{
+ firstPoint,
+ nextPoint
+ }]);
+ line.enter().append('line').attr('class', 'integration-preview-line').attr('stroke', 'red').attr('stroke-width', 2).attr('stroke-dasharray', '4,3').style('pointer-events', 'none').merge(line).attr('x1', d => xt(d.firstPoint.x)).attr('y1', d => yt(d.firstPoint.y)).attr('x2', d => xt(d.nextPoint.x)).attr('y2', d => yt(d.nextPoint.y));
+};
+const getCurvePointFromEvent = (event, focus) => {
+ const {
+ xt,
+ yt
+ } = TfRescale(focus);
+ if (_format.default.isCyclicVoltaLayout(focus.layout)) {
+ return fetchFreePt(event, focus, xt, yt);
+ }
+ return fetchPt(event, focus, xt);
+};
+exports.getCurvePointFromEvent = getCurvePointFromEvent;
+const cancelIntegrationDraft = focus => {
+ Object.assign(focus, {
+ firstIntegrationPoint: null
+ });
+ clearIntegrationPreview(focus);
+ (0, _integration_draft.forgetPendingIntegrationDraft)();
+};
+const updateIntegrationPreview = (event, focus) => {
+ if (!focus.isUiAddIntgSt || !focus.firstIntegrationPoint) return;
+ const pt = getCurvePointFromEvent(event, focus);
+ if (!pt) return;
+ drawIntegrationPreview(focus, focus.firstIntegrationPoint, pt);
+};
+const updateIntegrationSplitPreview = (event, focus) => {
+ if (!focus.isUiSplitIntgSt) return;
+ const {
+ splitX,
+ target
+ } = (0, _integration_split.getIntegrationSplitTargetFromEvent)(event, focus);
+ if (!target) {
+ (0, _integration_split.clearIntegrationSplitPreview)(focus);
+ return;
+ }
+ const {
+ shift = 0,
+ ignoreRef = false
+ } = focus.integrationSplitTargets || {};
+ (0, _integration_split.drawIntegrationSplitPreview)(focus, target, splitX, shift, ignoreRef);
+};
+const MouseMove = (event, focus) => {
+ const {
+ xt,
+ yt
+ } = TfRescale(focus);
+ const {
+ freq,
+ layout,
+ wavelength
+ } = focus;
+ if (_format.default.isCyclicVoltaLayout(layout)) {
+ const pt = fetchFreePt(event, focus, xt, yt);
+ if (pt) {
+ const tx = xt(pt.x);
+ const ty = yt(pt.y);
+ focus.root.select('.compass').attr('transform', `translate(${tx},${ty})`);
+ focus.root.select('.x-hover-line').attr('y1', 0 - ty).attr('y2', focus.h - ty);
+ focus.root.select('.cursor-txt').attr('transform', `translate(${tx},${10})`).text(pt.x.toFixed(3));
+ if (freq) {
+ focus.root.select('.cursor-txt-hz').attr('transform', `translate(${tx},${20})`).text(`${(pt.x * freq).toFixed(3)} Hz`);
+ } else {
+ focus.root.select('.cursor-txt-hz').text('');
+ }
+ }
+ } else {
+ const pt = fetchPt(event, focus, xt);
+ if (pt) {
+ const tx = xt(pt.x);
+ const ty = yt(pt.y);
+ focus.root.select('.compass').attr('transform', `translate(${tx},${ty})`);
+ focus.root.select('.x-hover-line').attr('y1', 0 - ty).attr('y2', focus.h - ty);
+ if (_format.default.isXRDLayout(layout)) {
+ let dValue = 0.0;
+ if (wavelength) {
+ dValue = (0, _chem.Convert2DValue)(pt.x, wavelength.value).toExponential(2);
+ } else {
+ dValue = (0, _chem.Convert2DValue)(pt.x).toExponential(2);
+ }
+ focus.root.select('.cursor-txt-hz').attr('transform', `translate(${tx},${ty - 30})`).text(`2Theta: ${pt.x.toExponential(2)}, d-value: ${dValue}`);
+ } else if (_format.default.isTGALayout(layout) || _format.default.isDSCLayout(layout)) {
+ focus.root.select('.cursor-txt').attr('transform', `translate(${tx},${10})`).text(`X: ${pt.x.toFixed(3)}, Y: ${pt.y.toFixed(3)}`);
+ } else {
+ focus.root.select('.cursor-txt').attr('transform', `translate(${tx},${10})`).text(pt.x.toFixed(3));
+ if (freq) {
+ focus.root.select('.cursor-txt-hz').attr('transform', `translate(${tx},${20})`).text(`${(pt.x * freq).toFixed(3)} Hz`);
+ } else {
+ focus.root.select('.cursor-txt-hz').text('');
+ }
+ }
+ }
+ }
+ updateIntegrationPreview(event, focus);
+ updateIntegrationSplitPreview(event, focus);
+};
+exports.MouseMove = MouseMove;
+const clickIntegrationPoint = (event, focus) => {
+ const pt = getCurvePointFromEvent(event, focus);
+ if (!pt) return;
+ const {
+ firstIntegrationPoint,
+ selectUiSweepAct
+ } = focus;
+ if (!firstIntegrationPoint) {
+ // Keep the draft local to D3; the second click emits the existing sweep payload.
+ const draftPoint = {
+ x: pt.x,
+ y: pt.y,
+ jcampIdx: focus.jcampIdx,
+ dataLength: focus.data.length
+ };
+ Object.assign(focus, {
+ firstIntegrationPoint: draftPoint
+ });
+ (0, _integration_draft.setPendingIntegrationDraft)({
+ jcampIdx: focus.jcampIdx,
+ dataLength: focus.data.length,
+ cancel: () => cancelIntegrationDraft(focus)
+ });
+ drawIntegrationPreview(focus, draftPoint, draftPoint);
+ return;
+ }
+ cancelIntegrationDraft(focus);
+ if (firstIntegrationPoint.x === pt.x) {
+ return;
+ }
+ selectUiSweepAct((0, _sweep.buildSweepPayloadFromXBounds)(focus, firstIntegrationPoint.x, pt.x));
+};
+const ClickCompass = (event, focus) => {
+ event.stopPropagation();
+ event.preventDefault();
+ if (focus.isUiAddIntgSt) {
+ clickIntegrationPoint(event, focus);
+ return;
+ }
+ if (focus.isUiSplitIntgSt) {
+ const {
+ splitX,
+ target
+ } = (0, _integration_split.getIntegrationSplitTargetFromEvent)(event, focus);
+ if (!target) return;
+ (0, _integration_split.clearIntegrationSplitPreview)(focus);
+ focus.splitIntegrationAct({
+ curveIdx: focus.jcampIdx,
+ target,
+ splitX,
+ data: focus.data
+ });
+ return;
+ }
+ const {
+ xt,
+ yt
+ } = TfRescale(focus);
+ let pt = fetchPt(event, focus, xt);
+ const {
+ layout,
+ cyclicvoltaSt,
+ jcampIdx
+ } = focus;
+ if (_format.default.isCyclicVoltaLayout(layout)) {
+ pt = fetchFreePt(event, focus, xt, yt);
+ const onPeak = false;
+ if (cyclicvoltaSt) {
+ const {
+ spectraList
+ } = cyclicvoltaSt;
+ const spectra = spectraList[jcampIdx];
+ const voltammetryPeakIdx = spectra.selectedIdx;
+ focus.clickUiTargetAct(pt, onPeak, voltammetryPeakIdx, jcampIdx);
+ } else {
+ focus.clickUiTargetAct(pt, onPeak);
+ }
+ } else {
+ focus.clickUiTargetAct(pt, false);
+ }
+};
+exports.ClickCompass = ClickCompass;
+const MountCompass = focus => {
+ const {
+ root,
+ w,
+ h
+ } = focus;
+ const compass = root.append('g').attr('class', 'compass');
+ const cursor = root.append('g').attr('class', 'cursor');
+ const preview = root.append('g').attr('class', 'integration-preview').attr('clip-path', 'url(#clip)');
+ const overlay = root.append('rect').attr('class', 'overlay-focus').attr('width', w).attr('height', h).attr('opacity', 0.0);
+ compass.append('line').attr('class', 'x-hover-line hover-line').attr('stroke', '#777').attr('stroke-width', 1).attr('stroke-dasharray', 2, 2);
+ compass.append('circle').attr('r', 4).attr('fill', 'none').attr('stroke', '#777').attr('stroke-width', 2);
+ cursor.append('text').attr('class', 'cursor-txt').attr('font-family', 'Helvetica').style('font-size', '12px').style('text-anchor', 'middle');
+ cursor.append('text').attr('class', 'cursor-txt-hz').attr('font-family', 'Helvetica').style('font-size', '12px').style('text-anchor', 'middle').style('fill', '#D68910');
+ preview.selectAll('*').remove();
+ overlay.on('mousemove', event => MouseMove(event, focus)).on('click', event => ClickCompass(event, focus));
+};
+exports.MountCompass = MountCompass;
\ No newline at end of file
diff --git a/dist/helpers/converter.js b/dist/helpers/converter.js
new file mode 100644
index 00000000..da24848d
--- /dev/null
+++ b/dist/helpers/converter.js
@@ -0,0 +1,99 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ToXY = exports.PksEdit = exports.PeckersEdit = exports.IsSame = void 0;
+const ToXY = data => {
+ const length = data ? data.length : 0;
+ if (length === 0) return [];
+ let peaks = [];
+ let i = 0;
+ for (i = 0; i < length; i += 1) {
+ const {
+ x,
+ y
+ } = data[i];
+ peaks = [...peaks, [x, y]];
+ }
+ return peaks;
+};
+exports.ToXY = ToXY;
+const IsSame = (one, two) => Math.abs((one - two) * 10000000) < 1.0;
+exports.IsSame = IsSame;
+const pksRmNeg = (dataPks, editPeakSt) => {
+ const {
+ selectedIdx,
+ peaks
+ } = editPeakSt;
+ const selectedEditPeaks = peaks[selectedIdx];
+ if (!selectedEditPeaks) {
+ return dataPks;
+ }
+ const {
+ neg
+ } = selectedEditPeaks;
+ if (!neg) {
+ return dataPks;
+ }
+ const negXs = neg.map(n => n.x);
+ const result = dataPks.map(p => {
+ const idx = negXs.findIndex(nx => IsSame(nx, p.x));
+ return idx >= 0 ? null : p;
+ }).filter(r => r != null);
+ return result;
+};
+const pksAddPos = (dataPks, editPeakSt) => {
+ const {
+ selectedIdx,
+ peaks
+ } = editPeakSt;
+ const selectedEditPeaks = peaks[selectedIdx];
+ if (!selectedEditPeaks) {
+ return dataPks;
+ }
+ const {
+ pos
+ } = selectedEditPeaks;
+ if (!pos) {
+ return dataPks;
+ }
+ const posXs = pos.map(p => p.x);
+ const posPks = dataPks.map(p => {
+ const idx = posXs.findIndex(px => px === p.x);
+ return idx >= 0 ? null : p;
+ }).filter(r => r != null);
+ const result = [...posPks, ...pos];
+ return result;
+};
+const PksEdit = (dataPks, editPeakSt, voltammetryPeak = false) => {
+ if (voltammetryPeak && voltammetryPeak.length > 0) {
+ let modDataPks = [];
+ voltammetryPeak.forEach(peak => {
+ if (peak.max) {
+ modDataPks = [...modDataPks, peak.max];
+ }
+ if (peak.min) {
+ modDataPks = [...modDataPks, peak.min];
+ }
+ });
+ modDataPks = modDataPks.sort((a, b) => a.x - b.x);
+ return modDataPks;
+ }
+ let modDataPks = pksAddPos(dataPks, editPeakSt);
+ modDataPks = pksRmNeg(modDataPks, editPeakSt);
+ modDataPks = modDataPks.sort((a, b) => a.x - b.x);
+ return modDataPks;
+};
+exports.PksEdit = PksEdit;
+const PeckersEdit = voltammetryPeak => {
+ let modDataPeckers = [];
+ voltammetryPeak.forEach(peak => {
+ if (peak.pecker) {
+ modDataPeckers = [...modDataPeckers, peak.pecker];
+ }
+ });
+ modDataPeckers = modDataPeckers.sort((a, b) => a.x - b.x);
+ return modDataPeckers;
+};
+exports.PeckersEdit = PeckersEdit;
\ No newline at end of file
diff --git a/dist/helpers/extractParams.js b/dist/helpers/extractParams.js
new file mode 100644
index 00000000..cbb4f86a
--- /dev/null
+++ b/dist/helpers/extractParams.js
@@ -0,0 +1,85 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.extractParams = void 0;
+var _format = _interopRequireDefault(require("./format"));
+const getScanIdx = (entity, scanSt) => {
+ const {
+ target,
+ isAuto
+ } = scanSt;
+ const {
+ features,
+ spectra
+ } = entity;
+ const defaultFeat = features.editPeak || features.autoPeak || features[0];
+ const hasEdit = !!defaultFeat.scanEditTarget;
+ const defaultIdx = isAuto || !hasEdit ? defaultFeat.scanAutoTarget : defaultFeat.scanEditTarget;
+ const defaultCount = +spectra.length;
+ let idx = +(target || defaultIdx || 0);
+ if (idx > defaultCount) {
+ idx = defaultCount;
+ }
+ return idx - 1;
+};
+const extrShare = (entity, thresSt, scanIdx = 0) => {
+ const {
+ spectra,
+ features
+ } = entity;
+ // const { autoPeak, editPeak } = features; // TBD
+ const autoPeak = features.autoPeak || features[scanIdx] || features[0];
+ const editPeak = features.editPeak || features[scanIdx] || features[0];
+ const hasEdit = editPeak && editPeak.data ? editPeak.data[0].x.length > 0 : false;
+ const feature = hasEdit && thresSt.isEdit ? editPeak : autoPeak;
+ const {
+ integration,
+ multiplicity
+ } = features;
+ return {
+ spectra,
+ feature,
+ hasEdit,
+ integration,
+ multiplicity
+ };
+};
+const extrMs = (entity, thresSt, scanSt) => {
+ const scanIdx = getScanIdx(entity, scanSt);
+ const {
+ spectra,
+ feature,
+ hasEdit
+ } = extrShare(entity, thresSt, scanIdx);
+ const topic = spectra[scanIdx].data[0];
+ return {
+ topic,
+ feature,
+ hasEdit
+ };
+};
+const extrNi = (entity, thresSt) => {
+ const scanIdx = 0;
+ const {
+ spectra,
+ feature,
+ hasEdit,
+ integration,
+ multiplicity
+ } = extrShare(entity, thresSt, scanIdx);
+ const topic = spectra[0].data[0];
+ return {
+ topic,
+ feature,
+ hasEdit,
+ integration,
+ multiplicity
+ };
+};
+const extractParams = (entity, thresSt, scanSt) => _format.default.isMsLayout(entity.layout) ? extrMs(entity, thresSt, scanSt) : extrNi(entity, thresSt);
+
+// eslint-disable-line
+exports.extractParams = extractParams;
\ No newline at end of file
diff --git a/dist/helpers/extractPeaksEdit.js b/dist/helpers/extractPeaksEdit.js
new file mode 100644
index 00000000..92af43f4
--- /dev/null
+++ b/dist/helpers/extractPeaksEdit.js
@@ -0,0 +1,75 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.extractPeaksEdit = exports.extractAutoPeaks = exports.extractAreaUnderCurve = void 0;
+var _converter = require("./converter");
+var _chem = require("./chem");
+var _shift = require("./shift");
+var _format = _interopRequireDefault(require("./format"));
+var _integration = require("./integration");
+const niOffset = (shiftSt, atIndex = 0) => {
+ const {
+ shifts
+ } = shiftSt;
+ const selectedShift = shifts[atIndex];
+ if (!selectedShift) {
+ return 0;
+ }
+ const {
+ ref,
+ peak
+ } = selectedShift;
+ const offset = (0, _shift.FromManualToOffset)(ref, peak);
+ return offset;
+};
+const msOffset = () => 0;
+const extractPeaksEdit = (feature, editPeakSt, thresSt, shiftSt, layoutSt, atIndex = 0) => {
+ const offset = _format.default.isMsLayout(layoutSt) ? msOffset() : niOffset(shiftSt, atIndex);
+ const peaks = (0, _chem.Convert2Peak)(feature, thresSt.value, offset);
+ const peaksEdit = (0, _converter.PksEdit)(peaks, editPeakSt);
+ return peaksEdit;
+};
+exports.extractPeaksEdit = extractPeaksEdit;
+const extractAutoPeaks = (feature, thresSt, shiftSt, layoutSt, atIndex = 0) => {
+ const offset = _format.default.isMsLayout(layoutSt) ? msOffset() : niOffset(shiftSt, atIndex);
+ const peaks = (0, _chem.Convert2Peak)(feature, thresSt.value, offset);
+ return peaks;
+};
+exports.extractAutoPeaks = extractAutoPeaks;
+const getAUCValue = (integrationSt, layoutSt) => {
+ const {
+ refArea,
+ refFactor,
+ stack
+ } = integrationSt;
+ if (Array.isArray(stack) && stack.length > 0) {
+ const data = stack.at(-1);
+ const ignoreRef = _format.default.isHplcUvVisLayout(layoutSt);
+ return (0, _integration.calcArea)(data, refArea, refFactor, ignoreRef);
+ }
+ return 0;
+};
+const extractAreaUnderCurve = (allIntegrationSt, presentIntegrationSt, layoutSt) => {
+ if (_format.default.isHplcUvVisLayout(layoutSt) && Array.isArray(allIntegrationSt) && presentIntegrationSt) {
+ const results = [];
+ allIntegrationSt.forEach(inte => {
+ const {
+ integrations
+ } = inte;
+ const subResults = [];
+ integrations.forEach(subInte => {
+ const aucVal = getAUCValue(subInte, layoutSt);
+ subResults.push(aucVal);
+ });
+ results.push(subResults);
+ });
+ return results;
+ }
+ return null;
+};
+
+// eslint-disable-line
+exports.extractAreaUnderCurve = extractAreaUnderCurve;
\ No newline at end of file
diff --git a/dist/helpers/focus.js b/dist/helpers/focus.js
new file mode 100644
index 00000000..c48f6dc7
--- /dev/null
+++ b/dist/helpers/focus.js
@@ -0,0 +1,10 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.mpyIdTag = exports.itgIdTag = void 0;
+const itgIdTag = d => `${Math.round(1000 * d.xL)}-${Math.round(1000 * d.xU)}`;
+exports.itgIdTag = itgIdTag;
+const mpyIdTag = d => `${Math.round(1000 * d.xExtent.xL)}-${Math.round(1000 * d.xExtent.xU)}`;
+exports.mpyIdTag = mpyIdTag;
\ No newline at end of file
diff --git a/dist/helpers/format.js b/dist/helpers/format.js
new file mode 100644
index 00000000..b528beb8
--- /dev/null
+++ b/dist/helpers/format.js
@@ -0,0 +1,656 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _jcampconverter = _interopRequireDefault(require("jcampconverter"));
+var _converter = require("./converter");
+var _list_layout = require("../constants/list_layout");
+var _multiplicity_calc = require("./multiplicity_calc");
+/* eslint-disable prefer-destructuring */
+/* eslint-disable no-mixed-operators, prefer-object-spread,
+function-paren-newline, no-unused-vars, default-param-last */
+
+const spectraDigit = layout => {
+ switch (layout) {
+ case _list_layout.LIST_LAYOUT.IR:
+ case _list_layout.LIST_LAYOUT.RAMAN:
+ case _list_layout.LIST_LAYOUT.UVVIS:
+ case _list_layout.LIST_LAYOUT.HPLC_UVVIS:
+ case _list_layout.LIST_LAYOUT.TGA:
+ case _list_layout.LIST_LAYOUT.DSC:
+ case _list_layout.LIST_LAYOUT.XRD:
+ case _list_layout.LIST_LAYOUT.CDS:
+ case _list_layout.LIST_LAYOUT.SEC:
+ case _list_layout.LIST_LAYOUT.GC:
+ case _list_layout.LIST_LAYOUT.MS:
+ return 0;
+ case _list_layout.LIST_LAYOUT.C13:
+ return 1;
+ case _list_layout.LIST_LAYOUT.H1:
+ case _list_layout.LIST_LAYOUT.F19:
+ case _list_layout.LIST_LAYOUT.P31:
+ case _list_layout.LIST_LAYOUT.N15:
+ case _list_layout.LIST_LAYOUT.Si29:
+ case _list_layout.LIST_LAYOUT.PLAIN:
+ case _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY:
+ default:
+ return 2;
+ }
+};
+const fixDigit = (input, precision) => {
+ const output = input || 0.0;
+ return output.toFixed(precision);
+};
+const buildData = entity => {
+ if (!entity) return {
+ isExist: false
+ };
+ const sp = entity && entity.spectrum;
+ const xLabel = sp ? `X (${sp.xUnit})` : '';
+ const yLabel = sp ? `Y (${sp.yUnit})` : '';
+ return {
+ entity,
+ xLabel,
+ yLabel,
+ isExist: true
+ };
+};
+const toPeakStr = peaks => {
+ const arr = peaks.map(p => `${p.x},${p.y}`);
+ const str = arr.join('#');
+ return str;
+};
+const spectraOps = {
+ [_list_layout.LIST_LAYOUT.PLAIN]: {
+ head: '',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.H1]: {
+ head: '1H',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.C13]: {
+ head: '13C',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.F19]: {
+ head: '19F',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.P31]: {
+ head: '31P',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.N15]: {
+ head: '15N',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.Si29]: {
+ head: '29Si',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.IR]: {
+ head: 'IR',
+ tail: ' cm-1'
+ },
+ [_list_layout.LIST_LAYOUT.RAMAN]: {
+ head: 'RAMAN',
+ tail: ' cm-1'
+ },
+ [_list_layout.LIST_LAYOUT.UVVIS]: {
+ head: 'UV-VIS (absorption, solvent), λmax',
+ tail: ' nm'
+ },
+ [_list_layout.LIST_LAYOUT.HPLC_UVVIS]: {
+ head: 'HPLC UV/VIS (transmittance)',
+ tail: ''
+ },
+ [_list_layout.LIST_LAYOUT.TGA]: {
+ head: 'THERMOGRAVIMETRIC ANALYSIS',
+ tail: ' SECONDS'
+ },
+ [_list_layout.LIST_LAYOUT.DSC]: {
+ head: 'DIFFERENTIAL SCANNING CALORIMETRY',
+ tail: ' SECONDS'
+ },
+ [_list_layout.LIST_LAYOUT.MS]: {
+ head: 'MASS',
+ tail: ' m/z'
+ },
+ [_list_layout.LIST_LAYOUT.XRD]: {
+ head: 'XRD',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY]: {
+ head: 'CV',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.CDS]: {
+ head: 'CIRCULAR DICHROISM SPECTROSCOPY',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.SEC]: {
+ head: 'SIZE EXCLUSION CHROMATOGRAPHY',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.GC]: {
+ head: 'GAS CHROMATOGRAPHY',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.EMISSIONS]: {
+ head: 'EMISSION',
+ tail: '.'
+ },
+ [_list_layout.LIST_LAYOUT.DLS_INTENSITY]: {
+ head: 'DLS',
+ tail: '.'
+ }
+};
+const rmRef = (peaks, shift, atIndex = 0) => {
+ if (!shift) return peaks;
+ const {
+ shifts
+ } = shift;
+ const selectedShift = shifts[atIndex];
+ const refValue = selectedShift.ref.value || selectedShift.peak.x;
+ return peaks.map(p => (0, _converter.IsSame)(p.x, refValue) ? null : p).filter(r => r != null);
+};
+const formatedMS = (peaks, maxY, decimal = 2, isAscend = true) => {
+ const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b);
+ const descendFunc = (a, b) => parseFloat(b) - parseFloat(a);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ let ordered = {};
+ peaks.forEach(p => {
+ const x = fixDigit(p.x, decimal);
+ const better = !ordered[x] || p.y > ordered[x];
+ if (better) {
+ ordered = Object.assign({}, ordered, {
+ [x]: p.y
+ });
+ }
+ });
+ ordered = Object.keys(ordered).sort(sortFunc).map(k => ({
+ x: k,
+ y: ordered[k]
+ }));
+ return ordered.map(o => `${o.x} (${parseInt(100 * o.y / maxY, 10)})`).join(', ');
+};
+const emLevel = (boundary, val, lowerIsStronger) => {
+ const {
+ maxY,
+ minY
+ } = boundary;
+ const ratio = lowerIsStronger ? 100 * (val - minY) / (maxY - minY) : 100 * (maxY - val) / (maxY - minY);
+ if (ratio > 85) return 'vw';
+ if (ratio > 60) return 'w';
+ if (ratio > 45) return 'm';
+ if (ratio > 30) return 's';
+ return 'vs';
+};
+const formatedEm = (peaks, maxY, decimal = 2, isAscend = true, isIntensity = false, boundary = {}, lowerIsStronger = false) => {
+ const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b);
+ const descendFunc = (a, b) => parseFloat(b) - parseFloat(a);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ let ordered = {};
+ peaks.forEach(p => {
+ const x = fixDigit(p.x, decimal);
+ const better = !ordered[x] || p.y > ordered[x];
+ if (better) {
+ ordered = Object.assign({}, ordered, {
+ [x]: p.y
+ });
+ }
+ });
+ ordered = Object.keys(ordered).sort(sortFunc).map(k => ({
+ x: k,
+ y: ordered[k]
+ }));
+ if (isIntensity) {
+ return ordered.map(o => `${o.x} (${emLevel(boundary, o.y, lowerIsStronger)})`).join(', ');
+ }
+ return ordered.map(o => `${o.x}`).join(', ');
+};
+const formatedUvVis = (peaks, maxY, decimal = 2, isAscend = true, isIntensity = false, boundary = {}, lowerIsStronger = false) => {
+ const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b);
+ const descendFunc = (a, b) => parseFloat(b) - parseFloat(a);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ let ordered = {};
+ peaks.forEach(p => {
+ const x = fixDigit(p.x, decimal);
+ const better = !ordered[x] || p.y > ordered[x];
+ if (better) {
+ ordered = Object.assign({}, ordered, {
+ [x]: p.y
+ });
+ }
+ });
+ ordered = Object.keys(ordered).sort(sortFunc).map(k => ({
+ x: k,
+ y: ordered[k]
+ }));
+
+ // return ordered.map(o => `${o.x} (${o.y.toFixed(2)})`)
+ // .join(', ');
+ return ordered.map(o => `${o.x}`).join(', ');
+};
+const formatedEmissions = (peaks, maxY, decimal = 2, isAscend = true, isIntensity = false, boundary = {}, lowerIsStronger = false) => {
+ const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b);
+ const descendFunc = (a, b) => parseFloat(b) - parseFloat(a);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ let ordered = {};
+ peaks.forEach(p => {
+ const x = fixDigit(p.x, decimal);
+ const better = !ordered[x] || p.y > ordered[x];
+ if (better) {
+ ordered = Object.assign({}, ordered, {
+ [x]: p.y
+ });
+ }
+ });
+ ordered = Object.keys(ordered).sort(sortFunc).map(k => ({
+ x: k,
+ y: ordered[k]
+ }));
+ return ordered.map(o => `${o.x} nm (${fixDigit(o.y, 2)} a.u.)`).join(', ');
+};
+const formatedDLSIntensity = (peaks, maxY, decimal = 2, isAscend = true, isIntensity = false, boundary = {}, lowerIsStronger = false) => {
+ const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b);
+ const descendFunc = (a, b) => parseFloat(b) - parseFloat(a);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ let ordered = {};
+ peaks.forEach(p => {
+ const x = fixDigit(p.x, decimal);
+ const better = !ordered[x] || p.y > ordered[x];
+ if (better) {
+ ordered = Object.assign({}, ordered, {
+ [x]: fixDigit(p.y, 2)
+ });
+ }
+ });
+ ordered = Object.keys(ordered).sort(sortFunc).map(k => ({
+ x: k,
+ y: ordered[k]
+ }));
+ return ordered.map(o => `${o.x} nm (${o.y} %)`).join(', ');
+};
+const formatedHplcUvVis = (peaks, decimal = 2, integration) => {
+ let stack = [];
+ if (integration) {
+ stack = integration.stack;
+ }
+ let ordered = {};
+ peaks.forEach(p => {
+ const x = fixDigit(p.x, decimal);
+ const better = !ordered[x] || p.y > ordered[x];
+ if (better) {
+ ordered = Object.assign({}, ordered, {
+ [x]: p.y
+ });
+ }
+ });
+ ordered = Object.keys(ordered).map(k => ({
+ x: k,
+ y: ordered[k]
+ }));
+ const arrResult = [];
+ ordered.forEach(o => {
+ let pStr = `${o.x} (${o.y.toFixed(2)})`;
+ if (stack) {
+ stack.forEach(s => {
+ if (s.xL <= o.x && s.xU >= o.x) {
+ pStr = `${o.x} (${o.y.toFixed(2)}, AUC=${s.absoluteArea})`;
+ }
+ });
+ }
+ arrResult.push(pStr);
+ });
+ return arrResult.join(', ');
+};
+const formatedXRD = (peaks, isAscend = true, waveLength, temperature) => {
+ const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b);
+ const descendFunc = (a, b) => parseFloat(b) - parseFloat(a);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ let ordered = {};
+ peaks.forEach(p => {
+ const x = fixDigit(p.x, 1);
+ const better = !ordered[x] || p.y > ordered[x];
+ if (better) {
+ ordered = Object.assign({}, ordered, {
+ [x]: p.y
+ });
+ }
+ });
+ const XRDSource = waveLength.label;
+ const XRDWavelength = `${waveLength.value} ${waveLength.unit}`;
+ ordered = Object.keys(ordered).sort(sortFunc).map(k => ({
+ x: k,
+ y: ordered[k]
+ }));
+ return `(${XRDSource}, ${XRDWavelength}, ${temperature} °C), 2θ [°] (d [nm]): ${ordered.map(o => `${o.x} (${fixDigit(o.y, 2)})`).join(', ')}`;
+};
+const rmShiftFromPeaks = (peaks, shift, atIndex = 0) => {
+ const peaksXY = (0, _converter.ToXY)(peaks);
+ const {
+ shifts
+ } = shift;
+ const selectedShift = shifts[atIndex];
+ if (!selectedShift) {
+ return peaks;
+ }
+ // const digit = spectraDigit(layout);
+ const rmShiftX = selectedShift.ref.value || selectedShift.peak.x;
+ const result = peaksXY.map(p => {
+ const srcX = parseFloat(p[0]);
+ const x = (0, _converter.IsSame)(srcX, rmShiftX) ? null : srcX;
+ if (!x) return null;
+ const y = parseFloat(p[1]);
+ return {
+ x,
+ y
+ };
+ }).filter(r => r != null);
+ return result;
+};
+const peaksBody = ({
+ peaks,
+ layout,
+ decimal,
+ shift,
+ isAscend,
+ isIntensity = false,
+ boundary = {},
+ integration,
+ atIndex = 0,
+ waveLength,
+ temperature
+}) => {
+ const result = rmShiftFromPeaks(peaks, shift, atIndex);
+ const ascendFunc = (a, b) => parseFloat(a.x) - parseFloat(b.x);
+ const descendFunc = (a, b) => parseFloat(b.x) - parseFloat(a.x);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ const ordered = result.sort(sortFunc);
+ const maxY = Math.max(...ordered.map(o => o.y));
+ if (layout === _list_layout.LIST_LAYOUT.MS) {
+ return formatedMS(ordered, maxY, decimal, isAscend);
+ }
+ if (layout === _list_layout.LIST_LAYOUT.IR) {
+ return formatedEm(ordered, maxY, decimal, isAscend, isIntensity, boundary, true);
+ }
+ if (layout === _list_layout.LIST_LAYOUT.UVVIS) {
+ return formatedUvVis(ordered, maxY, decimal, isAscend, isIntensity, boundary, false);
+ }
+ if (layout === _list_layout.LIST_LAYOUT.HPLC_UVVIS) {
+ return formatedHplcUvVis(ordered, decimal, integration);
+ }
+ if (layout === _list_layout.LIST_LAYOUT.EMISSIONS) {
+ return formatedEmissions(ordered, maxY, decimal, isAscend, isIntensity, boundary, false);
+ }
+ if (layout === _list_layout.LIST_LAYOUT.DLS_INTENSITY) {
+ return formatedDLSIntensity(ordered, maxY, decimal, isAscend, isIntensity, boundary, false);
+ }
+ if (layout === _list_layout.LIST_LAYOUT.RAMAN || layout === _list_layout.LIST_LAYOUT.TGA || layout === _list_layout.LIST_LAYOUT.DSC || layout === _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY || layout === _list_layout.LIST_LAYOUT.CDS || layout === _list_layout.LIST_LAYOUT.SEC || layout === _list_layout.LIST_LAYOUT.GC) {
+ return formatedEm(ordered, maxY, decimal, isAscend, isIntensity, boundary, false);
+ }
+ if (layout === _list_layout.LIST_LAYOUT.XRD) {
+ return formatedXRD(ordered, isAscend, waveLength, temperature);
+ }
+ return ordered.map(o => fixDigit(o.x, decimal)).join(', ');
+};
+const peaksWrapper = (layout, shift, atIndex = 0) => {
+ let solvTxt = '';
+ const {
+ shifts
+ } = shift;
+ const selectedShift = shifts[atIndex];
+ if (selectedShift.ref.label) {
+ solvTxt = ` (${selectedShift.ref.label})`;
+ }
+ if (layout === _list_layout.LIST_LAYOUT.PLAIN || layout === _list_layout.LIST_LAYOUT.DLS_ACF) {
+ return {
+ head: '',
+ tail: ''
+ };
+ }
+ const ops = spectraOps[layout];
+ if (!ops) {
+ return {
+ head: '',
+ tail: ''
+ };
+ }
+ return {
+ head: `${ops.head}${solvTxt} = `,
+ tail: ops.tail
+ };
+};
+const isNmrLayout = layoutSt => [_list_layout.LIST_LAYOUT.H1, _list_layout.LIST_LAYOUT.C13, _list_layout.LIST_LAYOUT.F19, _list_layout.LIST_LAYOUT.P31, _list_layout.LIST_LAYOUT.N15, _list_layout.LIST_LAYOUT.Si29].indexOf(layoutSt) >= 0;
+const is29SiLayout = layoutSt => _list_layout.LIST_LAYOUT.Si29 === layoutSt;
+const is15NLayout = layoutSt => _list_layout.LIST_LAYOUT.N15 === layoutSt;
+const is31PLayout = layoutSt => _list_layout.LIST_LAYOUT.P31 === layoutSt;
+const is19FLayout = layoutSt => _list_layout.LIST_LAYOUT.F19 === layoutSt;
+const is13CLayout = layoutSt => _list_layout.LIST_LAYOUT.C13 === layoutSt;
+const is1HLayout = layoutSt => _list_layout.LIST_LAYOUT.H1 === layoutSt;
+const isMsLayout = layoutSt => _list_layout.LIST_LAYOUT.MS === layoutSt;
+const isIrLayout = layoutSt => [_list_layout.LIST_LAYOUT.IR, 'INFRARED'].indexOf(layoutSt) >= 0;
+const isRamanLayout = layoutSt => _list_layout.LIST_LAYOUT.RAMAN === layoutSt;
+const isUvVisLayout = layoutSt => _list_layout.LIST_LAYOUT.UVVIS === layoutSt;
+const isHplcUvVisLayout = layoutSt => _list_layout.LIST_LAYOUT.HPLC_UVVIS === layoutSt;
+const isTGALayout = layoutSt => _list_layout.LIST_LAYOUT.TGA === layoutSt;
+const isDSCLayout = layoutSt => _list_layout.LIST_LAYOUT.DSC === layoutSt;
+const isXRDLayout = layoutSt => _list_layout.LIST_LAYOUT.XRD === layoutSt;
+const isCyclicVoltaLayout = layoutSt => _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY === layoutSt;
+const isCDSLayout = layoutSt => _list_layout.LIST_LAYOUT.CDS === layoutSt;
+const isSECLayout = layoutSt => _list_layout.LIST_LAYOUT.SEC === layoutSt;
+const isGCLayout = layoutSt => _list_layout.LIST_LAYOUT.GC === layoutSt;
+const isEmWaveLayout = layoutSt => [_list_layout.LIST_LAYOUT.IR, _list_layout.LIST_LAYOUT.RAMAN, _list_layout.LIST_LAYOUT.UVVIS, _list_layout.LIST_LAYOUT.HPLC_UVVIS].indexOf(layoutSt) >= 0;
+const hasMultiCurves = layoutSt => [_list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY, _list_layout.LIST_LAYOUT.SEC, _list_layout.LIST_LAYOUT.GC, _list_layout.LIST_LAYOUT.AIF].indexOf(layoutSt) >= 0;
+const isAIFLayout = layoutSt => _list_layout.LIST_LAYOUT.AIF === layoutSt;
+const isEmissionsLayout = layoutSt => _list_layout.LIST_LAYOUT.EMISSIONS === layoutSt;
+const isDLSACFLayout = layoutSt => _list_layout.LIST_LAYOUT.DLS_ACF === layoutSt;
+const isDLSIntensityLayout = layoutSt => _list_layout.LIST_LAYOUT.DLS_INTENSITY === layoutSt;
+const getNmrTyp = layout => {
+ switch (layout) {
+ case _list_layout.LIST_LAYOUT.H1:
+ return 'H';
+ case _list_layout.LIST_LAYOUT.C13:
+ return 'C';
+ case _list_layout.LIST_LAYOUT.F19:
+ return 'F';
+ case _list_layout.LIST_LAYOUT.P31:
+ return 'P';
+ case _list_layout.LIST_LAYOUT.N15:
+ return 'N';
+ case _list_layout.LIST_LAYOUT.Si29:
+ return 'Si';
+ default:
+ return '';
+ }
+};
+const formatPeaksByPrediction = (peaks, layout, isAscend, decimal, predictions = []) => {
+ const pDict = {};
+ peaks.forEach(p => {
+ pDict[p.x.toFixed(decimal)] = 0;
+ });
+ predictions.forEach(p => {
+ const key = p.real.toFixed(decimal);
+ if (typeof pDict[key] === 'number') {
+ pDict[key] += 1;
+ }
+ });
+ const typ = getNmrTyp(layout);
+ const ascendFunc = (a, b) => parseFloat(a.k) - parseFloat(b.k);
+ const descendFunc = (a, b) => parseFloat(b.k) - parseFloat(a.k);
+ const sortFunc = isAscend ? ascendFunc : descendFunc;
+ const pArr = Object.keys(pDict).map(k => {
+ if (pDict[k] === 1) return {
+ k,
+ v: k
+ };
+ return {
+ k,
+ v: `${k} (${pDict[k]}${typ})`
+ };
+ }).sort(sortFunc);
+ const body = pArr.map(p => p.v).join(', ');
+ return body;
+};
+const compareColors = idx => ['#ABB2B9', '#EDBB99', '#ABEBC6', '#D2B4DE', '#F9E79F'][idx % 5];
+const mutiEntitiesColors = idx => ['#2980b9', '#e4b423', '#8e44ad', '#2c3e50', '#6D214F', '#182C61', '#BDC581'][idx % 7];
+const strNumberFixedDecimal = (number, decimal = -1) => {
+ if (decimal <= 0) {
+ return `${number}`;
+ }
+ return number.toFixed(Math.max(decimal, (number.toString().split('.')[1] || []).length));
+};
+const strNumberFixedLength = (number, maxLength = -1) => {
+ if (maxLength <= 0) {
+ return `${number}`;
+ }
+ const splittedNum = number.toString().split('.') || [];
+ if (splittedNum.length === 0) {
+ return `${number}`;
+ }
+ const integerPart = splittedNum[0];
+ if (number >= 0 && maxLength <= integerPart.length || number < 0 && maxLength <= integerPart.length - 1) {
+ // eslint-disable-line
+ return `${Math.round(number)}`;
+ }
+ const lengthToFix = number >= 0 ? maxLength - integerPart.length : maxLength - integerPart.length + 1; // eslint-disable-line
+
+ return number.toFixed(lengthToFix);
+};
+const inlineNotation = (layout, data, sampleName = '') => {
+ let formattedString = '';
+ let quillData = [];
+ const {
+ scanRate,
+ voltaData
+ } = data;
+ switch (layout) {
+ case _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY:
+ {
+ if (!voltaData) {
+ break;
+ }
+ let refString = '';
+ let nonRefString = '';
+ let refOps = [];
+ const nonRefOps = [];
+ const {
+ listPeaks,
+ xyData
+ } = voltaData;
+ const {
+ x
+ } = xyData;
+ listPeaks.forEach(item => {
+ const {
+ isRef,
+ e12,
+ max,
+ min
+ } = item;
+ const e12Str = e12 ? strNumberFixedLength(e12, 3) : '0';
+ const scanRateStr = scanRate ? strNumberFixedLength(scanRate, 3) : '0';
+ if (isRef) {
+ const posNegString = x[0] > x[1] ? 'neg.' : 'pos.';
+ refString = `CV ( mM in vs. Ref (Fc+/Fc) = ${e12Str} V, v = ${scanRateStr} V/s, to ${posNegString}):`;
+ refOps = [{
+ insert: 'CV ( mM in vs. Ref '
+ }, {
+ insert: '(Fc'
+ }, {
+ insert: '+',
+ attributes: {
+ script: 'super'
+ }
+ }, {
+ insert: '/Fc) '
+ }, {
+ insert: `= ${e12Str} V, v = ${scanRateStr} V/s, to ${posNegString}):`
+ }];
+ } else {
+ const delta = max && min ? strNumberFixedLength(Math.abs(max.x - min.x) * 1000, 3) : '0';
+ nonRefString += `\nE1/2 = ([${sampleName}] , ΔEp) = ${e12Str} V (${delta} mV)`;
+ const currentNoneOps = [{
+ insert: '\nE'
+ }, {
+ insert: '1/2',
+ attributes: {
+ script: 'sub'
+ }
+ }, {
+ insert: ` = ([${sampleName}] , ΔE`
+ }, {
+ insert: 'p',
+ attributes: {
+ script: 'sub'
+ }
+ }, {
+ insert: `) = ${e12Str} V (${delta} mV)`
+ }];
+ nonRefOps.push(...currentNoneOps);
+ }
+ });
+ formattedString = refString + nonRefString;
+ quillData = [...refOps, ...nonRefOps];
+ break;
+ }
+ default:
+ break;
+ }
+ return {
+ quillData,
+ formattedString
+ };
+};
+const Format = {
+ toPeakStr,
+ buildData,
+ spectraDigit,
+ spectraOps,
+ peaksBody,
+ peaksWrapper,
+ rmRef,
+ rmShiftFromPeaks,
+ isNmrLayout,
+ is13CLayout,
+ is1HLayout,
+ is19FLayout,
+ is31PLayout,
+ is15NLayout,
+ is29SiLayout,
+ isMsLayout,
+ isIrLayout,
+ isRamanLayout,
+ isUvVisLayout,
+ isHplcUvVisLayout,
+ isTGALayout,
+ isDSCLayout,
+ isXRDLayout,
+ isCyclicVoltaLayout,
+ isCDSLayout,
+ isSECLayout,
+ isEmissionsLayout,
+ isDLSIntensityLayout,
+ isEmWaveLayout,
+ isGCLayout,
+ fixDigit,
+ formatPeaksByPrediction,
+ formatedMS,
+ formatedEm,
+ calcMpyCenter: _multiplicity_calc.calcMpyCenter,
+ compareColors,
+ mutiEntitiesColors,
+ hasMultiCurves,
+ isAIFLayout,
+ isDLSACFLayout,
+ strNumberFixedDecimal,
+ formatedXRD,
+ strNumberFixedLength,
+ inlineNotation
+};
+var _default = exports.default = Format;
\ No newline at end of file
diff --git a/dist/helpers/init.js b/dist/helpers/init.js
new file mode 100644
index 00000000..494047e6
--- /dev/null
+++ b/dist/helpers/init.js
@@ -0,0 +1,67 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.InitTip = exports.InitScale = exports.InitPathCall = exports.InitAxisCall = void 0;
+var _d3Tip = _interopRequireDefault(require("d3-tip"));
+var _format = _interopRequireDefault(require("./format"));
+const d3 = require('d3');
+const InitScale = (target, reverse = true) => {
+ const xRange = reverse ? [target.w, 0] : [0, target.w];
+ const x = d3.scaleLinear().range(xRange);
+ const y = d3.scaleLinear().range([target.h, 0]);
+ return {
+ x,
+ y
+ };
+};
+exports.InitScale = InitScale;
+const InitAxisCall = count => {
+ const yAxisFormat = d3.format('.2n');
+ const xAxisCall = d3.axisBottom().ticks(10);
+ const yAxisCall = d3.axisLeft().ticks(count).tickFormat(yAxisFormat);
+ return {
+ x: xAxisCall,
+ y: yAxisCall
+ };
+};
+exports.InitAxisCall = InitAxisCall;
+const InitPathCall = target => {
+ const line = d3.line().x(d => target.scales.x(d.x)).y(d => target.scales.y(d.y));
+ return line;
+};
+exports.InitPathCall = InitPathCall;
+const tpStyle = () => {
+ const stBorder = ' border: 2px solid #aaa;';
+ const stBorderRadius = ' border-radius: 5px;';
+ const stBackground = ' background: #555;';
+ const stColor = ' color: #fff;';
+ const stPadding = ' padding: 8px;';
+ const stOpacity = ' opacity: 0.9; ';
+ const stZindex = ' z-index: 1999;';
+ const stFontFamily = ' font-family: Helvetica;';
+ const style = stBorder + stBorderRadius + stBackground + stColor + stPadding + stOpacity + stPadding + stZindex + stFontFamily;
+ return style;
+};
+const tpDiv = (d, digits, yFactor = 1) => `
+
+
x: ${_format.default.fixDigit(d.x, digits)}
+
+
y: ${d3.format('.2~e')(d.y * (yFactor || 1))}
+
+ `;
+const InitTip = () => {
+ d3.select('.peak-tp').remove();
+ const tip = (0, _d3Tip.default)().attr('class', 'd3-tip').html(({
+ d,
+ layout,
+ yFactor
+ }) => tpDiv(d, _format.default.spectraDigit(layout), yFactor || 1));
+ return tip;
+};
+exports.InitTip = InitTip;
\ No newline at end of file
diff --git a/dist/helpers/integration.js b/dist/helpers/integration.js
new file mode 100644
index 00000000..53dfdc96
--- /dev/null
+++ b/dist/helpers/integration.js
@@ -0,0 +1,62 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.getLinearBaseline = exports.getIntegrationPoints = exports.getArea = exports.getAbsoluteArea = exports.calcArea = void 0;
+var _calc = require("./calc");
+/* eslint-disable no-mixed-operators */
+
+const getArea = (xL, xU, data) => {
+ let [iL, iU] = [data.length - 1, 0];
+ for (let i = 0; i < data.length; i += 1) {
+ const pt = data[i];
+ if (xL <= pt.x && pt.x <= xU) {
+ if (iL > i) {
+ iL = i;
+ }
+ if (i > iU) {
+ iU = i;
+ }
+ }
+ }
+ return Math.abs(data[iU].k - data[iL].k);
+};
+exports.getArea = getArea;
+const getIntegrationPoints = (xL, xU, data) => data.filter(d => d && Number.isFinite(d.x) && Number.isFinite(d.y) && d.x > xL && d.x < xU);
+exports.getIntegrationPoints = getIntegrationPoints;
+const getLinearBaseline = points => {
+ if (!points || !points[0]) return () => 0;
+ const point1 = points[0];
+ const point2 = points[points.length - 1];
+ const slope = (0, _calc.calcSlope)(point1.x, point1.y, point2.x, point2.y);
+ return point => point1.y + slope * (point.x - point1.x);
+};
+exports.getLinearBaseline = getLinearBaseline;
+const getAbsoluteArea = (xL, xU, data) => {
+ const ps = getIntegrationPoints(xL, xU, data);
+ if (ps.length < 2) return 0;
+ const baselineY = getLinearBaseline(ps);
+ let area = 0;
+ if (ps.length > 1) {
+ for (let i = 1; i < ps.length; i += 1) {
+ const pt = ps[i];
+ const delta = Math.abs(pt.y - baselineY(pt));
+ area += delta;
+ }
+ }
+ return area;
+};
+exports.getAbsoluteArea = getAbsoluteArea;
+const calcArea = (d, refArea, refFactor, ignoreRef = false) => {
+ if (ignoreRef) {
+ const {
+ absoluteArea
+ } = d;
+ return !absoluteArea ? 0 : d.absoluteArea.toFixed(2);
+ }
+ return (d.area * refFactor / refArea).toFixed(2);
+};
+
+// eslint-disable-line
+exports.calcArea = calcArea;
\ No newline at end of file
diff --git a/dist/helpers/integration_draft.js b/dist/helpers/integration_draft.js
new file mode 100644
index 00000000..7563cad8
--- /dev/null
+++ b/dist/helpers/integration_draft.js
@@ -0,0 +1,38 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.setPendingIntegrationDraft = exports.hasPendingIntegrationDraft = exports.forgetPendingIntegrationDraft = exports.confirmCancelPendingIntegration = exports.clearPendingIntegrationDraft = void 0;
+let pendingIntegrationDraft = null;
+const cancelMessage = 'You are currently creating an integration. Are you sure you want to cancel it?';
+const hasPendingIntegrationDraft = () => !!pendingIntegrationDraft;
+exports.hasPendingIntegrationDraft = hasPendingIntegrationDraft;
+const setPendingIntegrationDraft = draft => {
+ pendingIntegrationDraft = draft;
+};
+exports.setPendingIntegrationDraft = setPendingIntegrationDraft;
+const forgetPendingIntegrationDraft = () => {
+ pendingIntegrationDraft = null;
+};
+exports.forgetPendingIntegrationDraft = forgetPendingIntegrationDraft;
+const clearPendingIntegrationDraft = () => {
+ const draft = pendingIntegrationDraft;
+ pendingIntegrationDraft = null;
+ if (draft && typeof draft.cancel === 'function') {
+ draft.cancel();
+ }
+};
+exports.clearPendingIntegrationDraft = clearPendingIntegrationDraft;
+const confirmCancelPendingIntegration = () => {
+ if (!hasPendingIntegrationDraft()) return true;
+ const shouldCancel = typeof window === 'undefined' || typeof window.confirm !== 'function'
+ // This confirmation intentionally protects an in-progress two-click integration.
+ // eslint-disable-next-line no-alert
+ || window.confirm(cancelMessage);
+ if (shouldCancel) {
+ clearPendingIntegrationDraft();
+ }
+ return shouldCancel;
+};
+exports.confirmCancelPendingIntegration = confirmCancelPendingIntegration;
\ No newline at end of file
diff --git a/dist/helpers/integration_split.js b/dist/helpers/integration_split.js
new file mode 100644
index 00000000..dc245c74
--- /dev/null
+++ b/dist/helpers/integration_split.js
@@ -0,0 +1,96 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.resolveSplitPreviewExtent = exports.interpolateY = exports.getSplitXFromEvent = exports.getIntegrationSplitTargetFromEvent = exports.getIntegrationSplitTarget = exports.getIntegrationBounds = exports.drawIntegrationSplitPreview = exports.clearIntegrationSplitPreview = exports.NMR_SPLIT_PREVIEW_EXTENT = void 0;
+var _integration = require("./integration");
+const d3 = require('d3');
+const SPLIT_PREVIEW_CLASS = 'integration-split-preview-line';
+const NMR_SPLIT_PREVIEW_EXTENT = exports.NMR_SPLIT_PREVIEW_EXTENT = {
+ y1: 38,
+ y2: 55
+};
+const getIntegrationBounds = (target, shift = 0) => [target.xL - shift, target.xU - shift].sort((a, b) => a - b);
+exports.getIntegrationBounds = getIntegrationBounds;
+const getSplitXFromEvent = (event, focus) => {
+ const rawMouseX = d3.pointer(event, focus.root.node())[0];
+ return focus.scales.x.invert(rawMouseX);
+};
+exports.getSplitXFromEvent = getSplitXFromEvent;
+const clearIntegrationSplitPreview = focus => {
+ if (!focus || !focus.root) return;
+ focus.root.select(`.${SPLIT_PREVIEW_CLASS}`).remove();
+};
+exports.clearIntegrationSplitPreview = clearIntegrationSplitPreview;
+const getIntegrationSplitTarget = (focus, splitX) => {
+ const splitTargets = focus && focus.integrationSplitTargets;
+ if (!splitTargets || !Number.isFinite(splitX)) return null;
+ const {
+ stack = [],
+ shift = 0
+ } = splitTargets;
+ return stack.find(target => {
+ const [xL, xU] = getIntegrationBounds(target, shift);
+ return splitX > xL && splitX < xU;
+ });
+};
+exports.getIntegrationSplitTarget = getIntegrationSplitTarget;
+const getIntegrationSplitTargetFromEvent = (event, focus) => {
+ const splitX = getSplitXFromEvent(event, focus);
+ const target = getIntegrationSplitTarget(focus, splitX);
+ return {
+ splitX,
+ target
+ };
+};
+exports.getIntegrationSplitTargetFromEvent = getIntegrationSplitTargetFromEvent;
+const interpolateY = (points, x) => {
+ if (!points || points.length === 0) return null;
+ const sortedPoints = [...points].sort((a, b) => a.x - b.x);
+ const upperIndex = sortedPoints.findIndex(point => point.x >= x);
+ if (upperIndex <= 0) return sortedPoints[0].y;
+ if (upperIndex < 0) return sortedPoints[sortedPoints.length - 1].y;
+ const lowerPoint = sortedPoints[upperIndex - 1];
+ const upperPoint = sortedPoints[upperIndex];
+ const xDelta = upperPoint.x - lowerPoint.x;
+ if (xDelta === 0) return lowerPoint.y;
+ const ratio = (x - lowerPoint.x) / xDelta;
+ return lowerPoint.y + ratio * (upperPoint.y - lowerPoint.y);
+};
+exports.interpolateY = interpolateY;
+const resolveSplitPreviewExtent = (focus, target, splitX, shift, ignoreRef) => {
+ if (!focus || !target || !focus.scales || !focus.scales.y) return null;
+ const yt = focus.scales.y;
+ const [xL, xU] = getIntegrationBounds(target, shift);
+ if (!Number.isFinite(splitX) || splitX <= xL || splitX >= xU) return null;
+ if (!ignoreRef) {
+ return NMR_SPLIT_PREVIEW_EXTENT;
+ }
+ const points = (0, _integration.getIntegrationPoints)(xL, xU, focus.data);
+ if (points.length < 2) return null;
+ const baselineY = (0, _integration.getLinearBaseline)(points);
+ const curveY = interpolateY(points, splitX);
+ if (!Number.isFinite(curveY)) return null;
+ return {
+ y1: yt(baselineY({
+ x: splitX
+ })),
+ y2: yt(curveY)
+ };
+};
+exports.resolveSplitPreviewExtent = resolveSplitPreviewExtent;
+const drawIntegrationSplitPreview = (focus, target, splitX, shift, ignoreRef) => {
+ const extent = resolveSplitPreviewExtent(focus, target, splitX, shift, ignoreRef);
+ if (!extent) {
+ clearIntegrationSplitPreview(focus);
+ return;
+ }
+ const xt = focus.scales.x;
+ const x = xt(splitX);
+ const preview = focus.root.select('.integration-preview');
+ preview.raise();
+ const line = preview.selectAll(`.${SPLIT_PREVIEW_CLASS}`).data([extent]);
+ line.enter().append('line').attr('class', SPLIT_PREVIEW_CLASS).attr('stroke', 'red').attr('stroke-width', 2).attr('stroke-dasharray', '4,3').style('pointer-events', 'none').merge(line).attr('x1', x).attr('x2', x).attr('y1', d => d.y1).attr('y2', d => d.y2);
+};
+exports.drawIntegrationSplitPreview = drawIntegrationSplitPreview;
\ No newline at end of file
diff --git a/dist/helpers/mount.js b/dist/helpers/mount.js
new file mode 100644
index 00000000..5f1bb693
--- /dev/null
+++ b/dist/helpers/mount.js
@@ -0,0 +1,110 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.MountThresLine = exports.MountTags = exports.MountRef = exports.MountPath = exports.MountMarker = exports.MountMainFrame = exports.MountGrid = exports.MountComparePath = exports.MountClip = exports.MountBars = exports.MountAxisLabelY = exports.MountAxisLabelX = exports.MountAxis = void 0;
+var _compass = require("./compass");
+const MountTags = target => {
+ const igbPath = target.root.append('g').attr('class', 'igbPath-clip').attr('clip-path', 'url(#clip)');
+ const igcPath = target.root.append('g').attr('class', 'igcPath-clip').attr('clip-path', 'url(#clip)');
+ const igtPath = target.root.append('g').attr('class', 'igtPath-clip').attr('clip-path', 'url(#clip)');
+ const pPath = target.root.append('g').attr('class', 'pPath-clip').attr('clip-path', 'url(#clip)');
+ const bpPath = target.root.append('g').attr('class', 'bpPath-clip').attr('clip-path', 'url(#clip)');
+ const bpTxt = target.root.append('g').attr('class', 'bpTxt-clip').attr('clip-path', 'url(#clip)');
+ const mpybPath = target.root.append('g').attr('class', 'mpybPath-clip').attr('clip-path', 'url(#clip)');
+ const mpyt1Path = target.root.append('g').attr('class', 'mpyt1Path-clip').attr('clip-path', 'url(#clip)');
+ const mpyt2Path = target.root.append('g').attr('class', 'mpyt2Path-clip').attr('clip-path', 'url(#clip)');
+ const mpypPath = target.root.append('g').attr('class', 'mpypPath-clip').attr('clip-path', 'url(#clip)');
+ const aucPath = target.root.append('g').attr('class', 'aucPath-clip').attr('clip-path', 'url(#clip)');
+ const peckerPath = target.root.append('g').attr('class', 'peckerPath-clip').attr('clip-path', 'url(#clip)');
+ return {
+ pPath,
+ bpPath,
+ bpTxt,
+ igbPath,
+ igcPath,
+ igtPath,
+ mpybPath,
+ mpyt1Path,
+ mpyt2Path,
+ mpypPath,
+ aucPath,
+ peckerPath // eslint-disable-line
+ };
+};
+exports.MountTags = MountTags;
+const MountBars = target => {
+ const bars = target.root.append('g').attr('class', 'bars-clip').attr('clip-path', 'url(#clip)');
+ return bars;
+};
+exports.MountBars = MountBars;
+const MountRef = target => {
+ const ref = target.root.append('g').attr('class', 'ref-clip').attr('clip-path', 'url(#ref-clip)');
+ return ref;
+};
+exports.MountRef = MountRef;
+const MountPath = (target, color) => {
+ const path = target.root.append('g').attr('class', 'line-clip').attr('clip-path', 'url(#clip)').append('path').attr('class', 'line').style('fill', 'none').style('stroke', color).style('stroke-width', 1).on('click', event => (0, _compass.ClickCompass)(event, target));
+ return path;
+};
+exports.MountPath = MountPath;
+const MountComparePath = (target, color, id, alpha = 1) => {
+ const path = target.root.append('g').attr('class', 'line-clip-compare').attr('id', id).attr('clip-path', 'url(#clip)').append('path').attr('class', 'line').style('fill', 'none').style('stroke', color).style('stroke-opacity', alpha).style('stroke-width', 1).style('stroke-dasharray', '30, 3').on('click', event => (0, _compass.ClickCompass)(event, target));
+ return path;
+};
+exports.MountComparePath = MountComparePath;
+const MountThresLine = (target, color) => {
+ const thresLineUp = target.root.append('g').attr('class', 'line-clip').attr('clip-path', 'url(#clip)').append('path').attr('class', 'thresholdUp').style('stroke-dasharray', '3, 3').style('fill', 'none').style('stroke', color).style('stroke-width', 1);
+ const thresLineDw = target.root.append('g').attr('class', 'line-clip').attr('clip-path', 'url(#clip)').append('path').attr('class', 'thresholdDw').style('stroke-dasharray', '3, 3').style('fill', 'none').style('stroke', color).style('stroke-width', 1);
+ return [thresLineUp, thresLineDw];
+};
+exports.MountThresLine = MountThresLine;
+const MountGrid = target => {
+ const gridTrans = `translate(0, ${target.h})`;
+ const xGrid = target.root.append('g').attr('class', 'x-grid').attr('transform', gridTrans);
+ const yGrid = target.root.append('g').attr('class', 'y-grid');
+ return {
+ x: xGrid,
+ y: yGrid
+ };
+};
+exports.MountGrid = MountGrid;
+const MountAxis = target => {
+ const xAxisTrans = `translate(0, ${target.h})`;
+ const xAxis = target.root.append('g').attr('class', 'x-axis').attr('transform', xAxisTrans);
+ const yAxis = target.root.append('g').attr('class', 'y-axis');
+ return {
+ x: xAxis,
+ y: yAxis
+ };
+};
+exports.MountAxis = MountAxis;
+const MountAxisLabelX = target => {
+ const xTrans = `translate(${target.w / 2}, ${target.h + 30})`;
+ target.root.append('text').attr('text-anchor', 'middle').attr('transform', xTrans).attr('class', 'xLabel').attr('font-family', 'Helvetica').style('font-size', '12px');
+};
+exports.MountAxisLabelX = MountAxisLabelX;
+const MountAxisLabelY = target => {
+ const yR = 'rotate(-90)';
+ const yTrans = `translate(${16 - target.margin.l}, ${target.h / 2}) ${yR}`;
+ target.root.append('text').attr('text-anchor', 'middle').attr('transform', yTrans).attr('class', 'yLabel').attr('font-family', 'Helvetica').style('font-size', '12px');
+};
+exports.MountAxisLabelY = MountAxisLabelY;
+const MountMarker = (target, color) => {
+ const tTrans = `translate(${target.w - 80}, -10)`;
+ const lTrans = `translate(${target.w - 200}, -18)`;
+ target.root.append('text').attr('text-anchor', 'middle').attr('transform', tTrans).attr('class', 'mark-text').attr('font-family', 'Helvetica');
+ target.root.append('rect').attr('transform', lTrans).attr('width', 30).attr('height', 5).attr('class', 'mark-line').style('fill', color);
+};
+exports.MountMarker = MountMarker;
+const MountClip = target => {
+ target.svg.append('defs').append('clipPath').attr('id', 'clip').append('rect').attr('width', target.w).attr('height', target.h).attr('x', 0).attr('y', 0);
+};
+exports.MountClip = MountClip;
+const MountMainFrame = (target, name) => {
+ const transFrame = `translate(${target.margin.l}, ${target.margin.t})`;
+ const clsName = `${name}-main`;
+ target.svg.append('g').attr('class', clsName).attr('transform', transFrame);
+};
+exports.MountMainFrame = MountMainFrame;
\ No newline at end of file
diff --git a/dist/helpers/multiplicity.js b/dist/helpers/multiplicity.js
new file mode 100644
index 00000000..c1a420b4
--- /dev/null
+++ b/dist/helpers/multiplicity.js
@@ -0,0 +1,42 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.mpyBasicPatterns = exports.groupInterval = exports.getInterval = void 0;
+const mpyBasicPatterns = exports.mpyBasicPatterns = ['s', 'd', 't', 'q', 'quint', 'h', 'sept', 'o', 'n'];
+const getInterval = peaks => {
+ let itvs = [];
+ for (let idx = 0; idx < peaks.length - 1; idx += 1) {
+ const itv = Math.abs(peaks[idx + 1].x - peaks[idx].x);
+ itvs = [...itvs, itv];
+ }
+ return itvs;
+};
+exports.getInterval = getInterval;
+const groupInterval = itvs => {
+ let gitvs = [];
+ itvs.forEach(vv => {
+ let applied = false;
+ gitvs.forEach((gv, idx) => {
+ if (applied) return;
+ if (Math.abs((gv.c - vv) / gv.c) <= 0.03) {
+ const c = (gv.c * gv.es.length + vv) / (gv.es.length + 1);
+ const es = [...gv.es, vv];
+ gitvs = [...gitvs.filter((v, i) => i !== idx), {
+ c,
+ es
+ }];
+ applied = true;
+ }
+ });
+ if (!applied) {
+ gitvs = [...gitvs, {
+ c: vv,
+ es: [vv]
+ }];
+ }
+ });
+ return gitvs;
+};
+exports.groupInterval = groupInterval;
\ No newline at end of file
diff --git a/dist/helpers/multiplicity_calc.js b/dist/helpers/multiplicity_calc.js
new file mode 100644
index 00000000..f3bce198
--- /dev/null
+++ b/dist/helpers/multiplicity_calc.js
@@ -0,0 +1,102 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.calcMpyJStr = exports.calcMpyCoup = exports.calcMpyCenter = void 0;
+var _jAnalyzer = _interopRequireDefault(require("../third_party/jAnalyzer"));
+var _multiplicity = require("./multiplicity");
+var _multiplicity_verify_basic = require("./multiplicity_verify_basic");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const centerX = (ps, shift) => {
+ const pxs = ps.map(p => p.x).sort((a, b) => a - b);
+ const centIdx = (ps.length - 1) / 2;
+ if (centIdx < 0) return 0;
+ return pxs[centIdx] - shift;
+};
+const calcMpyCenter = (ps, shift, typ) => {
+ const count = ps.length;
+ const avgX = ps.reduce((sum, nxt) => sum + nxt.x, 0) / ps.length - shift;
+ if (typ === 'm') return avgX;
+ if (count % 2 === 0) return avgX;
+ return centerX(ps, shift);
+};
+exports.calcMpyCenter = calcMpyCenter;
+const calcMpyJStr = js => {
+ if (!Array.isArray(js) || js.length === 0) return ' - ';
+ const cJ = js.map(j => j.toFixed(3)).join(', ');
+ return `${cJ}`;
+};
+exports.calcMpyJStr = calcMpyJStr;
+const calcMpyPeakWidth = (x, metaSt) => {
+ const {
+ intervalL,
+ intervalR,
+ deltaX
+ } = metaSt.peaks;
+ let idxL = null;
+ intervalL.every((l, idx) => {
+ if (l.x < x) {
+ idxL = idx - 1;
+ return false;
+ }
+ return true;
+ });
+ let idxR = null;
+ intervalR.every((l, idx) => {
+ if (l.x < x) {
+ idxR = idx;
+ return false;
+ }
+ return true;
+ });
+ if (!idxL || !idxR) return 10 * deltaX;
+ return Math.abs(intervalL[idxL].x - intervalR[idxR].x);
+};
+const calcMpyCoup = (pks, metaSt) => {
+ if (pks.length === 0) return {
+ type: '',
+ js: ''
+ };
+ const orderPks = pks.sort((a, b) => b.x - a.x);
+ const {
+ observeFrequency
+ } = metaSt.peaks;
+ const peaks = orderPks.map(p => ({
+ x: p.x,
+ intensity: p.y,
+ width: calcMpyPeakWidth(p.x, metaSt)
+ }));
+ const signal = {
+ nbPeaks: peaks.length,
+ observe: observeFrequency,
+ nucleus: '1H',
+ peaks
+ };
+ _jAnalyzer.default.compilePattern(signal);
+ const type = signal.multiplicity;
+ const js = signal.nmrJs ? signal.nmrJs.map(j => j.coupling).sort() : [];
+ const isTPCMatch = (0, _multiplicity_verify_basic.verifyTypePeakCount)(type, peaks);
+ if (!isTPCMatch) return {
+ type: 'm',
+ js: []
+ };
+ if (['s', 'm'].indexOf(type) >= 0) return {
+ type,
+ js
+ };
+ const oivs = (0, _multiplicity.getInterval)(orderPks);
+ if (type === 't') return (0, _multiplicity_verify_basic.verifyTypeT)(type, js, oivs, metaSt);
+ if (type === 'q') return (0, _multiplicity_verify_basic.verifyTypeQ)(type, js, oivs, metaSt);
+ if (type === 'quint') return (0, _multiplicity_verify_basic.verifyTypeQuint)(type, js, oivs, metaSt);
+ if (type === 'h') return (0, _multiplicity_verify_basic.verifyTypeH)(type, js, oivs, metaSt);
+ if (type === 'sept') return (0, _multiplicity_verify_basic.verifyTypeSept)(type, js, oivs, metaSt);
+ if (type === 'o') return (0, _multiplicity_verify_basic.verifyTypeO)(type, js, oivs, metaSt);
+ return {
+ type,
+ js
+ };
+};
+exports.calcMpyCoup = calcMpyCoup;
\ No newline at end of file
diff --git a/dist/helpers/multiplicity_complat.js b/dist/helpers/multiplicity_complat.js
new file mode 100644
index 00000000..66d321ed
--- /dev/null
+++ b/dist/helpers/multiplicity_complat.js
@@ -0,0 +1,100 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.calcMpyComplat = void 0;
+var _multiplicity = require("./multiplicity");
+const calcMpyComplat = origPeaks => {
+ const peaks = origPeaks.sort((a, b) => a.x - b.x);
+ const count = peaks.length;
+ const itvs = (0, _multiplicity.getInterval)(peaks);
+ const gitvs = (0, _multiplicity.groupInterval)(itvs);
+ let type = 'm';
+ let js = [];
+ switch (count) {
+ case 1:
+ type = 's';
+ js = [];
+ break;
+ case 2:
+ if (gitvs.length === 1) {
+ type = 'd';
+ js = gitvs.map(g => g.c);
+ break;
+ }
+ break;
+ case 3:
+ if (gitvs.length === 1) {
+ type = 't';
+ js = gitvs.map(g => g.c);
+ break;
+ }
+ break;
+ case 4:
+ if (gitvs.length === 1) {
+ type = 'q';
+ js = gitvs.map(g => g.c);
+ break;
+ } else if (gitvs.length === 2) {
+ type = 'dd';
+ js = gitvs.map(g => g.c);
+ break;
+ }
+ break;
+ case 5:
+ if (gitvs.length === 1) {
+ type = 'quint';
+ js = gitvs.map(g => g.c);
+ break;
+ }
+ break;
+ case 6:
+ if (gitvs.length === 1) {
+ type = 'h';
+ js = gitvs.map(g => g.c);
+ break;
+ } else if (gitvs.length === 2) {
+ type = 'dt';
+ js = gitvs.map(g => g.c);
+ break;
+ }
+ // td
+ break;
+ case 7:
+ if (gitvs.length === 1) {
+ type = 'sept';
+ js = gitvs.map(g => g.c);
+ break;
+ } else if (gitvs.length === 3) {
+ type = 'ddd';
+ js = gitvs.map(g => g.c);
+ break;
+ }
+ // td
+ break;
+ case 8:
+ if (gitvs.length === 1) {
+ type = 'o';
+ js = gitvs.map(g => g.c);
+ break;
+ } else if (gitvs.length === 2) {
+ type = 'dq';
+ js = gitvs.map(g => g.c);
+ break;
+ } else if (gitvs.length === 3) {
+ type = 'ddd';
+ js = gitvs.map(g => g.c);
+ break;
+ }
+ // td
+ break;
+ default:
+ break;
+ }
+ return {
+ type,
+ js
+ };
+};
+exports.calcMpyComplat = calcMpyComplat;
\ No newline at end of file
diff --git a/dist/helpers/multiplicity_manual.js b/dist/helpers/multiplicity_manual.js
new file mode 100644
index 00000000..e649508f
--- /dev/null
+++ b/dist/helpers/multiplicity_manual.js
@@ -0,0 +1,125 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.calcMpyManual = void 0;
+var _multiplicity = require("./multiplicity");
+/* eslint-disable prefer-object-spread, default-param-last, no-mixed-operators */
+
+const isTypeM = mpyType => mpyType === 'm';
+const isTypeBasic = mpyType => _multiplicity.mpyBasicPatterns.slice(1).indexOf(mpyType) >= 0;
+const outputTypeM = k => Object.assign({}, k, {
+ mpyType: 'm',
+ js: []
+});
+const outputTypeBasic = (k, mpyType, ivs, freq) => {
+ const numIvs = ivs.length || 1;
+ const js = [freq * ivs.reduce((sum, x) => sum + x) / numIvs];
+ return Object.assign({}, k, {
+ mpyType,
+ js
+ });
+};
+const outputTypeDD = (k, mpyType, ivs, freq) => {
+ if (ivs.length >= 2) {
+ const js = [freq * ivs[0], freq * (ivs[0] + ivs[1])];
+ return Object.assign({}, k, {
+ mpyType,
+ js
+ });
+ }
+ return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+};
+const outputTypeDT = (k, mpyType, ivs, freq) => {
+ if (ivs.length >= 4) {
+ const js = [freq * ivs[0], freq * (ivs[1] + ivs[2] + ivs[3])];
+ return Object.assign({}, k, {
+ mpyType,
+ js
+ });
+ }
+ return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+};
+const outputTypeTD = (k, mpyType, ivs, freq) => {
+ if (ivs.length >= 2) {
+ const js = [freq * ivs[0], freq * (ivs[0] + ivs[1])];
+ return Object.assign({}, k, {
+ mpyType,
+ js
+ });
+ }
+ return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+};
+const outputTypeDQ = (k, mpyType, ivs, freq) => {
+ if (ivs.length >= 2) {
+ const js = [freq * ivs[0], freq * (ivs[0] + ivs[1])];
+ return Object.assign({}, k, {
+ mpyType,
+ js
+ });
+ } // only consider J = ([1,2], [1,3]), not J = ([1,2], [1,5])
+ return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+};
+const outputTypeQD = (k, mpyType, ivs, freq) => {
+ if (ivs.length >= 2) {
+ const js = [freq * ivs[0], freq * (ivs[0] + ivs[1])];
+ return Object.assign({}, k, {
+ mpyType,
+ js
+ });
+ }
+ return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+};
+const outputTypeDDD = (k, mpyType, ivs, freq) => {
+ if (ivs.length >= 3) {
+ const js = [freq * ivs[0], freq * (ivs[0] + ivs[1]), freq * (ivs[0] + ivs[1] + ivs[2] + ivs[3])];
+ return Object.assign({}, k, {
+ mpyType,
+ js
+ });
+ }
+ return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+};
+const calcMpyManual = (k, mpyType, metaSt) => {
+ const {
+ observeFrequency
+ } = metaSt.peaks;
+ const freq = observeFrequency || 1.0;
+ const ivs = (0, _multiplicity.getInterval)(k.peaks);
+ if (ivs.length === 0) return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+ if (isTypeM(mpyType)) return outputTypeM(k);
+ if (isTypeBasic(mpyType)) return outputTypeBasic(k, mpyType, ivs, freq);
+ if (mpyType === 'dd') return outputTypeDD(k, mpyType, ivs, freq);
+ if (mpyType === 'dt') return outputTypeDT(k, mpyType, ivs, freq);
+ if (mpyType === 'td') return outputTypeTD(k, mpyType, ivs, freq);
+ if (mpyType === 'dq') return outputTypeDQ(k, mpyType, ivs, freq);
+ if (mpyType === 'qd') return outputTypeQD(k, mpyType, ivs, freq);
+ if (mpyType === 'ddd') return outputTypeDDD(k, mpyType, ivs, freq);
+ return Object.assign({}, k, {
+ mpyType,
+ js: []
+ });
+};
+exports.calcMpyManual = calcMpyManual;
\ No newline at end of file
diff --git a/dist/helpers/multiplicity_verify_basic.js b/dist/helpers/multiplicity_verify_basic.js
new file mode 100644
index 00000000..f1d7df7a
--- /dev/null
+++ b/dist/helpers/multiplicity_verify_basic.js
@@ -0,0 +1,249 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.verifyTypeT = exports.verifyTypeSept = exports.verifyTypeQuint = exports.verifyTypeQ = exports.verifyTypePeakCount = exports.verifyTypeO = exports.verifyTypeH = void 0;
+/* eslint-disable prefer-object-spread, default-param-last, no-mixed-operators */
+// ---------------------------------------------------------------
+// verifyTypePeakCount
+// ---------------------------------------------------------------
+
+const verifyTypePeakCount = (type, peaks) => {
+ const isBasicWrong = type === 's' && peaks.length > 1 || type === 'd' && peaks.length > 2 || type === 't' && peaks.length > 3 || type === 'q' && peaks.length > 4 || type === 'quint' && peaks.length > 5 || type === 'h' && peaks.length > 6 || type === 'sept' && peaks.length > 7 || type === 'o' && peaks.length > 8 || type === 'n' && peaks.length > 9;
+ let limit = 1;
+ let mStr = type;
+ limit *= 5 ** (mStr.match(/quint/g) || []).length;
+ mStr = mStr.replace(/quint/g, '');
+ limit *= 7 ** (mStr.match(/sept/g) || []).length;
+ mStr = mStr.replace(/sept/g, '');
+ limit *= 2 ** (mStr.match(/d/g) || []).length;
+ mStr = mStr.replace(/d/g, '');
+ limit *= 3 ** (mStr.match(/t/g) || []).length;
+ mStr = mStr.replace(/t/g, '');
+ limit *= 4 ** (mStr.match(/q/g) || []).length;
+ mStr = mStr.replace(/q/g, '');
+ limit *= 6 ** (mStr.match(/h/g) || []).length;
+ mStr = mStr.replace(/h/g, '');
+ limit *= 8 ** (mStr.match(/o/g) || []).length;
+ mStr = mStr.replace(/o/g, '');
+ limit *= 9 ** (mStr.match(/n/g) || []).length;
+ mStr = mStr.replace(/n/g, '');
+ const isAdvanWrong = peaks.length > limit;
+ return !(isBasicWrong || isAdvanWrong);
+};
+
+// ---------------------------------------------------------------
+// Basic Multiplicity verification
+// ---------------------------------------------------------------
+exports.verifyTypePeakCount = verifyTypePeakCount;
+const allowedTolerance = 0.15;
+const faktor = 1.1;
+const passRuleIntervalCounts = (oivs, limit) => oivs.length === limit;
+const getRuleParams = (oivs, metaSt) => {
+ const {
+ deltaX,
+ observeFrequency
+ } = metaSt.peaks;
+ const sivs = [...oivs].sort((a, b) => b - a);
+ const ref = sivs[0];
+ const rDeltaX = Math.abs(2 * deltaX / ref);
+ const tTolerance = rDeltaX > allowedTolerance ? rDeltaX : allowedTolerance;
+ const tolerance = Math.abs(tTolerance * faktor);
+ const roivs = oivs.map(oiv => oiv / ref);
+ const rsivs = sivs.map(siv => siv / ref);
+ return {
+ roivs,
+ rsivs,
+ tolerance,
+ observeFrequency
+ };
+};
+const verifyTypeT = (type, js, oivs, metaSt) => {
+ if (!passRuleIntervalCounts(oivs, 2)) return {
+ type: 'm',
+ js: []
+ };
+ const {
+ rsivs,
+ tolerance
+ } = getRuleParams(oivs, metaSt);
+ const isT = Math.abs(rsivs[0] - rsivs[1]) < tolerance;
+ if (isT) return {
+ type,
+ js
+ };
+ return {
+ type: 'm',
+ js: []
+ };
+};
+exports.verifyTypeT = verifyTypeT;
+const verifyTypeQ = (type, js, oivs, metaSt) => {
+ if (!passRuleIntervalCounts(oivs, 3)) return {
+ type: 'm',
+ js: []
+ };
+ const {
+ roivs,
+ rsivs,
+ tolerance,
+ observeFrequency
+ } = getRuleParams(oivs, metaSt);
+ const isQ = Math.abs(rsivs[0] - rsivs[2]) < tolerance;
+ if (isQ) return {
+ type,
+ js
+ };
+ const isDD = Math.abs(roivs[0] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[1]) >= tolerance;
+ const ddJs = [oivs[0] * observeFrequency, (oivs[0] + oivs[1]) * observeFrequency];
+ if (isDD) return {
+ type: 'dd',
+ js: ddJs
+ };
+ return {
+ type: 'm',
+ js: []
+ };
+};
+exports.verifyTypeQ = verifyTypeQ;
+const verifyTypeQuint = (type, js, oivs, metaSt) => {
+ if (!passRuleIntervalCounts(oivs, 4)) return {
+ type: 'm',
+ js: []
+ };
+ const {
+ rsivs,
+ tolerance
+ } = getRuleParams(oivs, metaSt);
+ const isQuint = Math.abs(rsivs[0] - rsivs[3]) < tolerance;
+ if (isQuint) return {
+ type,
+ js
+ };
+ return {
+ type: 'm',
+ js: []
+ };
+};
+exports.verifyTypeQuint = verifyTypeQuint;
+const verifyTypeH = (type, js, oivs, metaSt) => {
+ if (!passRuleIntervalCounts(oivs, 5)) return {
+ type: 'm',
+ js: []
+ };
+ const {
+ roivs,
+ rsivs,
+ tolerance,
+ observeFrequency
+ } = getRuleParams(oivs, metaSt);
+ const isH = Math.abs(rsivs[0] - rsivs[4]) < tolerance;
+ if (isH) return {
+ type,
+ js
+ };
+ const isTD = Math.abs(roivs[0] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[4]) < tolerance && Math.abs(roivs[1] - roivs[3]) < tolerance && Math.abs(roivs[0] - roivs[1]) >= tolerance;
+ const tdJs = [oivs[0] * observeFrequency, (oivs[0] + oivs[1]) * observeFrequency];
+ if (isTD) return {
+ type: 'td',
+ js: tdJs
+ };
+ const isDT1 = Math.abs(roivs[0] - roivs[1]) < tolerance && Math.abs(roivs[0] - roivs[3]) < tolerance && Math.abs(roivs[0] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[2]) >= tolerance;
+ const dt1Js = [oivs[0] * observeFrequency, (oivs[1] + oivs[2] + oivs[3]) * observeFrequency];
+ if (isDT1) return {
+ type: 'dt',
+ js: dt1Js
+ };
+ const isDT2 = Math.abs(roivs[0] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[1] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[2] - roivs[3]) < tolerance && Math.abs(roivs[0] - roivs[2]) >= tolerance;
+ const dt2Js = [oivs[0] * observeFrequency, (oivs[1] + oivs[2] + oivs[3]) * observeFrequency];
+ if (isDT2) return {
+ type: 'dt',
+ js: dt2Js
+ };
+ return {
+ type: 'm',
+ js: []
+ };
+};
+exports.verifyTypeH = verifyTypeH;
+const verifyTypeSept = (type, js, oivs, metaSt) => {
+ if (!passRuleIntervalCounts(oivs, 6)) return {
+ type: 'm',
+ js: []
+ };
+ const {
+ roivs,
+ rsivs,
+ tolerance,
+ observeFrequency
+ } = getRuleParams(oivs, metaSt);
+ const isSept = Math.abs(rsivs[0] - rsivs[5]) < tolerance;
+ if (isSept) return {
+ type,
+ js
+ };
+ const isDDD = Math.abs(roivs[0] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[3]) < tolerance && Math.abs(roivs[0] - roivs[5]) < tolerance && Math.abs(roivs[1] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[1]) >= tolerance;
+ const dddJs = [oivs[0] * observeFrequency, (oivs[0] + oivs[1]) * observeFrequency, (oivs[0] + oivs[1] + oivs[2]) * observeFrequency];
+ if (isDDD) return {
+ type: 'ddd',
+ js: dddJs
+ };
+ return {
+ type: 'm',
+ js: []
+ };
+};
+exports.verifyTypeSept = verifyTypeSept;
+const verifyTypeO = (type, js, oivs, metaSt) => {
+ if (!passRuleIntervalCounts(oivs, 7)) return {
+ type: 'm',
+ js: []
+ };
+ const {
+ roivs,
+ rsivs,
+ tolerance,
+ observeFrequency
+ } = getRuleParams(oivs, metaSt);
+ const isO = Math.abs(rsivs[0] - rsivs[6]) < tolerance;
+ if (isO) return {
+ type,
+ js
+ };
+ const isQD = Math.abs(roivs[0] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[6]) < tolerance && Math.abs(roivs[1] - roivs[3]) < tolerance && Math.abs(roivs[1] - roivs[5]) < tolerance;
+ const qdJs = [oivs[0] * observeFrequency, (oivs[0] + oivs[1]) * observeFrequency];
+ if (isQD) return {
+ type: 'qd',
+ js: qdJs
+ };
+ const isDQ1 = Math.abs(roivs[0] - roivs[1] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[2] - roivs[3]) < tolerance && Math.abs(roivs[0] - roivs[3] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[4] - roivs[5]) < tolerance && Math.abs(roivs[0] - roivs[6]) < tolerance && Math.abs(roivs[1] - roivs[5]) < tolerance;
+ const dq1Js = [oivs[0] * observeFrequency, (oivs[0] + oivs[1]) * observeFrequency];
+ if (isDQ1) return {
+ type: 'dq',
+ js: dq1Js
+ };
+ const isDQ2 = Math.abs(roivs[0] - roivs[1]) < tolerance && Math.abs(roivs[0] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[5]) < tolerance && Math.abs(roivs[0] - roivs[6]) < tolerance && Math.abs(roivs[0] - roivs[3]) >= tolerance;
+ const dq2Js = [oivs[0] * observeFrequency, (oivs[0] + oivs[1] + oivs[2] + oivs[3]) * observeFrequency];
+ if (isDQ2) return {
+ type: 'dq',
+ js: dq2Js
+ };
+ const isDDD1 = Math.abs(roivs[0] - roivs[2]) < tolerance && Math.abs(roivs[0] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[6]) < tolerance && Math.abs(roivs[1] - roivs[5]) < tolerance;
+ const ddd1Js = [oivs[0] * observeFrequency, (oivs[0] + oivs[1]) * observeFrequency, (oivs[0] + oivs[1] + oivs[2] + oivs[3]) * observeFrequency];
+ if (isDDD1) return {
+ type: 'ddd',
+ js: ddd1Js
+ };
+ const isDDD2 = Math.abs(roivs[0] - roivs[2] - roivs[3]) < tolerance && Math.abs(roivs[0] - roivs[3] - roivs[4]) < tolerance && Math.abs(roivs[0] - roivs[6]) < tolerance && Math.abs(roivs[1] - roivs[5]) < tolerance && Math.abs(roivs[0] - roivs[1]) >= tolerance;
+ const ddd2Js = [oivs[0] * observeFrequency, (oivs[0] + oivs[1]) * observeFrequency, (oivs[0] + oivs[1] + oivs[2]) * observeFrequency];
+ if (isDDD2) return {
+ type: 'ddd',
+ js: ddd2Js
+ };
+ return {
+ type: 'm',
+ js: []
+ };
+};
+exports.verifyTypeO = verifyTypeO;
\ No newline at end of file
diff --git a/dist/helpers/shift.js b/dist/helpers/shift.js
new file mode 100644
index 00000000..917f161e
--- /dev/null
+++ b/dist/helpers/shift.js
@@ -0,0 +1,35 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.VirtalPts = exports.RealPts = exports.FromManualToOffset = exports.CalcResidualX = void 0;
+var _list_shift = require("../constants/list_shift");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const shiftNone = _list_shift.LIST_SHIFT_13C[0];
+const FromManualToOffset = (ref, peak) => {
+ if (!peak || ref.name === shiftNone.name) return 0;
+ const offset = peak.x - ref.value;
+ return offset || 0;
+};
+exports.FromManualToOffset = FromManualToOffset;
+const CalcResidualX = (origRef, origApex, nextApex) => {
+ if (!nextApex) return 0.0; // nextApex = false
+ if (origRef.name === shiftNone.name) return 0.0;
+ const origApexX = origApex ? origApex.x : 0.0;
+ const origShift = origApexX === 0.0 ? 0.0 : origRef.value; // orig shift
+ const resX = origShift - origApexX;
+ return resX;
+};
+exports.CalcResidualX = CalcResidualX;
+const VirtalPts = (pts, resX) => pts.map(pt => Object.assign({
+ x: pt.x + resX,
+ y: pt.y
+}));
+exports.VirtalPts = VirtalPts;
+const RealPts = (pts, resX) => pts.map(pt => Object.assign({
+ x: pt.x - resX,
+ y: pt.y
+}));
+exports.RealPts = RealPts;
\ No newline at end of file
diff --git a/dist/helpers/sweep.js b/dist/helpers/sweep.js
new file mode 100644
index 00000000..b65f4519
--- /dev/null
+++ b/dist/helpers/sweep.js
@@ -0,0 +1,39 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.resolveVisibleYExtent = exports.buildSweepPayloadFromXBounds = void 0;
+const resolveVisibleYExtent = focus => {
+ const {
+ currentExtent,
+ h,
+ scales
+ } = focus;
+ if (currentExtent && currentExtent.yExtent) {
+ return currentExtent.yExtent;
+ }
+ const yes = [h, 0].map(scales.y.invert).sort((a, b) => a - b);
+ return {
+ yL: yes[0],
+ yU: yes[1]
+ };
+};
+exports.resolveVisibleYExtent = resolveVisibleYExtent;
+const buildSweepPayloadFromXBounds = (focus, xA, xB) => {
+ const {
+ data,
+ dataPks
+ } = focus;
+ const xes = [xA, xB].map(x => Number(x)).sort((a, b) => a - b);
+ return {
+ xExtent: {
+ xL: xes[0],
+ xU: xes[1]
+ },
+ yExtent: resolveVisibleYExtent(focus),
+ data,
+ dataPks
+ };
+};
+exports.buildSweepPayloadFromXBounds = buildSweepPayloadFromXBounds;
\ No newline at end of file
diff --git a/dist/helpers/zoom.js b/dist/helpers/zoom.js
new file mode 100644
index 00000000..3fafd924
--- /dev/null
+++ b/dist/helpers/zoom.js
@@ -0,0 +1,22 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+const d3 = require('d3');
+const resetZoom = main => {
+ main.svg.call(main.zoom.transform, d3.zoomIdentity);
+ main.svg.selectAll('.brush').call(main.brush.move, null);
+};
+const MountZoom = (main, zoomed) => {
+ const zoomedCb = event => zoomed(event, main);
+ const resetZoomCb = event => {
+ event.stopPropagation();
+ event.preventDefault();
+ resetZoom(main);
+ };
+ main.zoom.on('zoom', zoomedCb);
+ main.svg.call(main.zoom).on('contextmenu.zoom', resetZoomCb);
+};
+var _default = exports.default = MountZoom;
\ No newline at end of file
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 00000000..88f8ad09
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,877 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+var _react = _interopRequireDefault(require("react"));
+var _reactDom = _interopRequireDefault(require("react-dom"));
+var _material = require("@mui/material");
+var _reactQuill = _interopRequireDefault(require("react-quill"));
+var _app = require("./app");
+var _nmr1h_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr1h_jcamp"));
+var _nmr1h_2_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr1h_2_jcamp"));
+var _nmr13c_dept_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr13c_dept_jcamp"));
+var _nmr13c_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr13c_jcamp"));
+var _nmr19f_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr19f_jcamp"));
+var _nmr31p_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr31p_jcamp"));
+var _nmr15n_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr15n_jcamp"));
+var _nmr29si_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr29si_jcamp"));
+var _ir_jcamp = _interopRequireDefault(require("./__tests__/fixtures/ir_jcamp"));
+var _compare_ir_1_jcamp = _interopRequireDefault(require("./__tests__/fixtures/compare_ir_1_jcamp"));
+var _compare_ir_2_jcamp = _interopRequireDefault(require("./__tests__/fixtures/compare_ir_2_jcamp"));
+var _raman_jcamp = _interopRequireDefault(require("./__tests__/fixtures/raman_jcamp"));
+var _ms_jcamp = _interopRequireDefault(require("./__tests__/fixtures/ms_jcamp"));
+var _nmr_result = _interopRequireDefault(require("./__tests__/fixtures/nmr_result"));
+var _ir_result = _interopRequireDefault(require("./__tests__/fixtures/ir_result"));
+var _phenylalanin = _interopRequireDefault(require("./__tests__/fixtures/phenylalanin"));
+var _compare_uv_vis_jcamp = _interopRequireDefault(require("./__tests__/fixtures/compare_uv_vis_jcamp"));
+var _uv_vis_jcamp = _interopRequireDefault(require("./__tests__/fixtures/uv_vis_jcamp"));
+var _hplc_uvvis_jcamp = _interopRequireDefault(require("./__tests__/fixtures/hplc_uvvis_jcamp"));
+var _hplc_uvvis_jcamp_ = _interopRequireDefault(require("./__tests__/fixtures/hplc_uvvis_jcamp_2"));
+var _tga_jcamp = _interopRequireDefault(require("./__tests__/fixtures/tga_jcamp"));
+var _dsc_jcamp = _interopRequireDefault(require("./__tests__/fixtures/dsc_jcamp"));
+var _xrd_jcamp_ = _interopRequireDefault(require("./__tests__/fixtures/xrd_jcamp_1"));
+var _xrd_jcamp_2 = _interopRequireDefault(require("./__tests__/fixtures/xrd_jcamp_2"));
+var _cyclic_voltammetry_ = _interopRequireDefault(require("./__tests__/fixtures/cyclic_voltammetry_1"));
+var _cyclic_voltammetry_2 = _interopRequireDefault(require("./__tests__/fixtures/cyclic_voltammetry_2"));
+var _cyclic_voltammetry_3 = _interopRequireDefault(require("./__tests__/fixtures/cyclic_voltammetry_3"));
+var _cds_jcamp = _interopRequireDefault(require("./__tests__/fixtures/cds_jcamp"));
+var _sec_1_jcamp = _interopRequireDefault(require("./__tests__/fixtures/sec_1_jcamp"));
+var _sec_2_jcamp = _interopRequireDefault(require("./__tests__/fixtures/sec_2_jcamp"));
+var _sec_3_jcamp = _interopRequireDefault(require("./__tests__/fixtures/sec_3_jcamp"));
+var _sec_4_jcamp = _interopRequireDefault(require("./__tests__/fixtures/sec_4_jcamp"));
+var _aif_jcamp_ = _interopRequireDefault(require("./__tests__/fixtures/aif_jcamp_1"));
+var _aif_jcamp_2 = _interopRequireDefault(require("./__tests__/fixtures/aif_jcamp_2"));
+var _gc_1_jcamp = _interopRequireDefault(require("./__tests__/fixtures/gc_1_jcamp"));
+var _gc_2_jcamp = _interopRequireDefault(require("./__tests__/fixtures/gc_2_jcamp"));
+var _gc_3_jcamp = _interopRequireDefault(require("./__tests__/fixtures/gc_3_jcamp"));
+var _emissions_jcamp = _interopRequireDefault(require("./__tests__/fixtures/emissions_jcamp"));
+var _dls_acf_jcamp = _interopRequireDefault(require("./__tests__/fixtures/dls_acf_jcamp"));
+var _dls_intensity_jcamp = _interopRequireDefault(require("./__tests__/fixtures/dls_intensity_jcamp"));
+var _qDescValue = require("./__tests__/fixtures/qDescValue");
+require("./__tests__/style/svg.css");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, default-param-last, no-nested-ternary */
+
+const pickSelectedSpectrumFromPayload = payload => {
+ const spectraList = payload?.spectra_list;
+ if (!Array.isArray(spectraList)) return payload || {};
+ if (spectraList.length === 0) return {};
+ const selectedIdx = Number.isFinite(payload?.curveSt?.curveIdx) ? payload.curveSt.curveIdx : 0;
+ return spectraList[selectedIdx] || spectraList[0] || {};
+};
+const normalizeShiftForFormatting = shift => {
+ if (shift && Array.isArray(shift.shifts)) return shift;
+ return {
+ selectedIdx: 0,
+ shifts: [shift || {
+ ref: {},
+ peak: false,
+ enable: true
+ }]
+ };
+};
+const nmr1HEntity = _app.FN.ExtractJcamp(_nmr1h_jcamp.default);
+const nmr1HEntity2 = _app.FN.ExtractJcamp(_nmr1h_2_jcamp.default);
+const nmr13CEntity = _app.FN.ExtractJcamp(_nmr13c_jcamp.default);
+const nmr13CDeptEntity = _app.FN.ExtractJcamp(_nmr13c_dept_jcamp.default);
+const nmr19FEntity = _app.FN.ExtractJcamp(_nmr19f_jcamp.default);
+const nmr31PEntity = _app.FN.ExtractJcamp(_nmr31p_jcamp.default);
+const nmr15NEntity = _app.FN.ExtractJcamp(_nmr15n_jcamp.default);
+const nmr29SiEntity = _app.FN.ExtractJcamp(_nmr29si_jcamp.default);
+const irEntity = _app.FN.ExtractJcamp(_ir_jcamp.default);
+const compIr1Entity = _app.FN.ExtractJcamp(_compare_ir_1_jcamp.default);
+const compIr2Entity = _app.FN.ExtractJcamp(_compare_ir_2_jcamp.default);
+const ramanEntity = _app.FN.ExtractJcamp(_raman_jcamp.default);
+const msEntity = _app.FN.ExtractJcamp(_ms_jcamp.default);
+const uvVisEntity = _app.FN.ExtractJcamp(_uv_vis_jcamp.default);
+const compUvVisEntity = _app.FN.ExtractJcamp(_compare_uv_vis_jcamp.default);
+const hplcUVVisEntity = _app.FN.ExtractJcamp(_hplc_uvvis_jcamp.default);
+const hplcUVVisEntity2 = _app.FN.ExtractJcamp(_hplc_uvvis_jcamp_.default);
+const tgaEntity = _app.FN.ExtractJcamp(_tga_jcamp.default);
+const dscEntity = _app.FN.ExtractJcamp(_dsc_jcamp.default);
+const xrdEntity1 = _app.FN.ExtractJcamp(_xrd_jcamp_.default);
+const xrdEntity2 = _app.FN.ExtractJcamp(_xrd_jcamp_2.default);
+const cyclicVoltaEntity1 = _app.FN.ExtractJcamp(_cyclic_voltammetry_.default);
+const cyclicVoltaEntity2 = _app.FN.ExtractJcamp(_cyclic_voltammetry_2.default);
+const cyclicVoltaEntity3 = _app.FN.ExtractJcamp(_cyclic_voltammetry_3.default);
+const cdsEntity = _app.FN.ExtractJcamp(_cds_jcamp.default);
+const secEntity1 = _app.FN.ExtractJcamp(_sec_1_jcamp.default);
+const secEntity2 = _app.FN.ExtractJcamp(_sec_2_jcamp.default);
+const secEntity3 = _app.FN.ExtractJcamp(_sec_3_jcamp.default);
+const secEntity4 = _app.FN.ExtractJcamp(_sec_4_jcamp.default);
+const aifEntity1 = _app.FN.ExtractJcamp(_aif_jcamp_.default);
+const aifEntity2 = _app.FN.ExtractJcamp(_aif_jcamp_2.default);
+const gcEntity1 = _app.FN.ExtractJcamp(_gc_1_jcamp.default);
+const gcEntity2 = _app.FN.ExtractJcamp(_gc_2_jcamp.default);
+const gcEntity3 = _app.FN.ExtractJcamp(_gc_3_jcamp.default);
+const emissionsEntity = _app.FN.ExtractJcamp(_emissions_jcamp.default);
+const dlsAcfEntity = _app.FN.ExtractJcamp(_dls_acf_jcamp.default);
+const dlsIntensityEntity = _app.FN.ExtractJcamp(_dls_intensity_jcamp.default);
+class DemoWriteIr extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ typ: 'nmr 1h',
+ desc: '',
+ predictions: false,
+ molecule: '',
+ showOthers: false,
+ descChanged: ''
+ };
+ this.onClick = this.onClick.bind(this);
+ this.writeMpy = this.writeMpy.bind(this);
+ this.writePeak = this.writePeak.bind(this);
+ this.formatPks = this.formatPks.bind(this);
+ this.formatMpy = this.formatMpy.bind(this);
+ this.savePeaks = this.savePeaks.bind(this);
+ this.predictOp = this.predictOp.bind(this);
+ this.updatInput = this.updatInput.bind(this);
+ this.loadEntity = this.loadEntity.bind(this);
+ this.loadQuill = this.loadQuill.bind(this);
+ this.onShowOthers = this.onShowOthers.bind(this);
+ this.loadOthers = this.loadOthers.bind(this);
+ this.onDescriptionChanged = this.onDescriptionChanged.bind(this);
+ this.loadMultiEntities = this.loadMultiEntities.bind(this);
+ }
+ onClick(typ) {
+ return () => {
+ this.setState({
+ typ,
+ desc: '',
+ predictions: false,
+ molecule: ''
+ });
+ };
+ }
+ onShowOthers(jcamp) {
+ // eslint-disable-line
+ this.setState({
+ showOthers: true
+ });
+ }
+ onDescriptionChanged(content) {
+ // console.log(content)
+ this.setState({
+ descChanged: content
+ });
+ }
+ loadEntity() {
+ const {
+ typ
+ } = this.state;
+ switch (typ) {
+ case 'nmr 1h':
+ return nmr1HEntity;
+ case 'nmr 13c':
+ return nmr13CEntity;
+ case 'nmr 13c dept':
+ return nmr13CDeptEntity;
+ case 'nmr 19f':
+ return nmr19FEntity;
+ case 'nmr 31p':
+ return nmr31PEntity;
+ case 'nmr 15n':
+ return nmr15NEntity;
+ case 'nmr 29si':
+ return nmr29SiEntity;
+ case 'ir':
+ return irEntity;
+ case 'raman':
+ return ramanEntity;
+ case 'uv/vis':
+ return uvVisEntity;
+ case 'hplc uv/vis':
+ return hplcUVVisEntity;
+ case 'tga':
+ return tgaEntity;
+ case 'dsc':
+ return dscEntity;
+ case 'xrd':
+ return xrdEntity1;
+ case 'cyclic volta':
+ return cyclicVoltaEntity2;
+ case 'cds':
+ return cdsEntity;
+ case 'sec':
+ return secEntity1;
+ case 'aif':
+ return aifEntity1;
+ case 'emissions':
+ return emissionsEntity;
+ case 'dls acf':
+ return dlsAcfEntity;
+ case 'dls intensity':
+ return dlsIntensityEntity;
+ case 'gc':
+ return gcEntity1;
+ case 'ms':
+ default:
+ return msEntity;
+ }
+ }
+ loadMultiEntities() {
+ const {
+ typ
+ } = this.state;
+ switch (typ) {
+ case 'cyclic volta':
+ return [cyclicVoltaEntity1, cyclicVoltaEntity2, cyclicVoltaEntity3];
+ case 'multi':
+ return [nmr1HEntity, nmr1HEntity2];
+ case 'multi hplc':
+ return [hplcUVVisEntity, hplcUVVisEntity2];
+ case 'multi ir':
+ return [compIr1Entity, compIr2Entity];
+ case 'multi xrd':
+ return [xrdEntity1, xrdEntity2];
+ case 'sec':
+ return [secEntity1, secEntity2, secEntity3, secEntity4];
+ case 'aif':
+ return [aifEntity1, aifEntity2];
+ case 'gc':
+ return [gcEntity1, gcEntity2, gcEntity3];
+ default:
+ return false;
+ }
+ }
+ loadQuill() {
+ const {
+ typ
+ } = this.state;
+ switch (typ) {
+ case 'nmr 1h':
+ return _qDescValue.q1H;
+ case 'nmr 13c':
+ return _qDescValue.q13C;
+ case 'nmr 13c dept':
+ return _qDescValue.q13C;
+ case 'ir':
+ return _qDescValue.qIR;
+ case 'nmr 19f':
+ case 'nmr 31p':
+ case 'nmr 15n':
+ case 'nmr 29si':
+ case 'raman':
+ case 'uv/vis':
+ case 'hplc uv/vis':
+ case 'tga':
+ case 'dsc':
+ case 'xrd':
+ case 'ms':
+ case 'cyclic volta':
+ case 'cds':
+ case 'sec':
+ case 'aif':
+ case 'emissions':
+ case 'dls acf':
+ case 'dls intensity':
+ case 'gc':
+ default:
+ return false;
+ }
+ }
+ loadOthers() {
+ const {
+ showOthers,
+ typ
+ } = this.state;
+ const isIr = typ === 'ir';
+ const isXRD = typ === 'xrd';
+ const others = showOthers ? isIr ? [compIr1Entity, compIr2Entity] : isXRD ? [xrdEntity2] : [compUvVisEntity] : [];
+ return {
+ others,
+ addOthersCb: this.onShowOthers
+ };
+ }
+ rmDollarSign(target) {
+ return target.replace(/\$/g, '');
+ }
+ formatPks({
+ peaks,
+ layout,
+ shift,
+ isAscend,
+ decimal,
+ isIntensity,
+ integration,
+ waveLength,
+ cyclicvoltaSt,
+ curveSt
+ }) {
+ const entity = this.loadEntity();
+ const safeLayout = layout || entity?.layout;
+ const {
+ features
+ } = entity;
+ const {
+ temperature
+ } = entity;
+ const {
+ maxY,
+ minY
+ } = Array.isArray(features) ? {} : features.editPeak || features.autoPeak;
+ const boundary = {
+ maxY,
+ minY
+ };
+ const shiftForFormatting = normalizeShiftForFormatting(shift);
+ const body = _app.FN.peaksBody({
+ peaks,
+ layout: safeLayout,
+ decimal,
+ shift: shiftForFormatting,
+ isAscend,
+ isIntensity,
+ boundary,
+ integration,
+ waveLength,
+ temperature
+ });
+ const wrapper = _app.FN.peaksWrapper(safeLayout, shiftForFormatting);
+ let desc = this.rmDollarSign(wrapper.head) + body + wrapper.tail;
+ if (_app.FN.isCyclicVoltaLayout(safeLayout) && cyclicvoltaSt?.spectraList && curveSt?.listCurves) {
+ const {
+ spectraList
+ } = cyclicvoltaSt;
+ const {
+ curveIdx,
+ listCurves
+ } = curveSt;
+ const selectedVolta = spectraList[curveIdx];
+ const selectedCurve = listCurves[curveIdx];
+ if (!selectedVolta || !selectedCurve?.feature) return desc;
+ const {
+ feature
+ } = selectedCurve;
+ const {
+ scanRate
+ } = feature;
+ const data = {
+ scanRate,
+ voltaData: {
+ listPeaks: selectedVolta.list,
+ xyData: feature.data[0]
+ }
+ };
+ const inlineData = _app.FN.inlineNotation(layout, data);
+ const {
+ formattedString
+ } = inlineData;
+ desc = formattedString;
+ }
+ return desc;
+ }
+ formatMpy({
+ multiplicity,
+ integration,
+ shift,
+ isAscend,
+ decimal,
+ layout
+ }) {
+ // obsv freq
+ const entity = this.loadEntity();
+ const {
+ features
+ } = entity;
+ const {
+ observeFrequency
+ } = Array.isArray(features) ? features[0] : features.editPeak || features.autoPeak;
+ const freq = observeFrequency[0];
+ const freqStr = freq ? `${parseInt(freq, 10)} MHz, ` : '';
+ // multiplicity
+ const {
+ refArea,
+ refFactor
+ } = integration;
+ const shiftVal = multiplicity.shift;
+ const ms = multiplicity.stack;
+ const is = integration.stack;
+ const macs = ms.map(m => {
+ const {
+ peaks,
+ mpyType,
+ xExtent
+ } = m;
+ const {
+ xL,
+ xU
+ } = xExtent;
+ const it = is.filter(i => i.xL === xL && i.xU === xU)[0] || {
+ area: 0
+ };
+ const area = it.area * refFactor / refArea; // eslint-disable-line
+ const center = _app.FN.calcMpyCenter(peaks, shiftVal, mpyType);
+ const safeCenter = Number.isFinite(center) ? center : 0;
+ const xs = m.peaks.map(p => p.x).sort((a, b) => a - b);
+ const [aIdx, bIdx] = isAscend ? [0, xs.length - 1] : [xs.length - 1, 0];
+ const hasValidRange = xs.length > 0 && Number.isFinite(shiftVal);
+ const mxA = mpyType === 'm' && hasValidRange ? (xs[aIdx] - shiftVal).toFixed(decimal) : safeCenter.toFixed(decimal);
+ const mxB = mpyType === 'm' && hasValidRange ? (xs[bIdx] - shiftVal).toFixed(decimal) : safeCenter.toFixed(decimal);
+ return Object.assign({}, m, {
+ area,
+ center,
+ mxA,
+ mxB
+ });
+ }).sort((a, b) => isAscend ? a.center - b.center : b.center - a.center);
+ const str = macs.map(m => {
+ const c = m.center;
+ const type = m.mpyType;
+ const it = Math.round(m.area);
+ const js = m.js.map(j => `J = ${j.toFixed(1)} Hz`).join(', ');
+ const atomCount = layout === '1H' ? `, ${it}H` : '';
+ const location = type === 'm' ? `${m.mxA}–${m.mxB}` : `${c.toFixed(decimal)}`;
+ return m.js.length === 0 ? `${location} (${type}${atomCount})` : `${location} (${type}, ${js}${atomCount})`;
+ }).join(', ');
+ const shiftRef = shift?.ref || {};
+ const {
+ label,
+ value,
+ name
+ } = shiftRef;
+ const hasValidShiftRef = !!label && Number.isFinite(value) && typeof name === 'string';
+ const solvent = hasValidShiftRef ? `${name.split('(')[0].trim()} [${value.toFixed(decimal)} ppm], ` : '';
+ return `${layout} NMR (${freqStr}${solvent}ppm) δ = ${str}.`;
+ }
+ writeMpy(payload) {
+ const {
+ layout,
+ shift,
+ isAscend,
+ decimal,
+ multiplicity,
+ integration
+ } = pickSelectedSpectrumFromPayload(payload);
+ if (!_app.FN.isNmrLayout(layout)) return;
+ const desc = this.formatMpy({
+ multiplicity,
+ integration,
+ shift,
+ isAscend,
+ decimal,
+ layout
+ });
+ this.setState({
+ desc
+ });
+ }
+ writePeak(payload) {
+ const {
+ peaks,
+ layout,
+ shift,
+ isAscend,
+ decimal,
+ isIntensity,
+ integration,
+ waveLength,
+ cyclicvoltaSt,
+ curveSt
+ } = pickSelectedSpectrumFromPayload(payload);
+ const desc = this.formatPks({
+ peaks,
+ layout,
+ shift,
+ isAscend,
+ decimal,
+ isIntensity,
+ integration,
+ waveLength,
+ // eslint-disable-line
+ cyclicvoltaSt,
+ curveSt // eslint-disable-line
+ });
+ this.setState({
+ desc
+ });
+ }
+ savePeaks(payload) {
+ const {
+ peaks,
+ layout,
+ shift,
+ isAscend,
+ decimal,
+ analysis,
+ isIntensity,
+ integration,
+ multiplicity,
+ waveLength
+ } = pickSelectedSpectrumFromPayload(payload);
+ const entity = this.loadEntity();
+ const safeLayout = layout || entity?.layout;
+ const {
+ features
+ } = entity;
+ const {
+ temperature
+ } = entity;
+ const {
+ maxY,
+ minY
+ } = Array.isArray(features) ? features[0] : features.editPeak || features.autoPeak;
+ const boundary = {
+ maxY,
+ minY
+ };
+ const shiftForFormatting = normalizeShiftForFormatting(shift);
+ const body = _app.FN.peaksBody({
+ peaks,
+ layout: safeLayout,
+ decimal,
+ shift: shiftForFormatting,
+ isAscend,
+ isIntensity,
+ boundary,
+ waveLength,
+ temperature
+ });
+ /*eslint-disable */
+ console.log(analysis);
+ console.log(integration);
+ console.log(multiplicity);
+ if (shift?.ref?.label) {
+ const label = this.rmDollarSign(shift.ref.label);
+ alert(`Peaks: ${body}` + '\n' + '- - - - - - - - - - -' + '\n' + `Shift solvent = ${label}, ${shift.ref.value}ppm` + '\n');
+ } else {
+ alert(`Peaks: ${body}` + '\n');
+ }
+ /*eslint-disable */
+ }
+ predictOp({
+ multiplicity,
+ curveSt
+ }) {
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = multiplicity;
+ const selectedMultiplicity = multiplicities[curveIdx];
+ const {
+ stack,
+ shift
+ } = selectedMultiplicity;
+ const targets = stack.map(stk => {
+ const {
+ mpyType,
+ peaks
+ } = stk;
+ return _app.FN.CalcMpyCenter(peaks, shift, mpyType);
+ });
+ // console.log(targets)
+ const {
+ molecule,
+ typ
+ } = this.state;
+ const predictions = {
+ running: true
+ };
+ this.setState({
+ predictions
+ });
+ // simulate fetching...
+ const result = typ === 'ir' ? _ir_result.default : _nmr_result.default;
+ setTimeout(() => {
+ this.setState({
+ predictions: result
+ });
+ }, 2000);
+ }
+ updatInput(e) {
+ const molecule = e.target.value;
+ this.setState({
+ molecule
+ });
+ }
+ render() {
+ const {
+ desc,
+ predictions,
+ molecule,
+ typ
+ } = this.state;
+ const entity = this.loadEntity();
+ const qDescVal = this.loadQuill();
+ const multiEntities = this.loadMultiEntities();
+ let operations = [{
+ name: 'write peaks',
+ value: this.writePeak
+ }, {
+ name: 'save',
+ value: this.savePeaks
+ }].filter(r => r.value);
+ if (_app.FN.isNmrLayout(entity.layout)) {
+ operations = [{
+ name: 'write multiplicity',
+ value: this.writeMpy
+ }, ...operations];
+ }
+ const refreshCb = () => alert('Refresch simulation!');
+ const forecast = {
+ btnCb: this.predictOp,
+ refreshCb,
+ inputCb: this.updatInput,
+ molecule: molecule,
+ predictions
+ };
+ const molSvg = ['nmr 1h', 'ir', 'cyclic volta'].indexOf(typ) >= 0 ? _phenylalanin.default.path : '';
+ const others = this.loadOthers();
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ style: {
+ width: Math.round(window.innerWidth * 0.96)
+ },
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ style: {
+ margin: '0 0 15px 55px'
+ },
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('nmr 1h'),
+ children: "NMR 1H"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('nmr 13c'),
+ children: "NMR 13C"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('nmr 13c dept'),
+ children: "NMR 13C DEPT"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('nmr 19f'),
+ children: "NMR 19F"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('nmr 31p'),
+ children: "NMR 31P"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('nmr 15n'),
+ children: "NMR 15N"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('nmr 29si'),
+ children: "NMR 29Si"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('ir'),
+ children: "IR"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('raman'),
+ children: "RAMAN"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-uv-vis",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('uv/vis'),
+ children: "UV/VIS"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-hplc",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('hplc uv/vis'),
+ children: "HPLC UV/VIS"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-tga",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('tga'),
+ children: "TGA"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-dsc",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('dsc'),
+ children: "DSC"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-xrd",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('xrd'),
+ children: "XRD"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-cv",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('cyclic volta'),
+ children: "CV"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('cds'),
+ children: "CDS"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-sec",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('sec'),
+ children: "SEC"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-sec",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('gc'),
+ children: "GC"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ id: "btn-sod",
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('aif'),
+ children: "SORPTION-DESORPTION"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('emissions'),
+ children: "EMISSIONS"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('dls acf'),
+ children: "DLS ACF"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('dls intensity'),
+ children: "DLS intensity"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('ms'),
+ children: "MS"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('multi'),
+ children: "Multi NMR"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('multi ir'),
+ children: "Multi IR"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('multi hplc'),
+ children: "Multi HPLC"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
+ variant: "contained",
+ style: {
+ margin: '0 10px 0 10px'
+ },
+ onClick: this.onClick('multi xrd'),
+ children: "Multi XRD"
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_app.SpectraEditor, {
+ entity: entity,
+ multiEntities: multiEntities,
+ others: others,
+ editorOnly: false,
+ descriptions: desc,
+ canChangeDescription: true,
+ onDescriptionChanged: this.onDescriptionChanged,
+ molSvg: molSvg,
+ exactMass: '123.0',
+ userManualLink: {
+ cv: "https://www.chemotion.net/chemotionsaurus/docs/eln/chemspectra/cvanalysis"
+ },
+ forecast: forecast,
+ operations: operations
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
+ children: "Description Changed"
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactQuill.default, {
+ className: 'card-sv-quill',
+ value: this.state.descChanged,
+ modules: {
+ toolbar: false
+ },
+ readOnly: true
+ })]
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ container: true,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
+ item: true,
+ xs: 10,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputBase, {
+ style: {
+ margin: '0 0 0 63px'
+ },
+ placeholder: "Description",
+ multiline: true,
+ fullWidth: true,
+ rows: "2",
+ margin: "dense",
+ value: desc
+ })
+ })
+ })]
+ });
+ }
+}
+
+// - - - DOM - - -
+_reactDom.default.render(/*#__PURE__*/(0, _jsxRuntime.jsx)(DemoWriteIr, {}), document.getElementById('root'));
\ No newline at end of file
diff --git a/dist/layer_content.js b/dist/layer_content.js
new file mode 100644
index 00000000..56a2fb51
--- /dev/null
+++ b/dist/layer_content.js
@@ -0,0 +1,104 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _index = _interopRequireDefault(require("./components/d3_line/index"));
+var _index2 = _interopRequireDefault(require("./components/d3_rect/index"));
+var _forecast_viewer = _interopRequireDefault(require("./components/forecast_viewer"));
+var _format = _interopRequireDefault(require("./helpers/format"));
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, default-param-last, react/function-component-definition */
+
+const extractLayout = (forecast, layoutSt) => {
+ const isEmpty = Object.keys(forecast).length === 0 && forecast.constructor === Object;
+ const isNmr = _format.default.isNmrLayout(layoutSt);
+ const isMs = _format.default.isMsLayout(layoutSt);
+ const isIr = _format.default.isIrLayout(layoutSt);
+ const isUvvis = _format.default.isUvVisLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt);
+ const isXRD = _format.default.isXRDLayout(layoutSt);
+ const showForecast = !isEmpty && (isNmr || isIr || isUvvis || isXRD);
+ return {
+ showForecast,
+ isNmr,
+ isIr,
+ isMs,
+ isUvvis,
+ isXRD
+ };
+};
+const Content = ({
+ topic,
+ feature,
+ cLabel,
+ xLabel,
+ yLabel,
+ forecast,
+ operations,
+ layoutSt
+}) => {
+ const {
+ showForecast,
+ isNmr,
+ isIr,
+ isMs,
+ isUvvis,
+ isXRD
+ } = extractLayout(forecast, layoutSt);
+ if (showForecast) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_forecast_viewer.default, {
+ topic: topic,
+ cLabel: cLabel,
+ xLabel: xLabel,
+ yLabel: yLabel,
+ feature: feature,
+ forecast: forecast,
+ isNmr: isNmr,
+ isIr: isIr,
+ isUvvis: isUvvis,
+ isXRD: isXRD,
+ operations: operations
+ });
+ }
+ if (isMs) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.default, {
+ topic: topic,
+ cLabel: cLabel,
+ xLabel: xLabel,
+ yLabel: yLabel,
+ feature: feature,
+ isHidden: false
+ });
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.default, {
+ topic: topic,
+ cLabel: cLabel,
+ xLabel: xLabel,
+ yLabel: yLabel,
+ feature: feature,
+ isHidden: false
+ });
+};
+const mapStateToProps = (state, _) => (
+// eslint-disable-line
+{
+ layoutSt: state.layout
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+Content.propTypes = {
+ topic: _propTypes.default.object.isRequired,
+ feature: _propTypes.default.object.isRequired,
+ cLabel: _propTypes.default.string.isRequired,
+ xLabel: _propTypes.default.string.isRequired,
+ yLabel: _propTypes.default.string.isRequired,
+ forecast: _propTypes.default.object.isRequired,
+ operations: _propTypes.default.array.isRequired,
+ layoutSt: _propTypes.default.string.isRequired
+};
+var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps))(Content);
\ No newline at end of file
diff --git a/dist/layer_init.js b/dist/layer_init.js
new file mode 100644
index 00000000..3df80431
--- /dev/null
+++ b/dist/layer_init.js
@@ -0,0 +1,256 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _styles = require("@mui/styles");
+var _submit = require("./actions/submit");
+var _manager = require("./actions/manager");
+var _meta = require("./actions/meta");
+var _jcamp = require("./actions/jcamp");
+var _layer_prism = _interopRequireDefault(require("./layer_prism"));
+var _format = _interopRequireDefault(require("./helpers/format"));
+var _multi_jcamps_viewer = _interopRequireDefault(require("./components/multi_jcamps_viewer"));
+var _curve = require("./actions/curve");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const styles = () => ({});
+class LayerInit extends _react.default.Component {
+ constructor(props) {
+ super(props);
+ this.normChange = this.normChange.bind(this);
+ this.execReset = this.execReset.bind(this);
+ this.initReducer = this.initReducer.bind(this);
+ this.updateOthers = this.updateOthers.bind(this);
+ this.updateMultiEntities = this.updateMultiEntities.bind(this);
+ }
+ componentDidMount() {
+ this.execReset();
+ this.initReducer();
+ this.updateOthers();
+ this.updateMultiEntities();
+ }
+ componentDidUpdate(prevProps) {
+ this.normChange(prevProps);
+ this.updateOthers();
+ this.updateMultiEntities();
+ }
+ normChange(prevProps) {
+ const {
+ entity
+ } = this.props;
+ if (prevProps.entity !== entity) {
+ this.execReset();
+ }
+ }
+ execReset() {
+ const {
+ entity,
+ updateMetaPeaksAct,
+ resetInitCommonAct,
+ resetInitMsAct,
+ resetInitNmrAct,
+ resetInitCommonWithIntergationAct,
+ resetDetectorAct,
+ updateDSCMetaDataAct,
+ resetMultiplicityAct
+ } = this.props;
+ resetInitCommonAct();
+ resetDetectorAct();
+ const {
+ layout,
+ features
+ } = entity;
+ if (_format.default.isMsLayout(layout)) {
+ // const { autoPeak, editPeak } = features; // TBD
+ const autoPeak = features.autoPeak || features[0];
+ const editPeak = features.editPeak || features[0];
+ const baseFeat = editPeak || autoPeak;
+ resetInitMsAct(baseFeat);
+ } else if (_format.default.isNmrLayout(layout)) {
+ const {
+ integration,
+ multiplicity,
+ simulation
+ } = features;
+ updateMetaPeaksAct(entity);
+ resetInitNmrAct({
+ integration,
+ multiplicity,
+ simulation
+ });
+ } else if (_format.default.isHplcUvVisLayout(layout)) {
+ const {
+ integration
+ } = features;
+ updateMetaPeaksAct(entity);
+ resetInitCommonWithIntergationAct({
+ integration
+ });
+ } else if (_format.default.isDSCLayout(layout)) {
+ const {
+ dscMetaData
+ } = features;
+ updateDSCMetaDataAct(dscMetaData);
+ } else {
+ resetMultiplicityAct();
+ }
+ }
+ initReducer() {
+ const {
+ operations,
+ updateOperationAct
+ } = this.props;
+ updateOperationAct(operations[0]);
+ }
+ updateOthers() {
+ const {
+ others,
+ addOthersAct
+ } = this.props;
+ addOthersAct(others);
+ }
+ updateMultiEntities() {
+ const {
+ multiEntities,
+ setAllCurvesAct,
+ entity
+ } = this.props;
+ const isMultiSpectra = Array.isArray(multiEntities) && multiEntities.length > 1;
+ if (isMultiSpectra) {
+ setAllCurvesAct(multiEntities);
+ return;
+ }
+ if (_format.default.isCyclicVoltaLayout(entity.layout)) {
+ const payload = Array.isArray(multiEntities) && multiEntities.length > 0 ? multiEntities : [entity];
+ setAllCurvesAct(payload);
+ return;
+ }
+ setAllCurvesAct(false);
+ }
+ render() {
+ const {
+ entity,
+ cLabel,
+ xLabel,
+ yLabel,
+ forecast,
+ operations,
+ descriptions,
+ molSvg,
+ editorOnly,
+ exactMass,
+ canChangeDescription,
+ onDescriptionChanged,
+ multiEntities,
+ entityFileNames,
+ userManualLink
+ } = this.props;
+ const target = entity.spectra[0];
+ const {
+ layout
+ } = entity;
+ const xxLabel = !xLabel && xLabel === '' ? `X (${target.xUnit})` : xLabel;
+ const yyLabel = !yLabel && yLabel === '' ? `Y (${target.yUnit})` : yLabel;
+ const isMultiSpectra = Array.isArray(multiEntities) && multiEntities.length > 1;
+ if (isMultiSpectra) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_multi_jcamps_viewer.default, {
+ multiEntities: multiEntities,
+ entityFileNames: entityFileNames,
+ userManualLink: userManualLink,
+ molSvg: molSvg,
+ exactMass: exactMass,
+ operations: operations,
+ descriptions: descriptions,
+ canChangeDescription: canChangeDescription,
+ onDescriptionChanged: onDescriptionChanged
+ });
+ } else if (_format.default.isCyclicVoltaLayout(layout)) {
+ // eslint-disable-line
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_multi_jcamps_viewer.default, {
+ multiEntities: [entity],
+ entityFileNames: entityFileNames,
+ userManualLink: userManualLink,
+ molSvg: molSvg,
+ exactMass: exactMass,
+ operations: operations,
+ descriptions: descriptions,
+ canChangeDescription: canChangeDescription,
+ onDescriptionChanged: onDescriptionChanged
+ });
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_prism.default, {
+ entity: entity,
+ cLabel: cLabel,
+ xLabel: xxLabel,
+ yLabel: yyLabel,
+ forecast: forecast,
+ operations: operations,
+ descriptions: descriptions,
+ molSvg: molSvg,
+ editorOnly: editorOnly,
+ exactMass: exactMass,
+ canChangeDescription: canChangeDescription,
+ onDescriptionChanged: onDescriptionChanged
+ });
+ }
+}
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({
+ resetInitCommonAct: _manager.resetInitCommon,
+ resetInitNmrAct: _manager.resetInitNmr,
+ resetInitMsAct: _manager.resetInitMs,
+ resetInitCommonWithIntergationAct: _manager.resetInitCommonWithIntergation,
+ resetDetectorAct: _manager.resetDetector,
+ resetMultiplicityAct: _manager.resetMultiplicity,
+ updateOperationAct: _submit.updateOperation,
+ updateMetaPeaksAct: _meta.updateMetaPeaks,
+ addOthersAct: _jcamp.addOthers,
+ setAllCurvesAct: _curve.setAllCurves,
+ updateDSCMetaDataAct: _meta.updateDSCMetaData
+}, dispatch);
+LayerInit.propTypes = {
+ entity: _propTypes.default.object.isRequired,
+ multiEntities: _propTypes.default.array,
+ // eslint-disable-line
+ entityFileNames: _propTypes.default.array,
+ // eslint-disable-line
+ others: _propTypes.default.object.isRequired,
+ cLabel: _propTypes.default.string.isRequired,
+ xLabel: _propTypes.default.string.isRequired,
+ yLabel: _propTypes.default.string.isRequired,
+ molSvg: _propTypes.default.string.isRequired,
+ editorOnly: _propTypes.default.bool.isRequired,
+ exactMass: _propTypes.default.string.isRequired,
+ forecast: _propTypes.default.object.isRequired,
+ operations: _propTypes.default.array.isRequired,
+ descriptions: _propTypes.default.array.isRequired,
+ resetInitCommonAct: _propTypes.default.func.isRequired,
+ resetInitNmrAct: _propTypes.default.func.isRequired,
+ resetInitMsAct: _propTypes.default.func.isRequired,
+ resetInitCommonWithIntergationAct: _propTypes.default.func.isRequired,
+ updateOperationAct: _propTypes.default.func.isRequired,
+ updateMetaPeaksAct: _propTypes.default.func.isRequired,
+ addOthersAct: _propTypes.default.func.isRequired,
+ canChangeDescription: _propTypes.default.bool.isRequired,
+ onDescriptionChanged: _propTypes.default.func,
+ // eslint-disable-line
+ setAllCurvesAct: _propTypes.default.func.isRequired,
+ userManualLink: _propTypes.default.object,
+ // eslint-disable-line
+ resetDetectorAct: _propTypes.default.func.isRequired,
+ resetMultiplicityAct: _propTypes.default.func.isRequired,
+ updateDSCMetaDataAct: _propTypes.default.func.isRequired
+};
+var _default = exports.default = (0, _reactRedux.connect)(
+// eslint-disable-line
+mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(LayerInit)); // eslint-disable-line
\ No newline at end of file
diff --git a/dist/layer_prism.js b/dist/layer_prism.js
new file mode 100644
index 00000000..7680524a
--- /dev/null
+++ b/dist/layer_prism.js
@@ -0,0 +1,150 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _react = _interopRequireDefault(require("react"));
+var _propTypes = _interopRequireDefault(require("prop-types"));
+var _reactRedux = require("react-redux");
+var _redux = require("redux");
+var _Grid = _interopRequireDefault(require("@mui/material/Grid"));
+var _styles = require("@mui/styles");
+var _index = _interopRequireDefault(require("./components/panel/index"));
+var _index2 = _interopRequireDefault(require("./components/cmd_bar/index"));
+var _layer_content = _interopRequireDefault(require("./layer_content"));
+var _list_ui = require("./constants/list_ui");
+var _extractParams = require("./helpers/extractParams");
+var _jsxRuntime = require("react/jsx-runtime");
+/* eslint-disable prefer-object-spread, default-param-last,
+react/function-component-definition, react/require-default-props
+*/
+
+const styles = () => ({});
+const LayerPrism = ({
+ entity,
+ cLabel,
+ xLabel,
+ yLabel,
+ forecast,
+ operations,
+ descriptions,
+ molSvg,
+ editorOnly,
+ exactMass,
+ thresSt,
+ scanSt,
+ uiSt,
+ canChangeDescription,
+ onDescriptionChanged
+}) => {
+ const {
+ topic,
+ feature,
+ hasEdit,
+ integration
+ } = (0, _extractParams.extractParams)(entity, thresSt, scanSt);
+ if (!topic) return null;
+ const {
+ viewer
+ } = uiSt;
+ if (viewer === _list_ui.LIST_UI_VIEWER_TYPE.ANALYSIS) {
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.default, {
+ feature: feature,
+ hasEdit: hasEdit,
+ forecast: forecast,
+ operations: operations,
+ editorOnly: editorOnly
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: "react-spectrum-editor",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Grid.default, {
+ container: true,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Grid.default, {
+ item: true,
+ xs: 12,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_content.default, {
+ topic: topic,
+ feature: feature,
+ cLabel: cLabel,
+ xLabel: xLabel,
+ yLabel: yLabel,
+ forecast: forecast,
+ operations: operations
+ })
+ })
+ })
+ })]
+ });
+ }
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.default, {
+ feature: feature,
+ hasEdit: hasEdit,
+ forecast: forecast,
+ operations: operations,
+ editorOnly: editorOnly
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
+ className: "react-spectrum-editor",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Grid.default, {
+ container: true,
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Grid.default, {
+ item: true,
+ xs: 9,
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_content.default, {
+ topic: topic,
+ feature: feature,
+ cLabel: cLabel,
+ xLabel: xLabel,
+ yLabel: yLabel,
+ forecast: forecast,
+ operations: operations
+ })
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Grid.default, {
+ item: true,
+ xs: 3,
+ align: "center",
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.default, {
+ feature: feature,
+ integration: integration,
+ editorOnly: editorOnly,
+ molSvg: molSvg,
+ exactMass: exactMass,
+ descriptions: descriptions,
+ canChangeDescription: canChangeDescription,
+ onDescriptionChanged: onDescriptionChanged
+ })
+ })]
+ })
+ })]
+ });
+};
+const mapStateToProps = (state, props) => (
+// eslint-disable-line
+{
+ scanSt: state.scan,
+ thresSt: state.threshold.list[state.curve.curveIdx],
+ uiSt: state.ui
+});
+const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch);
+LayerPrism.propTypes = {
+ entity: _propTypes.default.object.isRequired,
+ cLabel: _propTypes.default.string.isRequired,
+ xLabel: _propTypes.default.string.isRequired,
+ yLabel: _propTypes.default.string.isRequired,
+ molSvg: _propTypes.default.string.isRequired,
+ editorOnly: _propTypes.default.bool.isRequired,
+ exactMass: _propTypes.default.string,
+ forecast: _propTypes.default.object.isRequired,
+ operations: _propTypes.default.array.isRequired,
+ descriptions: _propTypes.default.array.isRequired,
+ thresSt: _propTypes.default.object.isRequired,
+ scanSt: _propTypes.default.object.isRequired,
+ uiSt: _propTypes.default.object.isRequired,
+ canChangeDescription: _propTypes.default.bool.isRequired,
+ onDescriptionChanged: _propTypes.default.func
+};
+var _default = exports.default = (0, _reactRedux.connect)(
+// eslint-disable-line
+mapStateToProps, mapDispatchToProps)((0, _styles.withStyles)(styles)(LayerPrism)); // eslint-disable-line
\ No newline at end of file
diff --git a/dist/reducers/index.js b/dist/reducers/index.js
new file mode 100644
index 00000000..50868a3b
--- /dev/null
+++ b/dist/reducers/index.js
@@ -0,0 +1,51 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _redux = require("redux");
+var _reducer_threshold = _interopRequireDefault(require("./reducer_threshold"));
+var _reducer_edit_peak = _interopRequireDefault(require("./reducer_edit_peak"));
+var _reducer_status = _interopRequireDefault(require("./reducer_status"));
+var _reducer_manager = _interopRequireDefault(require("./reducer_manager"));
+var _reducer_layout = _interopRequireDefault(require("./reducer_layout"));
+var _reducer_shift = _interopRequireDefault(require("./reducer_shift"));
+var _reducer_scan = _interopRequireDefault(require("./reducer_scan"));
+var _reducer_forecast = _interopRequireDefault(require("./reducer_forecast"));
+var _reducer_ui = _interopRequireDefault(require("./reducer_ui"));
+var _reducer_submit = _interopRequireDefault(require("./reducer_submit"));
+var _reducer_integration = _interopRequireDefault(require("./reducer_integration"));
+var _reducer_multiplicity = _interopRequireDefault(require("./reducer_multiplicity"));
+var _reducer_simulation = _interopRequireDefault(require("./reducer_simulation"));
+var _reducer_meta = _interopRequireDefault(require("./reducer_meta"));
+var _reducer_jcamp = _interopRequireDefault(require("./reducer_jcamp"));
+var _reducer_wavelength = _interopRequireDefault(require("./reducer_wavelength"));
+var _reducer_voltammetry = _interopRequireDefault(require("./reducer_voltammetry"));
+var _reducer_curve = _interopRequireDefault(require("./reducer_curve"));
+var _reducer_axes = _interopRequireDefault(require("./reducer_axes"));
+var _reducer_detector = _interopRequireDefault(require("./reducer_detector"));
+const rootReducer = (0, _redux.combineReducers)({
+ threshold: _reducer_threshold.default,
+ editPeak: _reducer_edit_peak.default,
+ status: _reducer_status.default,
+ manager: _reducer_manager.default,
+ layout: _reducer_layout.default,
+ shift: _reducer_shift.default,
+ scan: _reducer_scan.default,
+ forecast: _reducer_forecast.default,
+ ui: _reducer_ui.default,
+ submit: _reducer_submit.default,
+ integration: _reducer_integration.default,
+ multiplicity: _reducer_multiplicity.default,
+ simulation: _reducer_simulation.default,
+ meta: _reducer_meta.default,
+ jcamp: _reducer_jcamp.default,
+ wavelength: _reducer_wavelength.default,
+ cyclicvolta: _reducer_voltammetry.default,
+ curve: _reducer_curve.default,
+ axesUnits: _reducer_axes.default,
+ detector: _reducer_detector.default
+});
+var _default = exports.default = rootReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_axes.js b/dist/reducers/reducer_axes.js
new file mode 100644
index 00000000..b9544a85
--- /dev/null
+++ b/dist/reducers/reducer_axes.js
@@ -0,0 +1,56 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable default-param-last, prefer-object-spread */
+
+const initialState = {
+ axes: [{
+ xUnit: '',
+ yUnit: ''
+ }]
+};
+const updateAxis = (state, payload, isYAxis = false) => {
+ const {
+ value,
+ curveIndex
+ } = payload;
+ const {
+ axes
+ } = state;
+ let selectedAxes = axes[curveIndex];
+ if (!selectedAxes) {
+ selectedAxes = {
+ xUnit: '',
+ yUnit: ''
+ };
+ }
+ let newAxes = null;
+ if (isYAxis) {
+ newAxes = Object.assign({}, selectedAxes, {
+ yUnit: value
+ });
+ } else {
+ newAxes = Object.assign({}, selectedAxes, {
+ xUnit: value
+ });
+ }
+ axes[curveIndex] = newAxes;
+ return Object.assign({}, state, {
+ axes
+ });
+};
+const axesReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.AXES.UPDATE_X_AXIS:
+ return updateAxis(state, action.payload);
+ case _action_type.AXES.UPDATE_Y_AXIS:
+ return updateAxis(state, action.payload, true);
+ default:
+ return state;
+ }
+};
+var _default = exports.default = axesReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_curve.js b/dist/reducers/reducer_curve.js
new file mode 100644
index 00000000..91c11de1
--- /dev/null
+++ b/dist/reducers/reducer_curve.js
@@ -0,0 +1,78 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+var _extractParams = require("../helpers/extractParams");
+var _chem = require("../helpers/chem");
+var _format = _interopRequireDefault(require("../helpers/format"));
+/* eslint-disable prefer-object-spread, default-param-last, max-len */
+
+const initialState = {
+ listCurves: [],
+ curveIdx: 0,
+ isShowAllCurve: false
+};
+const setAllCurves = (state, action) => {
+ const {
+ payload
+ } = action;
+ if (payload) {
+ const entities = payload.map((entity, idx) => {
+ const {
+ topic,
+ feature,
+ hasEdit,
+ integration,
+ multiplicity
+ } = (0, _extractParams.extractParams)(entity, {
+ isEdit: true
+ });
+ // const layout = entity.layout;
+ const {
+ layout
+ } = entity;
+ const maxminPeak = (0, _chem.Convert2MaxMinPeak)(layout, feature, 0);
+ const color = _format.default.mutiEntitiesColors(idx);
+ return {
+ layout,
+ topic,
+ feature,
+ hasEdit,
+ integration,
+ multiplicity,
+ maxminPeak,
+ color,
+ curveIdx: idx
+ };
+ });
+ return Object.assign({}, state, {
+ curveIdx: 0,
+ listCurves: entities
+ });
+ }
+ return Object.assign({}, state, {
+ curveIdx: 0,
+ listCurves: payload
+ });
+};
+const curveReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.CURVE.SELECT_WORKING_CURVE:
+ return Object.assign({}, state, {
+ curveIdx: action.payload
+ });
+ case _action_type.CURVE.SET_ALL_CURVES:
+ return setAllCurves(state, action);
+ case _action_type.CURVE.SET_SHOULD_SHOW_ALL_CURVES:
+ return Object.assign({}, state, {
+ isShowAllCurve: action.payload
+ });
+ default:
+ return state;
+ }
+};
+var _default = exports.default = curveReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_detector.js b/dist/reducers/reducer_detector.js
new file mode 100644
index 00000000..203cf350
--- /dev/null
+++ b/dist/reducers/reducer_detector.js
@@ -0,0 +1,50 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable no-case-declarations */
+/* eslint-disable default-param-last */
+
+const initialState = {
+ curves: [{
+ curveIdx: 0,
+ selectedDetector: ''
+ }]
+};
+const findCurveIndex = (curves, targetCurveIdx) => curves.findIndex(curve => curve.curveIdx === targetCurveIdx);
+const updateOrAppendCurve = (curves, targetCurveIdx, newCurve) => {
+ const existingCurveIndex = findCurveIndex(curves, targetCurveIdx);
+ if (existingCurveIndex !== -1) {
+ return curves.map((curve, index) => index === existingCurveIndex ? {
+ ...curve,
+ ...newCurve
+ } : curve);
+ }
+ return [...curves, newCurve];
+};
+const detectorReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.SEC.UPDATE_DETECTOR:
+ const {
+ curveIdx,
+ selectedDetector
+ } = action.payload;
+ // eslint-disable-next-line max-len
+ const updatedCurves = updateOrAppendCurve(state.curves, curveIdx, {
+ curveIdx,
+ selectedDetector
+ });
+ return {
+ ...state,
+ curves: updatedCurves
+ };
+ case _action_type.MANAGER.RESET_DETECTOR:
+ return initialState;
+ default:
+ return state;
+ }
+};
+var _default = exports.default = detectorReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_edit_peak.js b/dist/reducers/reducer_edit_peak.js
new file mode 100644
index 00000000..35d38bff
--- /dev/null
+++ b/dist/reducers/reducer_edit_peak.js
@@ -0,0 +1,234 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.editPeakReducer = exports.default = void 0;
+var _reduxUndo = _interopRequireDefault(require("redux-undo"));
+var _action_type = require("../constants/action_type");
+var _undo_redo_config = require("./undo_redo_config");
+var _calc = require("../helpers/calc");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ selectedIdx: 0,
+ peaks: [{
+ prevOffset: 0,
+ pos: [],
+ neg: []
+ }]
+};
+const defaultEmptyPeaks = {
+ prevOffset: 0,
+ pos: [],
+ neg: []
+};
+const addToPos = (state, action) => {
+ const {
+ peaks
+ } = state;
+ const {
+ payload
+ } = action;
+ const {
+ dataToAdd,
+ curveIdx
+ } = payload;
+ let selectedEditPeaks = peaks[curveIdx];
+ if (!selectedEditPeaks) {
+ selectedEditPeaks = defaultEmptyPeaks;
+ }
+ const oriPosState = selectedEditPeaks.pos;
+ const oriNegState = selectedEditPeaks.neg;
+ const idxN = oriNegState.findIndex(n => (0, _calc.almostEqual)(n.x, dataToAdd.x));
+ if (idxN >= 0) {
+ // rm the peak from oriNegState if it is already deleted.
+ const neg = [...oriNegState.slice(0, idxN), ...oriNegState.slice(idxN + 1)];
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ neg
+ });
+ const newPeaks = [...peaks];
+ newPeaks[curveIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks
+ });
+ }
+ const idxP = oriPosState.findIndex(p => (0, _calc.almostEqual)(p.x, dataToAdd.x));
+ if (idxP < 0) {
+ // add the peak
+ const pos = [...oriPosState, dataToAdd];
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ pos
+ });
+ const newPeaks = [...peaks];
+ newPeaks[curveIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks,
+ selectedIdx: curveIdx
+ });
+ }
+ return state;
+};
+const rmFromPos = (state, action) => {
+ const {
+ selectedIdx,
+ peaks
+ } = state;
+ const selectedEditPeaks = peaks[selectedIdx];
+ const oriPosState = selectedEditPeaks.pos;
+ const idx = oriPosState.findIndex(p => p.x === action.payload.x);
+ const pos = [...oriPosState.slice(0, idx), ...oriPosState.slice(idx + 1)];
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ pos
+ });
+ const newPeaks = [...peaks];
+ newPeaks[selectedIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks
+ });
+};
+const addToNeg = (state, action) => {
+ const {
+ peaks
+ } = state;
+ const {
+ payload
+ } = action;
+ const {
+ dataToAdd,
+ curveIdx
+ } = payload;
+ let selectedEditPeaks = peaks[curveIdx];
+ if (!selectedEditPeaks) {
+ selectedEditPeaks = defaultEmptyPeaks;
+ }
+ const oriPosState = selectedEditPeaks.pos;
+ const oriNegState = selectedEditPeaks.neg;
+ const idxP = oriPosState.findIndex(n => n.x === dataToAdd.x);
+ if (idxP >= 0) {
+ const pos = [...oriPosState.slice(0, idxP), ...oriPosState.slice(idxP + 1)];
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ pos
+ });
+ const newPeaks = [...peaks];
+ newPeaks[curveIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks
+ });
+ }
+ const idxN = oriNegState.findIndex(n => n.x === dataToAdd.x);
+ if (idxN < 0) {
+ const neg = [...oriNegState, dataToAdd];
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ neg
+ });
+ const newPeaks = [...peaks];
+ newPeaks[curveIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks,
+ selectedIdx: curveIdx
+ });
+ }
+ return state;
+};
+const rmFromNeg = (state, action) => {
+ const {
+ selectedIdx,
+ peaks
+ } = state;
+ const selectedEditPeaks = peaks[selectedIdx];
+ const oriNegState = selectedEditPeaks.neg;
+ const idx = oriNegState.findIndex(n => n.x === action.payload.x);
+ const neg = [...oriNegState.slice(0, idx), ...oriNegState.slice(idx + 1)];
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ neg
+ });
+ const newPeaks = [...peaks];
+ newPeaks[selectedIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks
+ });
+};
+const processShift = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ curveIdx
+ } = action.payload;
+ const {
+ peaks
+ } = state;
+ let selectedEditPeaks = peaks[curveIdx];
+ if (!selectedEditPeaks) {
+ selectedEditPeaks = defaultEmptyPeaks;
+ }
+ const {
+ pos,
+ neg,
+ prevOffset
+ } = payload;
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ pos,
+ neg,
+ prevOffset
+ });
+ const newPeaks = [...peaks];
+ newPeaks[curveIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks
+ });
+};
+const clearAllPeaks = (state, action) => {
+ const {
+ curveIdx,
+ dataPeaks
+ } = action.payload;
+ const {
+ peaks
+ } = state;
+ const selectedEditPeaks = peaks[curveIdx];
+ const {
+ pos
+ } = selectedEditPeaks;
+ const newSelectedEditPeaks = Object.assign({}, selectedEditPeaks, {
+ pos: [],
+ neg: [...pos, ...dataPeaks]
+ });
+ const newPeaks = [...peaks];
+ newPeaks[curveIdx] = newSelectedEditPeaks;
+ return Object.assign({}, state, {
+ peaks: newPeaks
+ });
+};
+const editPeakReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.EDITPEAK.ADD_POSITIVE:
+ return addToPos(state, action);
+ case _action_type.EDITPEAK.ADD_NEGATIVE:
+ return addToNeg(state, action);
+ case _action_type.EDITPEAK.RM_POSITIVE:
+ return rmFromPos(state, action);
+ case _action_type.EDITPEAK.RM_NEGATIVE:
+ return rmFromNeg(state, action);
+ case _action_type.EDITPEAK.SHIFT:
+ return processShift(state, action);
+ case _action_type.EDITPEAK.CLEAR_ALL:
+ return clearAllPeaks(state, action);
+ case _action_type.MANAGER.RESETALL:
+ return {
+ selectedIdx: 0,
+ peaks: [{
+ prevOffset: 0,
+ pos: [],
+ neg: []
+ }]
+ };
+ default:
+ return _undo_redo_config.undoRedoActions.indexOf(action.type) >= 0 ? Object.assign({}, state) : state;
+ }
+};
+exports.editPeakReducer = editPeakReducer;
+const undoableEditPeakReducer = (0, _reduxUndo.default)(editPeakReducer, _undo_redo_config.undoRedoConfig);
+var _default = exports.default = undoableEditPeakReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_forecast.js b/dist/reducers/reducer_forecast.js
new file mode 100644
index 00000000..7dcb6c05
--- /dev/null
+++ b/dist/reducers/reducer_forecast.js
@@ -0,0 +1,120 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ predictions: {
+ outline: {},
+ output: {
+ result: []
+ }
+ }
+};
+const updateIrResl = (stResl, plPred) => {
+ const {
+ sma,
+ identity,
+ value
+ } = plPred;
+ const {
+ svgs
+ } = stResl;
+ const prevFgs = stResl.fgs;
+ const nextVal = {
+ [`status${identity}`]: value
+ };
+ const nextFgs = prevFgs.map(fg => {
+ if (fg.sma === sma) {
+ return Object.assign({}, fg, nextVal);
+ }
+ return fg;
+ });
+ const nextResult = {
+ type: 'ir',
+ fgs: nextFgs,
+ svgs
+ };
+ return nextResult;
+};
+const updateIrStatus = (state, action) => {
+ const {
+ predictions
+ } = action.payload;
+ const {
+ outline,
+ output
+ } = state.predictions;
+ const stResl = output.result[0];
+ const nextResl = updateIrResl(stResl, predictions);
+ return Object.assign({}, state, {
+ predictions: {
+ outline,
+ output: {
+ result: [nextResl]
+ }
+ }
+ });
+};
+const updateNmrResl = (stResl, plPred) => {
+ const {
+ idx,
+ atom,
+ identity,
+ value
+ } = plPred;
+ const preResult = stResl;
+ const nextShifts = preResult.shifts.map((s, index) => {
+ if (s.atom === atom && index === idx) {
+ return Object.assign({}, s, {
+ [`status${identity}`]: value
+ });
+ }
+ return s;
+ });
+ const nextResult = Object.assign({}, preResult, {
+ shifts: nextShifts
+ });
+ return nextResult;
+};
+const updateNmrStatus = (state, action) => {
+ const {
+ predictions
+ } = action.payload;
+ const {
+ outline,
+ output
+ } = state.predictions;
+ const stResl = output.result[0];
+ const nextResl = updateNmrResl(stResl, predictions);
+ const newSt = Object.assign({}, state, {
+ predictions: {
+ outline,
+ output: {
+ result: [nextResl]
+ }
+ }
+ });
+ return newSt;
+};
+const forecastReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.FORECAST.INIT_STATUS:
+ if (!action.payload) return state;
+ return Object.assign({}, action.payload);
+ case _action_type.FORECAST.SET_IR_STATUS:
+ return updateIrStatus(state, action);
+ case _action_type.FORECAST.SET_NMR_STATUS:
+ return updateNmrStatus(state, action);
+ case _action_type.FORECAST.CLEAR_STATUS:
+ case _action_type.MANAGER.RESETALL:
+ return initialState;
+ default:
+ return state;
+ }
+};
+var _default = exports.default = forecastReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_integration.js b/dist/reducers/reducer_integration.js
new file mode 100644
index 00000000..ce3daefe
--- /dev/null
+++ b/dist/reducers/reducer_integration.js
@@ -0,0 +1,298 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.integrationReducer = exports.default = void 0;
+var _reduxUndo = _interopRequireDefault(require("redux-undo"));
+var _action_type = require("../constants/action_type");
+var _integration = require("../helpers/integration");
+var _undo_redo_config = require("./undo_redo_config");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [],
+ refArea: 1,
+ refFactor: 1,
+ shift: 0,
+ edited: false
+ }]
+};
+const defaultEmptyIntegration = {
+ stack: [],
+ refArea: 1,
+ refFactor: 1,
+ shift: 0,
+ edited: false
+};
+const addToStack = (state, action) => {
+ const {
+ newData,
+ curveIdx
+ } = action.payload;
+ const {
+ integrations
+ } = state;
+ let selectedIntegration = integrations[curveIdx];
+ if (selectedIntegration === false || selectedIntegration === undefined) {
+ selectedIntegration = defaultEmptyIntegration;
+ }
+ const {
+ stack,
+ refArea,
+ shift
+ } = selectedIntegration;
+ const {
+ xExtent,
+ data
+ } = newData;
+ const {
+ xL,
+ xU
+ } = xExtent;
+ if (!Number.isFinite(xL) || !Number.isFinite(xU) || xU - xL === 0) {
+ return state;
+ }
+ const area = (0, _integration.getArea)(xL, xU, data);
+ const defaultRefArea = stack.length === 0 ? area : refArea;
+ const absoluteArea = (0, _integration.getAbsoluteArea)(xL, xU, data); // area depends on y baseline
+ const newStack = [...stack, {
+ xL: xL + shift,
+ xU: xU + shift,
+ area,
+ absoluteArea
+ }];
+ const newIntegration = Object.assign({}, selectedIntegration, {
+ stack: newStack,
+ refArea: defaultRefArea
+ });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+ return Object.assign({}, state, {
+ integrations: newArrIntegration,
+ selectedIdx: curveIdx
+ });
+};
+const rmFromStack = (state, action) => {
+ const {
+ dataToRemove,
+ curveIdx
+ } = action.payload;
+ const {
+ xL,
+ xU,
+ xExtent
+ } = dataToRemove;
+ const {
+ integrations
+ } = state;
+ const selectedIntegration = integrations[curveIdx];
+ const {
+ stack
+ } = selectedIntegration;
+ let [txL, txU] = [0, 0];
+ if (Number.isFinite(xL) && Number.isFinite(xU)) {
+ [txL, txU] = [xL, xU];
+ } else if (xExtent) {
+ [txL, txU] = [xExtent.xL, xExtent.xU];
+ } else {
+ return state;
+ }
+ const newStack = stack.filter(k => k.xL !== txL && k.xU !== txU);
+ const newIntegration = Object.assign({}, selectedIntegration, {
+ stack: newStack
+ });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+ return Object.assign({}, state, {
+ integrations: newArrIntegration,
+ selectedIdx: curveIdx
+ });
+};
+const hasEnoughDataResolution = (xL, xU, data) => {
+ const [lower, upper] = [xL, xU].sort((a, b) => a - b);
+ const points = data.filter(pt => pt && Number.isFinite(pt.x) && pt.x >= lower && pt.x <= upper);
+ if (points.length < 2) return false;
+ return points.some(pt => pt.x !== points[0].x);
+};
+const buildSplitStackItem = (xL, xU, data, shift) => {
+ const [lower, upper] = [xL, xU].sort((a, b) => a - b);
+ const area = (0, _integration.getArea)(lower, upper, data);
+ const absoluteArea = (0, _integration.getAbsoluteArea)(lower, upper, data);
+ return {
+ xL: lower + shift,
+ xU: upper + shift,
+ area,
+ absoluteArea
+ };
+};
+const splitStack = (state, action) => {
+ const {
+ curveIdx,
+ target,
+ splitX,
+ data
+ } = action.payload;
+ if (!Number.isFinite(curveIdx) || !target || !Array.isArray(data)) {
+ return state;
+ }
+ const {
+ integrations
+ } = state;
+ const selectedIntegration = integrations[curveIdx];
+ if (!selectedIntegration || selectedIntegration === false) {
+ return state;
+ }
+ const {
+ stack,
+ shift
+ } = selectedIntegration;
+ const targetIndex = stack.findIndex(item => item.xL === target.xL && item.xU === target.xU);
+ if (targetIndex < 0 || !Number.isFinite(splitX)) {
+ return state;
+ }
+ const original = stack[targetIndex];
+ const [xL, xU] = [original.xL - shift, original.xU - shift].sort((a, b) => a - b);
+ if (!Number.isFinite(xL) || !Number.isFinite(xU) || splitX <= xL || splitX >= xU) {
+ return state;
+ }
+ if (!hasEnoughDataResolution(xL, splitX, data) || !hasEnoughDataResolution(splitX, xU, data)) {
+ return state;
+ }
+ const leftIntegration = buildSplitStackItem(xL, splitX, data, shift);
+ const rightIntegration = buildSplitStackItem(splitX, xU, data, shift);
+ const newStack = [...stack.slice(0, targetIndex), leftIntegration, rightIntegration, ...stack.slice(targetIndex + 1)];
+ const newIntegration = Object.assign({}, selectedIntegration, {
+ stack: newStack
+ });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+ return Object.assign({}, state, {
+ integrations: newArrIntegration,
+ selectedIdx: curveIdx
+ });
+};
+const setRef = (state, action) => {
+ const {
+ refData,
+ curveIdx
+ } = action.payload;
+ const {
+ integrations
+ } = state;
+ const selectedIntegration = integrations[curveIdx];
+ const {
+ stack
+ } = selectedIntegration;
+ const {
+ xL,
+ xU
+ } = refData;
+ const ref = stack.filter(k => k.xL === xL && k.xU === xU)[0];
+ if (!ref) {
+ return state;
+ }
+ const refArea = ref.area;
+ const newIntegration = Object.assign({}, selectedIntegration, {
+ refArea
+ });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+ return Object.assign({}, state, {
+ integrations: newArrIntegration,
+ selectedIdx: curveIdx
+ });
+};
+const setFkr = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ curveIdx,
+ factor
+ } = payload;
+ const {
+ integrations
+ } = state;
+ const selectedIntegration = integrations[curveIdx];
+ const val = parseFloat(factor);
+ const refFactor = val < 0.01 ? 0.01 : val;
+ const newIntegration = Object.assign({}, selectedIntegration, {
+ refFactor
+ });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+ return Object.assign({}, state, {
+ integrations: newArrIntegration
+ });
+};
+const setShift = (state, action) => {
+ const {
+ selectedIdx,
+ integrations
+ } = state;
+ const selectedIntegration = integrations[selectedIdx];
+ const shift = action.payload.prevOffset;
+ const newIntegration = Object.assign({}, selectedIntegration, {
+ shift
+ });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[selectedIdx] = newIntegration;
+ return Object.assign({}, state, {
+ integrations: newArrIntegration
+ });
+};
+const resetAll = (state, action) => {
+ const newState = action.payload;
+ return Object.assign({}, state, newState);
+};
+const clearAll = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ curveIdx
+ } = payload;
+ const {
+ integrations
+ } = state;
+ const newIntegration = Object.assign({}, defaultEmptyIntegration, {
+ edited: true
+ });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+ return Object.assign({}, state, {
+ integrations: newArrIntegration,
+ selectedIdx: curveIdx
+ });
+};
+const integrationReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.UI.SWEEP.SELECT_INTEGRATION:
+ return addToStack(state, action);
+ case _action_type.INTEGRATION.RM_ONE:
+ return rmFromStack(state, action);
+ case _action_type.INTEGRATION.SPLIT:
+ return splitStack(state, action);
+ case _action_type.INTEGRATION.SET_REF:
+ return setRef(state, action);
+ case _action_type.INTEGRATION.SET_FKR:
+ return setFkr(state, action);
+ case _action_type.INTEGRATION.RESET_ALL_RDC:
+ return resetAll(state, action);
+ case _action_type.INTEGRATION.CLEAR_ALL:
+ return clearAll(state, action);
+ case _action_type.EDITPEAK.SHIFT:
+ return setShift(state, action);
+ case _action_type.MANAGER.RESETALL:
+ return state;
+ default:
+ return _undo_redo_config.undoRedoActions.indexOf(action.type) >= 0 ? Object.assign({}, state) : state;
+ }
+};
+exports.integrationReducer = integrationReducer;
+const undoableIntegrationReducer = (0, _reduxUndo.default)(integrationReducer, _undo_redo_config.undoRedoConfig);
+var _default = exports.default = undoableIntegrationReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_jcamp.js b/dist/reducers/reducer_jcamp.js
new file mode 100644
index 00000000..6c18ec0f
--- /dev/null
+++ b/dist/reducers/reducer_jcamp.js
@@ -0,0 +1,99 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ selectedIdx: 0,
+ jcamps: [{
+ others: [],
+ addOthersCb: false
+ }]
+};
+const addOthers = (state, {
+ others,
+ addOthersCb
+}) => {
+ const {
+ selectedIdx,
+ jcamps
+ } = state;
+ const selectedJcamp = jcamps[selectedIdx];
+ if (selectedJcamp.others.length > 5) return state;
+ const decoOthers = others.map(o => Object.assign({}, o, {
+ show: true
+ }));
+ const newJcamp = Object.assign({}, selectedJcamp, {
+ others: [...decoOthers].slice(0, 5),
+ addOthersCb
+ });
+ jcamps[selectedIdx] = newJcamp;
+ return Object.assign({}, state, {
+ jcamps
+ });
+};
+const rmOthersOne = (state, payload) => {
+ const {
+ selectedIdx,
+ jcamps
+ } = state;
+ const selectedJcamp = jcamps[selectedIdx];
+ const idx = payload;
+ const {
+ others
+ } = selectedJcamp;
+ const nextOther = others.filter((_, i) => i !== idx);
+ const newJcamp = Object.assign({}, selectedJcamp, {
+ others: nextOther
+ });
+ jcamps[selectedIdx] = newJcamp;
+ return Object.assign({}, state, {
+ jcamps
+ });
+};
+const toggleShow = (state, payload) => {
+ const {
+ selectedIdx,
+ jcamps
+ } = state;
+ const selectedJcamp = jcamps[selectedIdx];
+ const idx = payload;
+ const {
+ others
+ } = selectedJcamp;
+ const nextOthers = others.map((o, i) => {
+ if (i !== idx) return o;
+ const currentShow = o.show;
+ return Object.assign({}, o, {
+ show: !currentShow
+ });
+ });
+ const newJcamp = Object.assign({}, selectedJcamp, {
+ others: nextOthers
+ });
+ jcamps[selectedIdx] = newJcamp;
+ return Object.assign({}, state, {
+ jcamps
+ });
+};
+const layoutReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.JCAMP.ADD_OTHERS:
+ return addOthers(state, action.payload);
+ case _action_type.JCAMP.RM_OTHERS_ONE:
+ return rmOthersOne(state, action.payload);
+ case _action_type.JCAMP.TOGGLE_SHOW:
+ return toggleShow(state, action.payload);
+ case _action_type.JCAMP.CLEAR_ALL:
+ return initialState;
+ case _action_type.MANAGER.RESETALL:
+ return initialState;
+ default:
+ return state;
+ }
+};
+var _default = exports.default = layoutReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_layout.js b/dist/reducers/reducer_layout.js
new file mode 100644
index 00000000..c264e570
--- /dev/null
+++ b/dist/reducers/reducer_layout.js
@@ -0,0 +1,22 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+var _list_layout = require("../constants/list_layout");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = _list_layout.LIST_LAYOUT.C13;
+const layoutReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.LAYOUT.UPDATE:
+ return action.payload;
+ case _action_type.MANAGER.RESETALL:
+ return action.payload.operation.layout;
+ default:
+ return state;
+ }
+};
+var _default = exports.default = layoutReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_manager.js b/dist/reducers/reducer_manager.js
new file mode 100644
index 00000000..2de439dd
--- /dev/null
+++ b/dist/reducers/reducer_manager.js
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+/* eslint-disable prefer-object-spread, default-param-last */
+// import { MANAGER } from '../constants/action_type';
+
+const initialState = {};
+const managerReducer = (state = initialState, action) => {
+ switch (action.type) {
+ default:
+ return state;
+ }
+};
+var _default = exports.default = managerReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_meta.js b/dist/reducers/reducer_meta.js
new file mode 100644
index 00000000..3b92cb0e
--- /dev/null
+++ b/dist/reducers/reducer_meta.js
@@ -0,0 +1,40 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ peaks: {
+ intervalL: null,
+ intervalR: null,
+ observeFrequency: null,
+ deltaX: null
+ },
+ dscMetaData: {
+ meltingPoint: null,
+ tg: null
+ }
+};
+const updateMetaData = (state, action) => {
+ const {
+ dscMetaData
+ } = action.payload;
+ return Object.assign({}, state, {
+ dscMetaData
+ });
+};
+const metaReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.META.UPDATE_PEAKS_RDC:
+ return Object.assign({}, state, action.payload);
+ case _action_type.META.UPDATE_META_DATA_RDC:
+ return updateMetaData(state, action);
+ default:
+ return state;
+ }
+};
+var _default = exports.default = metaReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_multiplicity.js b/dist/reducers/reducer_multiplicity.js
new file mode 100644
index 00000000..651182e1
--- /dev/null
+++ b/dist/reducers/reducer_multiplicity.js
@@ -0,0 +1,199 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _reduxUndo = _interopRequireDefault(require("redux-undo"));
+var _action_type = require("../constants/action_type");
+var _undo_redo_config = require("./undo_redo_config");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ selectedIdx: 0,
+ multiplicities: [{
+ stack: [],
+ shift: 0,
+ smExtext: false,
+ edited: false
+ }]
+};
+const defaultEmptyMultiplicity = {
+ stack: [],
+ shift: 0,
+ smExtext: false,
+ edited: false
+};
+const setShift = (state, action) => {
+ const shift = action.payload.prevOffset;
+ const {
+ selectedIdx,
+ multiplicities
+ } = state;
+ const selectedMulti = multiplicities[selectedIdx];
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ shift
+ });
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[selectedIdx] = newSelectedMulti;
+ return Object.assign({}, state, {
+ multiplicities: newMultiplicities
+ });
+};
+const rmFromStack = (state, action) => {
+ const {
+ dataToRemove,
+ curveIdx
+ } = action.payload;
+ const {
+ multiplicities
+ } = state;
+ const selectedMulti = multiplicities[curveIdx];
+ const {
+ stack
+ } = selectedMulti;
+ const {
+ xL,
+ xU,
+ xExtent
+ } = dataToRemove;
+ let [txL, txU] = [0, 0];
+ if (xL && xU) {
+ // rm click integration
+ [txL, txU] = [xL, xU];
+ } else if (xExtent) {
+ // rm click multiplicity
+ [txL, txU] = [xExtent.xL, xExtent.xU];
+ } else {
+ return state;
+ }
+ const newStack = stack.filter(k => {
+ const [kxL, kxU] = [k.xExtent.xL, k.xExtent.xU];
+ return kxL !== txL && kxU !== txU;
+ });
+ const newSmExtext = newStack[0] ? newStack[0].xExtent : false;
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ stack: newStack,
+ smExtext: newSmExtext
+ });
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ return Object.assign({}, state, {
+ multiplicities: newMultiplicities,
+ selectedIdx: curveIdx
+ });
+};
+const updateMpyJ = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ xExtent,
+ value
+ } = payload;
+ if (!value && value !== '') return state;
+ const {
+ selectedIdx,
+ multiplicities
+ } = state;
+ const selectedMulti = multiplicities[selectedIdx];
+ const {
+ stack
+ } = selectedMulti;
+ const regx = /[^0-9.,-]/g;
+ const js = value.replace(regx, '').split(',').map(j => parseFloat(j)).filter(j => j);
+ const newStack = stack.map(k => {
+ if (k.xExtent.xL === xExtent.xL && k.xExtent.xU === xExtent.xU) {
+ if (k.mpyType === 'm') return Object.assign({}, k, {
+ js: []
+ });
+ return Object.assign({}, k, {
+ js
+ });
+ }
+ return k;
+ });
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ stack: newStack
+ });
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[selectedIdx] = newSelectedMulti;
+ return Object.assign({}, state, {
+ multiplicities: newMultiplicities
+ });
+};
+const clickMpyOne = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ curveIdx,
+ payloadData
+ } = payload;
+ const {
+ multiplicities
+ } = state;
+ const selectedMulti = multiplicities[curveIdx];
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ smExtext: payloadData
+ });
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ return Object.assign({}, state, {
+ multiplicities: newMultiplicities,
+ selectedIdx: curveIdx
+ });
+};
+const clearAll = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ curveIdx
+ } = payload;
+ const {
+ multiplicities
+ } = state;
+ const newSelectedMulti = Object.assign({}, defaultEmptyMultiplicity, {
+ edited: true
+ });
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ return Object.assign({}, state, {
+ multiplicities: newMultiplicities
+ });
+};
+const multiplicityReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.EDITPEAK.SHIFT:
+ return setShift(state, action);
+ case _action_type.INTEGRATION.RM_ONE:
+ return rmFromStack(state, action);
+ case _action_type.UI.SWEEP.SELECT_MULTIPLICITY_RDC:
+ case _action_type.MULTIPLICITY.PEAK_RM_BY_PANEL_RDC:
+ case _action_type.MULTIPLICITY.PEAK_RM_BY_UI_RDC:
+ case _action_type.MULTIPLICITY.PEAK_ADD_BY_UI_RDC:
+ case _action_type.MULTIPLICITY.RESET_ONE_RDC:
+ return action.payload;
+ case _action_type.MULTIPLICITY.UPDATE_J:
+ return updateMpyJ(state, action);
+ case _action_type.MULTIPLICITY.TYPE_SELECT_RDC:
+ return action.payload;
+ case _action_type.MULTIPLICITY.ONE_CLICK:
+ case _action_type.MULTIPLICITY.ONE_CLICK_BY_UI:
+ return clickMpyOne(state, action);
+ case _action_type.MULTIPLICITY.RESET_ALL_RDC:
+ return action.payload;
+ case _action_type.MULTIPLICITY.CLEAR_ALL:
+ return clearAll(state, action);
+ case _action_type.MANAGER.RESETALL:
+ return state;
+ case _action_type.MANAGER.RESET_MULTIPLICITY:
+ return initialState;
+ default:
+ return _undo_redo_config.undoRedoActions.indexOf(action.type) >= 0 ? Object.assign({}, state) : state;
+ }
+};
+const undoableMultiplicityReducer = (0, _reduxUndo.default)(multiplicityReducer, _undo_redo_config.undoRedoConfig);
+var _default = exports.default = undoableMultiplicityReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_scan.js b/dist/reducers/reducer_scan.js
new file mode 100644
index 00000000..99fe706b
--- /dev/null
+++ b/dist/reducers/reducer_scan.js
@@ -0,0 +1,46 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ target: false,
+ count: 1,
+ isAuto: true
+};
+const setTarget = (state, payload) => Object.assign({}, state, {
+ target: payload
+});
+const resetAll = (state, payload) => {
+ const {
+ scanCount,
+ scanEditTarget
+ } = payload;
+ return Object.assign({}, state, {
+ target: false,
+ count: parseInt(scanCount, 10),
+ isAuto: !scanEditTarget
+ });
+};
+const toggleIsAuto = state => Object.assign({}, state, {
+ isAuto: !state.isAuto,
+ target: false
+});
+const scanReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.SCAN.SET_TARGET:
+ case _action_type.SCAN.RESET_TARGET:
+ return setTarget(state, action.payload);
+ case _action_type.SCAN.TOGGLE_ISAUTO:
+ return toggleIsAuto(state);
+ case _action_type.MANAGER.RESET_INIT_MS:
+ return resetAll(state, action.payload);
+ default:
+ return state;
+ }
+};
+var _default = exports.default = scanReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_shift.js b/dist/reducers/reducer_shift.js
new file mode 100644
index 00000000..310ac7d8
--- /dev/null
+++ b/dist/reducers/reducer_shift.js
@@ -0,0 +1,245 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+var _list_shift = require("../constants/list_shift");
+var _shift = require("../helpers/shift");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const shiftNone = _list_shift.LIST_SHIFT_1H[0];
+const normalizeShiftName = input => (input || '').toString().normalize('NFKD').replace(/[^a-z0-9]+/gi, '').toLowerCase();
+
+// const initialState = {
+// ref: shiftNone,
+// peak: false,
+// enable: true,
+// };
+
+const initialState = {
+ selectedIdx: 0,
+ shifts: [{
+ ref: shiftNone,
+ peak: false,
+ enable: true
+ }]
+};
+const defaultEmptyShift = {
+ ref: shiftNone,
+ peak: false,
+ enable: true
+};
+const resetRef = payload => {
+ const {
+ shift,
+ layout
+ } = payload;
+ if (!shift || !shift.solventName || !shift.solventValue) return shiftNone;
+ const name = shift.solventName;
+ const normalizedName = normalizeShiftName(name);
+ let target = false;
+ const listShift = (0, _list_shift.getListShift)(layout);
+ listShift.forEach(l => {
+ if (normalizeShiftName(l.name) === normalizedName) {
+ target = l;
+ }
+ });
+ return target || shiftNone[0];
+};
+const resetEnable = payload => {
+ const {
+ typ
+ } = payload.operation;
+ switch (typ) {
+ case 'NMR':
+ return true;
+ default:
+ return false;
+ }
+};
+const resetShift = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ curvesInfo
+ } = payload;
+ const {
+ isMultiCurve,
+ curveIdx,
+ numberOfCurve
+ } = curvesInfo;
+ const {
+ shifts
+ } = state;
+ let selectedShift = shifts[curveIdx];
+ if (selectedShift === false || selectedShift === undefined) {
+ selectedShift = defaultEmptyShift;
+ }
+ if (isMultiCurve) {
+ for (let idx = 0; idx < numberOfCurve; idx += 1) {
+ const checkShift = shifts[idx];
+ if (!checkShift) {
+ shifts[idx] = defaultEmptyShift;
+ }
+ }
+ }
+ const newShift = Object.assign({}, defaultEmptyShift, {
+ ref: resetRef(payload),
+ enable: resetEnable(payload)
+ });
+ shifts[curveIdx] = newShift;
+ return Object.assign({}, state, {
+ shifts,
+ selectedIdx: curveIdx
+ });
+};
+const updateShift = (state, action) => {
+ // eslint-disable-line
+ const {
+ selectedIdx,
+ shifts
+ } = state;
+ let selectedShift = shifts[selectedIdx];
+ if (selectedShift === false || selectedShift === undefined) {
+ selectedShift = defaultEmptyShift;
+ }
+ const newShift = Object.assign({}, selectedShift, {
+ ref: false,
+ enable: selectedShift.enable
+ });
+ shifts[selectedIdx] = newShift;
+ return Object.assign({}, state, {
+ shifts,
+ selectedIdx
+ });
+};
+const setRef = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ dataToSet,
+ curveIdx
+ } = payload;
+ const {
+ shifts
+ } = state;
+ let selectedShift = shifts[curveIdx];
+ if (selectedShift === false || selectedShift === undefined) {
+ selectedShift = defaultEmptyShift;
+ }
+ const newShift = Object.assign({}, selectedShift, {
+ ref: dataToSet,
+ enable: true
+ });
+ shifts[curveIdx] = newShift;
+ return Object.assign({}, state, {
+ shifts,
+ selectedIdx: curveIdx
+ });
+};
+const setPeak = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ dataToSet,
+ curveIdx
+ } = payload;
+ const {
+ shifts
+ } = state;
+ let selectedShift = shifts[curveIdx];
+ if (selectedShift === false || selectedShift === undefined) {
+ selectedShift = defaultEmptyShift;
+ }
+ const resX = (0, _shift.CalcResidualX)(selectedShift.ref, selectedShift.peak, dataToSet);
+ const trueApex = (0, _shift.RealPts)([dataToSet], resX)[0];
+ const isSamePt = selectedShift.peak.x === trueApex.x;
+ const truePeak = trueApex && trueApex.x && !isSamePt ? trueApex : false;
+ const newShift = Object.assign({}, selectedShift, {
+ peak: truePeak,
+ enable: true
+ });
+ shifts[curveIdx] = newShift;
+ return Object.assign({}, state, {
+ shifts,
+ selectedIdx: curveIdx
+ });
+};
+const removePeak = (state, action) => {
+ // eslint-disable-line
+ const {
+ selectedIdx,
+ shifts
+ } = state;
+ let selectedShift = shifts[selectedIdx];
+ if (selectedShift === false || selectedShift === undefined) {
+ selectedShift = defaultEmptyShift;
+ }
+ const newShift = Object.assign({}, selectedShift, {
+ peak: false,
+ enable: true
+ });
+ shifts[selectedIdx] = newShift;
+ return Object.assign({}, state, {
+ shifts,
+ selectedIdx
+ });
+};
+const addNegative = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ dataToAdd,
+ curveIdx
+ } = payload;
+ const {
+ shifts
+ } = state;
+ let selectedShift = shifts[curveIdx];
+ if (selectedShift === false || selectedShift === undefined) {
+ selectedShift = defaultEmptyShift;
+ }
+ const rmApex = selectedShift.peak.x === dataToAdd.x;
+ if (!rmApex) {
+ return state;
+ }
+ const newShift = Object.assign({}, selectedShift, {
+ peak: false,
+ enable: true
+ });
+ shifts[curveIdx] = newShift;
+ return Object.assign({}, state, {
+ shifts,
+ selectedIdx: curveIdx
+ });
+};
+const shiftReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.SHIFT.SET_REF:
+ return setRef(state, action);
+ case _action_type.SHIFT.SET_PEAK:
+ {
+ return setPeak(state, action);
+ }
+ case _action_type.SHIFT.RM_PEAK:
+ return removePeak(state, action);
+ case _action_type.EDITPEAK.ADD_NEGATIVE:
+ {
+ return addNegative(state, action);
+ }
+ case _action_type.LAYOUT.UPDATE:
+ return updateShift(initialState, action);
+ case _action_type.MANAGER.RESETSHIFT:
+ // case MANAGER.RESETALL:
+ return resetShift(initialState, action);
+ default:
+ return state;
+ }
+};
+var _default = exports.default = shiftReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_simulation.js b/dist/reducers/reducer_simulation.js
new file mode 100644
index 00000000..81d0df10
--- /dev/null
+++ b/dist/reducers/reducer_simulation.js
@@ -0,0 +1,25 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ nmrSimPeaks: []
+};
+const resetAll = (state, action) => {
+ const newState = action.payload;
+ return Object.assign({}, state, newState);
+};
+const simulatioinReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.SIMULATION.RESET_ALL_RDC:
+ return resetAll(state, action);
+ default:
+ return state;
+ }
+};
+var _default = exports.default = simulatioinReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_status.js b/dist/reducers/reducer_status.js
new file mode 100644
index 00000000..e14b5f7c
--- /dev/null
+++ b/dist/reducers/reducer_status.js
@@ -0,0 +1,45 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ btnSubmit: false
+};
+const statusReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.STATUS.TOGGLEBTNSUBMIT:
+ return Object.assign({}, state, {
+ btnSubmit: false
+ } // !state.btnSubmit
+ );
+ case _action_type.STATUS.TOGGLEBTNALL:
+ return Object.assign({}, state, {
+ btnSubmit: false
+ } // !state.btnSubmit
+ );
+ case _action_type.STATUS.ENABLEBTNALL:
+ case _action_type.EDITPEAK.ADDPOSITIVE:
+ case _action_type.EDITPEAK.RMPOSITIVE:
+ case _action_type.EDITPEAK.ADDNEGATIVE:
+ case _action_type.EDITPEAK.RMNEGATIVE:
+ case _action_type.THRESHOLD.UPDATE_VALUE:
+ case _action_type.THRESHOLD.RESET_VALUE:
+ return Object.assign({}, state, {
+ btnSubmit: false
+ });
+ case _action_type.LAYOUT.UPDATE:
+ return Object.assign({}, state, {
+ btnSubmit: false
+ });
+ case _action_type.MANAGER.RESETALL:
+ return initialState;
+ default:
+ return initialState;
+ }
+};
+var _default = exports.default = statusReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_submit.js b/dist/reducers/reducer_submit.js
new file mode 100644
index 00000000..6fc47bf8
--- /dev/null
+++ b/dist/reducers/reducer_submit.js
@@ -0,0 +1,59 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+var _format = _interopRequireDefault(require("../helpers/format"));
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ isAscend: false,
+ isIntensity: true,
+ decimal: 2,
+ operation: {
+ name: 'empty'
+ }
+};
+const updateOperation = action => ({
+ operation: action.payload || initialState.operation
+});
+const submitReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.SUBMIT.TOGGLE_IS_ASCEND:
+ return Object.assign({}, state, {
+ isAscend: !state.isAscend
+ });
+ case _action_type.SUBMIT.TOGGLE_IS_INTENSITY:
+ return Object.assign({}, state, {
+ isIntensity: !state.isIntensity
+ });
+ case _action_type.SUBMIT.UPDATE_OPERATION:
+ return Object.assign({}, state, updateOperation(action));
+ case _action_type.SUBMIT.UPDATE_DECIMAL:
+ return Object.assign({}, state, {
+ decimal: action.payload.target.value
+ });
+ case _action_type.LAYOUT.UPDATE:
+ {
+ const decimal = _format.default.spectraDigit(action.payload);
+ return Object.assign({}, state, {
+ decimal
+ });
+ }
+ case _action_type.MANAGER.RESETALL:
+ {
+ const decimal = _format.default.spectraDigit(action.payload.operation.layout);
+ return Object.assign({}, state, {
+ decimal,
+ isIntensity: true,
+ isAscend: false
+ });
+ }
+ default:
+ return state;
+ }
+};
+var _default = exports.default = submitReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_threshold.js b/dist/reducers/reducer_threshold.js
new file mode 100644
index 00000000..7fc7f727
--- /dev/null
+++ b/dist/reducers/reducer_threshold.js
@@ -0,0 +1,222 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ selectedIdx: 0,
+ list: [{
+ isEdit: true,
+ value: false,
+ upper: false,
+ lower: false
+ }]
+};
+
+// const defaultThresHold = {
+// isEdit: true,
+// value: false,
+// upper: false,
+// lower: false,
+// };
+
+const setThresHoldValue = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ list,
+ selectedIdx
+ } = state;
+ if (payload) {
+ const {
+ value,
+ curveIdx
+ } = payload;
+ const selectedThres = list[curveIdx];
+ const newSelectedThres = Object.assign({}, selectedThres, {
+ value
+ });
+ const newListThres = [...list];
+ newListThres[curveIdx] = newSelectedThres;
+ return Object.assign({}, state, {
+ list: newListThres,
+ selectedIdx: curveIdx
+ });
+ }
+ const selectedThres = list[selectedIdx];
+ const newSelectedThres = Object.assign({}, selectedThres, {
+ value: payload
+ });
+ const newListThres = [...list];
+ newListThres[selectedIdx] = newSelectedThres;
+ return Object.assign({}, state, {
+ list: newListThres
+ });
+};
+const setThresHoldUpper = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ list,
+ selectedIdx
+ } = state;
+ if (payload) {
+ const {
+ value,
+ curveIdx
+ } = payload;
+ const selectedThres = list[curveIdx];
+ const newSelectedThres = Object.assign({}, selectedThres, {
+ upper: value
+ });
+ const newListThres = [...list];
+ newListThres[curveIdx] = newSelectedThres;
+ return Object.assign({}, state, {
+ list: newListThres,
+ selectedIdx: curveIdx
+ });
+ }
+ const selectedThres = list[selectedIdx];
+ const newSelectedThres = Object.assign({}, selectedThres, {
+ upper: payload
+ });
+ const newListThres = [...list];
+ newListThres[selectedIdx] = newSelectedThres;
+ return Object.assign({}, state, {
+ list: newListThres
+ });
+};
+const setThresHoldLower = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ list,
+ selectedIdx
+ } = state;
+ if (payload) {
+ const {
+ value,
+ curveIdx
+ } = payload;
+ const selectedThres = list[curveIdx];
+ const newSelectedThres = Object.assign({}, selectedThres, {
+ lower: value
+ });
+ const newListThres = [...list];
+ newListThres[curveIdx] = newSelectedThres;
+ return Object.assign({}, state, {
+ list: newListThres,
+ selectedIdx: curveIdx
+ });
+ }
+ const selectedThres = list[selectedIdx];
+ const newSelectedThres = Object.assign({}, selectedThres, {
+ lower: payload
+ });
+ const newListThres = [...list];
+ newListThres[selectedIdx] = newSelectedThres;
+ return Object.assign({}, state, {
+ list: newListThres
+ });
+};
+const setThresHoldIsEdit = state => {
+ const {
+ list,
+ selectedIdx
+ } = state;
+ const selectedThres = list[selectedIdx];
+ const {
+ isEdit
+ } = selectedThres;
+ const newSelectedThres = Object.assign({}, selectedThres, {
+ isEdit: !isEdit
+ });
+ const newListThres = [...list];
+ newListThres[selectedIdx] = newSelectedThres;
+ return Object.assign({}, state, {
+ list: newListThres
+ });
+};
+const resetAll = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ list
+ } = state;
+ const newList = list.map(item => ({
+ isEdit: item.isEdit,
+ value: payload && payload.thresRef,
+ upper: item.upper,
+ lower: item.lower
+ }));
+ return Object.assign({}, state, {
+ selectedIdx: 0,
+ list: newList
+ });
+};
+const setListThreshold = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ list
+ } = state;
+ if (payload && payload.length > list.length) {
+ const newList = payload.map(() => ({
+ isEdit: true,
+ value: false,
+ upper: false,
+ lower: false
+ }));
+ return Object.assign({}, state, {
+ list: newList
+ });
+ }
+ return state;
+};
+const resetInitCommon = state => {
+ const {
+ list
+ } = state;
+ const newList = list.map(item => ({
+ isEdit: true,
+ value: item.value,
+ upper: item.upper,
+ lower: item.lower
+ }));
+ return Object.assign({}, state, {
+ selectedIdx: 0,
+ list: newList
+ });
+};
+const thresholdReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.CURVE.SET_ALL_CURVES:
+ return setListThreshold(state, action);
+ case _action_type.THRESHOLD.UPDATE_VALUE:
+ return setThresHoldValue(state, action);
+ case _action_type.THRESHOLD.UPDATE_UPPER_VALUE:
+ return setThresHoldUpper(state, action);
+ case _action_type.THRESHOLD.UPDATE_LOWER_VALUE:
+ return setThresHoldLower(state, action);
+ case _action_type.THRESHOLD.RESET_VALUE:
+ return setThresHoldValue(state, action);
+ case _action_type.THRESHOLD.TOGGLE_ISEDIT:
+ return setThresHoldIsEdit(state);
+ case _action_type.MANAGER.RESET_INIT_COMMON:
+ return resetInitCommon(state);
+ case _action_type.MANAGER.RESETALL:
+ return resetAll(state, action);
+ default:
+ return state;
+ }
+};
+var _default = exports.default = thresholdReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_ui.js b/dist/reducers/reducer_ui.js
new file mode 100644
index 00000000..14b7533f
--- /dev/null
+++ b/dist/reducers/reducer_ui.js
@@ -0,0 +1,49 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+var _list_ui = require("../constants/list_ui");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ viewer: _list_ui.LIST_UI_VIEWER_TYPE.SPECTRUM,
+ sweepType: _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN,
+ sweepExtent: {
+ xExtent: false,
+ yExtent: false
+ },
+ jcampIdx: 0
+};
+const uiReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.UI.VIEWER.SET_TYPE:
+ return Object.assign({}, state, {
+ viewer: action.payload
+ });
+ case _action_type.UI.SWEEP.SET_TYPE:
+ if (action.payload === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET) {
+ return Object.assign({}, state, {
+ sweepExtent: {
+ xExtent: false,
+ yExtent: false
+ }
+ });
+ }
+ return Object.assign({}, state, {
+ sweepType: action.payload,
+ jcampIdx: action.jcampIdx
+ });
+ case _action_type.UI.SWEEP.SELECT_ZOOMIN:
+ return Object.assign({}, state, {
+ sweepExtent: action.payload
+ });
+ case _action_type.MANAGER.RESETALL:
+ return initialState;
+ default:
+ return state;
+ }
+};
+var _default = exports.default = uiReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_voltammetry.js b/dist/reducers/reducer_voltammetry.js
new file mode 100644
index 00000000..dd9e7727
--- /dev/null
+++ b/dist/reducers/reducer_voltammetry.js
@@ -0,0 +1,603 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _action_type = require("../constants/action_type");
+var _chem = require("../helpers/chem");
+/* eslint-disable prefer-object-spread, default-param-last */
+
+const initialState = {
+ spectraList: [],
+ areaValue: 1.0,
+ areaUnit: 'cm²',
+ useCurrentDensity: false
+};
+const initSpectra = {
+ list: [],
+ origin: [],
+ selectedIdx: -1,
+ isWorkMaxPeak: true,
+ jcampIdx: -1,
+ shift: {
+ ref: null,
+ val: 0,
+ prevValue: 0
+ },
+ hasRefPeak: false,
+ history: []
+};
+const addPairPeak = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload !== undefined) {
+ let spectra = spectraList[payload];
+ if (!spectra) {
+ spectra = initSpectra;
+ spectraList.push(spectra);
+ }
+ const {
+ list,
+ selectedIdx
+ } = spectra;
+ let index = selectedIdx;
+ index += 1;
+ const newList = list.map(item => {
+ // eslint-disable-line
+ return {
+ ...item
+ };
+ });
+ newList.push({
+ min: null,
+ max: null,
+ isRef: false,
+ e12: null,
+ createdAt: Date.now()
+ });
+ spectraList[payload] = Object.assign({}, spectra, {
+ list: newList,
+ selectedIdx: index,
+ origin: [...newList]
+ }); // eslint-disable-line
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const removePairPeak = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload !== undefined) {
+ const {
+ index,
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ if (spectra) {
+ const {
+ list,
+ origin
+ } = spectra;
+ list.splice(index, 1);
+ origin.splice(index, 1);
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ list,
+ selectedIdx: index,
+ origin
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+ }
+ return state;
+};
+const getE12 = data => {
+ if (data.max && data.min) {
+ const {
+ max,
+ min
+ } = data;
+ const delta = (0, _chem.GetCyclicVoltaPeakSeparate)(max.x, min.x);
+ return Math.min(max.x, min.x) + 0.5 * delta;
+ }
+ return null;
+};
+const addPeak = (state, action, isMax = true) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload) {
+ const {
+ peak,
+ index,
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ const {
+ list
+ } = spectra;
+ const newList = list.map(item => {
+ // eslint-disable-line
+ return {
+ ...item
+ };
+ });
+ let pairPeak = newList[index];
+ if (isMax) {
+ pairPeak = Object.assign({}, pairPeak, {
+ max: peak
+ });
+ } else {
+ pairPeak = Object.assign({}, pairPeak, {
+ min: peak
+ });
+ }
+ pairPeak.e12 = getE12(pairPeak);
+ pairPeak.updatedAt = Date.now();
+ newList[index] = pairPeak;
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ list: newList,
+ selectedIdx: index,
+ jcampIdx,
+ origin: [...newList]
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const removePeak = (state, action, isMax = true) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload) {
+ const {
+ index,
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ const {
+ list
+ } = spectra;
+ const newList = list;
+ const pairPeak = newList[index];
+ if (isMax) {
+ pairPeak.max = null;
+ } else {
+ pairPeak.min = null;
+ }
+ pairPeak.e12 = getE12(pairPeak);
+ pairPeak.updatedAt = Date.now();
+ newList[index] = pairPeak;
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ list: newList,
+ selectedIdx: index,
+ jcampIdx,
+ origin: [...newList]
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const selectPairPeak = (state, action) => {
+ const {
+ payload
+ } = action;
+ if (payload !== undefined) {
+ const {
+ spectraList
+ } = state;
+ const {
+ index,
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ if (spectra) {
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ selectedIdx: index
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+ }
+ return state;
+};
+const setWorkWithMaxPeak = (state, action) => {
+ const {
+ payload
+ } = action;
+ if (payload !== undefined) {
+ const {
+ spectraList
+ } = state;
+ const {
+ isMax,
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ if (spectra) {
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ isWorkMaxPeak: isMax
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+ }
+ return state;
+};
+const addPecker = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload) {
+ const {
+ peak,
+ index,
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ const {
+ list
+ } = spectra;
+ const newList = list;
+ const pairPeak = newList[index];
+ pairPeak.pecker = peak;
+ pairPeak.updatedAt = Date.now();
+ newList[index] = pairPeak;
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ list: newList,
+ selectedIdx: index,
+ jcampIdx,
+ origin: [...newList]
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const removePecker = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload) {
+ const {
+ index,
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ const {
+ list
+ } = spectra;
+ const newList = list;
+ const pairPeak = newList[index];
+ pairPeak.pecker = null;
+ pairPeak.updatedAt = Date.now();
+ newList[index] = pairPeak;
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ list: newList,
+ selectedIdx: index,
+ jcampIdx,
+ origin: [...newList]
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const setRef = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload) {
+ const {
+ jcampIdx
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ const {
+ list,
+ shift,
+ hasRefPeak,
+ history
+ } = spectra;
+ const newShift = Object.assign({}, shift);
+ const refPeaks = list.filter(pairPeak => pairPeak.isRef === true);
+ let offset = 0.0;
+ if (hasRefPeak) {
+ const currRefPeaks = refPeaks[0];
+ newShift.ref = currRefPeaks;
+ const {
+ val
+ } = shift;
+ const {
+ e12
+ } = currRefPeaks;
+ offset = e12 - val;
+ const newList = spectra.list.map(pairPeak => {
+ //eslint-disable-line
+ const {
+ max,
+ min,
+ pecker,
+ isRef
+ } = pairPeak;
+ let newMax = null;
+ let newMin = null;
+ let newPecker = null;
+ if (max) {
+ newMax = hasRefPeak ? {
+ x: max.x - offset,
+ y: max.y
+ } : {
+ x: max.x + parseFloat(offset),
+ y: max.y
+ };
+ }
+ if (min) {
+ newMin = hasRefPeak ? {
+ x: min.x - offset,
+ y: min.y
+ } : {
+ x: min.x + parseFloat(offset),
+ y: min.y
+ };
+ }
+ if (pecker) {
+ newPecker = hasRefPeak ? {
+ x: pecker.x - offset,
+ y: pecker.y
+ } : {
+ x: pecker.x + parseFloat(offset),
+ y: pecker.y
+ }; //eslint-disable-line
+ }
+ const newPairPeak = Object.assign({}, pairPeak, {
+ max: newMax,
+ min: newMin,
+ pecker: newPecker
+ }); //eslint-disable-line
+ newPairPeak.e12 = getE12(newPairPeak);
+ newPairPeak.updatedAt = Date.now();
+ if (isRef) {
+ newShift.ref = newPairPeak;
+ newShift.prevValue += offset;
+ }
+ return newPairPeak;
+ });
+ history.push(...[newList]);
+ spectra.list = newList;
+ } else {
+ newShift.ref = null;
+ const {
+ val
+ } = newShift;
+ offset = val;
+ const newList = spectra.origin.map(pairPeak => {
+ //eslint-disable-line
+ const {
+ max,
+ min,
+ pecker
+ } = pairPeak;
+ let newMax = null;
+ let newMin = null;
+ let newPecker = null;
+ if (max) {
+ newMax = {
+ x: max.x + parseFloat(val),
+ y: max.y
+ };
+ }
+ if (min) {
+ newMin = {
+ x: min.x + parseFloat(val),
+ y: min.y
+ };
+ }
+ if (pecker) {
+ newPecker = {
+ x: pecker.x + parseFloat(val),
+ y: pecker.y
+ };
+ }
+ const newPairPeak = Object.assign({}, pairPeak, {
+ max: newMax,
+ min: newMin,
+ pecker: newPecker,
+ isRef: false
+ }); //eslint-disable-line
+ newPairPeak.e12 = getE12(newPairPeak);
+ newPairPeak.updatedAt = Date.now();
+ return newPairPeak;
+ });
+ history.push(...[newList]);
+ spectra.list = newList;
+ newShift.prevValue = parseFloat(offset);
+ }
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ shift: newShift,
+ jcampIdx
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const selectRefPeaks = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload) {
+ const {
+ index,
+ jcampIdx,
+ checked
+ } = payload;
+ const spectra = spectraList[jcampIdx];
+ const {
+ list,
+ shift,
+ history
+ } = spectra;
+ const newShift = shift;
+ const newList = list;
+ newList.forEach((pairPeak, idx) => {
+ const newPairPeak = pairPeak;
+ newPairPeak.isRef = false;
+ newPairPeak.updatedAt = Date.now();
+ if (idx === index) {
+ newPairPeak.isRef = checked;
+ newList[index] = newPairPeak;
+ }
+ });
+ const refPeaks = newList.filter(pairPeak => pairPeak.isRef === true);
+ const hasRefPeak = refPeaks.length > 0;
+ history.push(...[newList]);
+ spectraList[jcampIdx] = Object.assign({}, spectra, {
+ list: newList,
+ selectedIdx: index,
+ jcampIdx,
+ hasRefPeak,
+ shift: newShift
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const selectRefFactor = (state, action) => {
+ const {
+ payload
+ } = action;
+ const {
+ spectraList
+ } = state;
+ if (payload) {
+ const {
+ factor,
+ curveIdx
+ } = payload;
+ const spectra = spectraList[curveIdx];
+ const {
+ shift
+ } = spectra;
+ const newShift = Object.assign({}, shift);
+ newShift.val = factor;
+ spectraList[curveIdx] = Object.assign({}, spectra, {
+ shift: newShift,
+ jcampIdx: curveIdx
+ });
+ return Object.assign({}, state, {
+ spectraList
+ });
+ }
+ return state;
+};
+const cyclicVoltaReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.CYCLIC_VOLTA_METRY.ADD_PAIR_PEAKS:
+ return addPairPeak(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.REMOVE_PAIR_PEAKS:
+ return removePairPeak(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.ADD_MAX_PEAK:
+ return addPeak(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.REMOVE_MAX_PEAK:
+ return removePeak(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.ADD_MIN_PEAK:
+ return addPeak(state, action, false);
+ case _action_type.CYCLIC_VOLTA_METRY.REMOVE_MIN_PEAK:
+ return removePeak(state, action, false);
+ case _action_type.CYCLIC_VOLTA_METRY.WORK_WITH_MAX_PEAK:
+ return setWorkWithMaxPeak(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.SELECT_PAIR_PEAK:
+ return selectPairPeak(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.ADD_PECKER:
+ return addPecker(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.REMOVE_PECKER:
+ return removePecker(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.SET_REF:
+ return setRef(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.SELECT_REF_PEAK:
+ return selectRefPeaks(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.SET_FACTOR:
+ return selectRefFactor(state, action);
+ case _action_type.CYCLIC_VOLTA_METRY.RESETALL:
+ return Object.assign({}, state, {
+ spectraList: []
+ });
+ case _action_type.CYCLIC_VOLTA_METRY.SET_AREA_VALUE:
+ {
+ const {
+ value
+ } = action.payload;
+ if (value === '') {
+ return Object.assign({}, state, {
+ areaValue: ''
+ });
+ }
+ const areaValue = Number.isFinite(value) ? value : state.areaValue;
+ return Object.assign({}, state, {
+ areaValue
+ });
+ }
+ case _action_type.CYCLIC_VOLTA_METRY.SET_AREA_UNIT:
+ {
+ const {
+ unit
+ } = action.payload;
+ return Object.assign({}, state, {
+ areaUnit: unit
+ });
+ }
+ case _action_type.CYCLIC_VOLTA_METRY.TOGGLE_DENSITY:
+ {
+ return Object.assign({}, state, {
+ useCurrentDensity: !state.useCurrentDensity
+ });
+ }
+ default:
+ return state;
+ }
+};
+var _default = exports.default = cyclicVoltaReducer;
\ No newline at end of file
diff --git a/dist/reducers/reducer_wavelength.js b/dist/reducers/reducer_wavelength.js
new file mode 100644
index 00000000..7c6de7ab
--- /dev/null
+++ b/dist/reducers/reducer_wavelength.js
@@ -0,0 +1,20 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _list_wavelength = require("../constants/list_wavelength");
+var _action_type = require("../constants/action_type");
+/* eslint-disable default-param-last */
+
+const initialState = _list_wavelength.LIST_WAVE_LENGTH[0];
+const wavelengthReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case _action_type.XRD.UPDATE_WAVE_LENGTH:
+ return action.payload;
+ default:
+ return state;
+ }
+};
+var _default = exports.default = wavelengthReducer;
\ No newline at end of file
diff --git a/dist/reducers/undo_redo_config.js b/dist/reducers/undo_redo_config.js
new file mode 100644
index 00000000..122961e6
--- /dev/null
+++ b/dist/reducers/undo_redo_config.js
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.undoRedoConfig = exports.undoRedoActions = void 0;
+var _reduxUndo = require("redux-undo");
+var _action_type = require("../constants/action_type");
+const undoRedoActions = exports.undoRedoActions = [_action_type.EDITPEAK.ADD_POSITIVE, _action_type.EDITPEAK.ADD_NEGATIVE, _action_type.EDITPEAK.RM_POSITIVE, _action_type.EDITPEAK.RM_NEGATIVE, _action_type.EDITPEAK.SHIFT, _action_type.EDITPEAK.CLEAR_ALL, _action_type.MANAGER.RESETALL, _action_type.MANAGER.RESETSHIFT, _action_type.MANAGER.RESET_INIT_COMMON, _action_type.MANAGER.RESET_INIT_NMR, _action_type.MANAGER.RESET_INIT_MS, _action_type.MANAGER.RESET_INIT_COMMON_WITH_INTERGATION, _action_type.UI.SWEEP.SELECT_INTEGRATION, _action_type.UI.SWEEP.SELECT_MULTIPLICITY_RDC, _action_type.INTEGRATION.RM_ONE, _action_type.INTEGRATION.SET_REF, _action_type.INTEGRATION.SET_FKR, _action_type.INTEGRATION.SPLIT, _action_type.INTEGRATION.RESET_ALL, _action_type.INTEGRATION.CLEAR_ALL, _action_type.MULTIPLICITY.PEAK_RM_BY_PANEL_RDC, _action_type.MULTIPLICITY.PEAK_RM_BY_UI_RDC, _action_type.MULTIPLICITY.PEAK_ADD_BY_UI_RDC, _action_type.MULTIPLICITY.RESET_ONE_RDC, _action_type.MULTIPLICITY.UPDATE_J, _action_type.MULTIPLICITY.TYPE_SELECT_RDC, _action_type.MULTIPLICITY.ONE_CLICK, _action_type.MULTIPLICITY.ONE_CLICK_BY_UI, _action_type.MULTIPLICITY.RESET_ALL_RDC, _action_type.MULTIPLICITY.CLEAR_ALL];
+const undoRedoConfig = exports.undoRedoConfig = {
+ debug: false,
+ limit: 10,
+ ignoreInitialState: true,
+ filter: (0, _reduxUndo.includeAction)(undoRedoActions),
+ clearHistoryType: [_action_type.EDITPEAK.SHIFT, _action_type.EDITPEAK.CLEAR_ALL, _action_type.MANAGER.RESETALL, _action_type.MANAGER.RESETSHIFT, _action_type.MANAGER.RESET_INIT_COMMON, _action_type.MANAGER.RESET_INIT_NMR, _action_type.MANAGER.RESET_INIT_MS, _action_type.MANAGER.RESET_INIT_COMMON_WITH_INTERGATION],
+ neverSkipReducer: [_action_type.EDITPEAK.SHIFT, _action_type.EDITPEAK.CLEAR_ALL, _action_type.MANAGER.RESETALL, _action_type.MANAGER.RESETSHIFT, _action_type.MANAGER.RESET_INIT_COMMON, _action_type.MANAGER.RESET_INIT_NMR, _action_type.MANAGER.RESET_INIT_MS, _action_type.MANAGER.RESET_INIT_COMMON_WITH_INTERGATION]
+};
\ No newline at end of file
diff --git a/dist/sagas/index.js b/dist/sagas/index.js
new file mode 100644
index 00000000..6b9c1884
--- /dev/null
+++ b/dist/sagas/index.js
@@ -0,0 +1,17 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = rootSaga;
+var _effects = require("redux-saga/effects");
+var _saga_edit_peak = _interopRequireDefault(require("./saga_edit_peak"));
+var _saga_manager = _interopRequireDefault(require("./saga_manager"));
+var _saga_ui = _interopRequireDefault(require("./saga_ui"));
+var _saga_meta = _interopRequireDefault(require("./saga_meta"));
+var _saga_multiplicity = _interopRequireDefault(require("./saga_multiplicity"));
+var _saga_multi_entities = _interopRequireDefault(require("./saga_multi_entities"));
+function* rootSaga() {
+ yield (0, _effects.all)([..._saga_edit_peak.default, ..._saga_manager.default, ..._saga_ui.default, ..._saga_meta.default, ..._saga_multiplicity.default, ..._saga_multi_entities.default]);
+}
\ No newline at end of file
diff --git a/dist/sagas/saga_edit_peak.js b/dist/sagas/saga_edit_peak.js
new file mode 100644
index 00000000..a68ad59d
--- /dev/null
+++ b/dist/sagas/saga_edit_peak.js
@@ -0,0 +1,75 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _effects = require("redux-saga/effects");
+var _action_type = require("../constants/action_type");
+var _shift = require("../helpers/shift");
+var _list_shift = require("../constants/list_shift");
+const getShift = state => state.shift;
+const getEditPeak = state => state.editPeak.present;
+function* addVirtualFactor(action) {
+ const originShift = yield (0, _effects.select)(getShift);
+ const origEPeak = yield (0, _effects.select)(getEditPeak);
+ const {
+ payload
+ } = action;
+ const {
+ curveIdx
+ } = payload;
+ const {
+ peaks
+ } = origEPeak;
+ let currentOriginPeaks = peaks[curveIdx];
+ if (currentOriginPeaks === false || currentOriginPeaks === undefined) {
+ currentOriginPeaks = {
+ prevOffset: 0,
+ pos: [],
+ neg: []
+ };
+ }
+ let currentOriginShift = originShift.shifts[curveIdx];
+ if (currentOriginShift === false || currentOriginShift === undefined) {
+ const shiftNone = _list_shift.LIST_SHIFT_1H[0];
+ currentOriginShift = {
+ ref: shiftNone,
+ peak: false,
+ enable: true
+ };
+ }
+ const origRef = currentOriginShift.ref;
+ const origApex = currentOriginShift.peak;
+ const {
+ prevOffset,
+ pos,
+ neg
+ } = currentOriginPeaks;
+ const absOffset = (0, _shift.FromManualToOffset)(origRef, origApex);
+ const relOffset = prevOffset - absOffset;
+ const nextPos = (0, _shift.VirtalPts)(pos, relOffset);
+ const nextNeg = (0, _shift.VirtalPts)(neg, relOffset);
+ yield (0, _effects.put)({
+ type: _action_type.EDITPEAK.SHIFT,
+ payload: Object.assign({}, payload, {
+ // eslint-disable-line
+ prevOffset: absOffset,
+ pos: nextPos,
+ neg: nextNeg
+ })
+ });
+}
+const editPeakSagas = [(0, _effects.takeEvery)(_action_type.SHIFT.SET_REF, addVirtualFactor), (0, _effects.takeEvery)(_action_type.SHIFT.SET_PEAK, addVirtualFactor)];
+var _default = exports.default = editPeakSagas;
+/* LOGIC
+ -no po - tg
+ | picked | another | absoffset | prevOffset | relative | newOffset
+-------------------------------------------------------------------
+0 | 40 20 - - - 0
+1 | 180 160 -140 0 140 140
+2 | 80 60 -40 -140 -100 100
+3 | 20 0 +20 -100 -120
+-------------------------------------------------------------------
+
+*/
\ No newline at end of file
diff --git a/dist/sagas/saga_manager.js b/dist/sagas/saga_manager.js
new file mode 100644
index 00000000..e87aec57
--- /dev/null
+++ b/dist/sagas/saga_manager.js
@@ -0,0 +1,97 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _effects = require("redux-saga/effects");
+var _action_type = require("../constants/action_type");
+const getLayout = state => state.layout;
+const getCurveSt = state => state.curve;
+const getIntegrationSt = state => state.integration.present;
+function* resetShift(action) {
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const layout = yield (0, _effects.select)(getLayout);
+ const {
+ payload
+ } = action;
+ const {
+ curveIdx,
+ listCurves
+ } = curveSt;
+ const numberOfCurve = listCurves.length;
+ yield (0, _effects.put)({
+ type: _action_type.MANAGER.RESETSHIFT,
+ payload: Object.assign(
+ // eslint-disable-line
+ {}, payload, {
+ layout,
+ curvesInfo: {
+ isMultiCurve: numberOfCurve > 0,
+ curveIdx,
+ numberOfCurve
+ }
+ })
+ });
+}
+function* resetInitNmr(action) {
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const integationSt = yield (0, _effects.select)(getIntegrationSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ integration,
+ simulation
+ } = action.payload;
+ const {
+ integrations
+ } = integationSt;
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = integration;
+ const payload = Object.assign({}, integationSt, {
+ integrations: newArrIntegration,
+ selectedIdx: curveIdx
+ }); // eslint-disable-line
+
+ if (integration) {
+ yield (0, _effects.put)({
+ type: _action_type.INTEGRATION.RESET_ALL_RDC,
+ payload
+ });
+ }
+ if (simulation) {
+ yield (0, _effects.put)({
+ type: _action_type.SIMULATION.RESET_ALL_RDC,
+ payload: simulation
+ });
+ }
+}
+function* resetInitCommonWithIntergation(action) {
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const integationSt = yield (0, _effects.select)(getIntegrationSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ integration
+ } = action.payload;
+ const {
+ integrations
+ } = integationSt;
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = integration;
+ const payload = Object.assign({}, integationSt, {
+ integrations: newArrIntegration,
+ selectedIdx: curveIdx
+ }); // eslint-disable-line
+
+ if (integration) {
+ yield (0, _effects.put)({
+ type: _action_type.INTEGRATION.RESET_ALL_RDC,
+ payload
+ });
+ }
+}
+const managerSagas = [(0, _effects.takeEvery)(_action_type.MANAGER.RESETALL, resetShift), (0, _effects.takeEvery)(_action_type.MANAGER.RESET_INIT_NMR, resetInitNmr), (0, _effects.takeEvery)(_action_type.MANAGER.RESET_INIT_COMMON_WITH_INTERGATION, resetInitCommonWithIntergation)];
+var _default = exports.default = managerSagas;
\ No newline at end of file
diff --git a/dist/sagas/saga_meta.js b/dist/sagas/saga_meta.js
new file mode 100644
index 00000000..6b3be549
--- /dev/null
+++ b/dist/sagas/saga_meta.js
@@ -0,0 +1,44 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _effects = require("redux-saga/effects");
+var _action_type = require("../constants/action_type");
+var _peakInterval = require("../third_party/peakInterval");
+function* updateMetaPeaks(action) {
+ const {
+ payload
+ } = action;
+ const {
+ intervalL,
+ intervalR
+ } = (0, _peakInterval.getPeakIntervals)(payload);
+ const {
+ observeFrequency,
+ data
+ } = payload.spectra[0];
+ const deltaX = Math.abs(data[0].x[0] - data[0].x[1]);
+ yield (0, _effects.put)({
+ type: _action_type.META.UPDATE_PEAKS_RDC,
+ payload: {
+ peaks: {
+ intervalL,
+ intervalR,
+ observeFrequency,
+ deltaX
+ }
+ }
+ });
+}
+function* updateMetaData(action) {
+ yield (0, _effects.put)({
+ type: _action_type.META.UPDATE_META_DATA_RDC,
+ payload: {
+ dscMetaData: action.payload
+ }
+ });
+}
+const metaSagas = [(0, _effects.takeEvery)(_action_type.META.UPDATE_PEAKS, updateMetaPeaks), (0, _effects.takeEvery)(_action_type.META.UPDATE_META_DATA, updateMetaData)];
+var _default = exports.default = metaSagas;
\ No newline at end of file
diff --git a/dist/sagas/saga_multi_entities.js b/dist/sagas/saga_multi_entities.js
new file mode 100644
index 00000000..ee648abd
--- /dev/null
+++ b/dist/sagas/saga_multi_entities.js
@@ -0,0 +1,234 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _effects = require("redux-saga/effects");
+var _action_type = require("../constants/action_type");
+var _list_layout = require("../constants/list_layout");
+/* eslint-disable no-plusplus */
+
+const getLayoutSt = state => state.layout;
+const getCurveSt = state => state.curve;
+const getIntegrationSt = state => state.integration.present;
+const getMultiplicitySt = state => state.multiplicity.present;
+function getMaxMinPeak(curve) {
+ return curve.maxminPeak;
+}
+function* setCyclicVoltametry(action) {
+ // eslint-disable-line
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ listCurves
+ } = curveSt;
+ if (listCurves) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.RESETALL,
+ payload: null
+ });
+ const numberOfCurves = listCurves.length;
+ if (numberOfCurves <= 0) {
+ return;
+ }
+ const firstCurve = listCurves[0];
+ const {
+ layout
+ } = firstCurve;
+ if (layout !== _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) {
+ return;
+ }
+ const cvSt = yield (0, _effects.select)(state => state.cyclicvolta);
+ const {
+ feature
+ } = firstCurve;
+ if (feature) {
+ const {
+ weAreaValue,
+ weAreaUnit,
+ currentMode
+ } = feature;
+ if (typeof weAreaUnit === 'string' && weAreaUnit.length > 0) {
+ const unit = weAreaUnit.replace('^2', '²');
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_AREA_UNIT,
+ payload: {
+ unit
+ }
+ });
+ } else {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_AREA_UNIT,
+ payload: {
+ unit: 'cm²'
+ }
+ });
+ }
+ if (weAreaValue !== undefined && weAreaValue !== null) {
+ let numeric = null;
+ if (typeof weAreaValue === 'string') {
+ const parsed = parseFloat(weAreaValue);
+ if (!Number.isNaN(parsed)) numeric = parsed;
+ } else if (Number.isFinite(weAreaValue)) {
+ numeric = weAreaValue;
+ }
+ if (Number.isFinite(numeric)) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_AREA_VALUE,
+ payload: {
+ value: numeric
+ }
+ });
+ } else {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_AREA_VALUE,
+ payload: {
+ value: 1.0
+ }
+ });
+ }
+ }
+ if (typeof currentMode === 'string' && currentMode.length > 0) {
+ const wantDensity = currentMode.toUpperCase() === 'DENSITY';
+ if (!!cvSt.useCurrentDensity !== wantDensity) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.TOGGLE_DENSITY,
+ payload: null
+ });
+ }
+ }
+ }
+ for (let index = 0; index < listCurves.length; index++) {
+ const curve = listCurves[index];
+ const maxminPeak = getMaxMinPeak(curve);
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_PAIR_PEAKS,
+ payload: index
+ });
+ for (let pidx = 0; pidx < maxminPeak.max.length; pidx++) {
+ const maxPeak = maxminPeak.max[pidx];
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_MAX_PEAK,
+ payload: {
+ peak: maxPeak,
+ index: pidx,
+ jcampIdx: index
+ }
+ });
+ const minPeak = maxminPeak.min[pidx];
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_MIN_PEAK,
+ payload: {
+ peak: minPeak,
+ index: pidx,
+ jcampIdx: index
+ }
+ });
+ const pecker = maxminPeak.pecker[pidx];
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_PECKER,
+ payload: {
+ peak: pecker,
+ index: pidx,
+ jcampIdx: index
+ }
+ });
+ }
+ const {
+ refIndex
+ } = maxminPeak;
+ if (refIndex > -1) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.SELECT_REF_PEAK,
+ payload: {
+ index: refIndex,
+ jcampIdx: index,
+ checked: true
+ }
+ });
+ }
+ }
+ }
+}
+function* setCyclicVoltametryRef(action) {
+ // eslint-disable-line
+ const layoutSt = yield (0, _effects.select)(getLayoutSt);
+ if (layoutSt !== _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) {
+ return;
+ }
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_REF,
+ payload: {
+ jcampIdx: curveIdx
+ }
+ });
+}
+function* setInitIntegrations(action) {
+ // eslint-disable-line
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ listCurves
+ } = curveSt;
+ if (listCurves) {
+ for (let index = 0; index < listCurves.length; index++) {
+ const integationSt = yield (0, _effects.select)(getIntegrationSt);
+ const multiplicitySt = yield (0, _effects.select)(getMultiplicitySt);
+ const curve = listCurves[index];
+ const {
+ integration,
+ multiplicity,
+ simulation
+ } = curve;
+ if (integration) {
+ const {
+ integrations
+ } = integationSt;
+ const newArrIntegration = [...integrations];
+ if (index < newArrIntegration.length) {
+ newArrIntegration[index] = integration;
+ } else {
+ newArrIntegration.push(integration);
+ }
+ const payload = Object.assign({}, integationSt, {
+ integrations: newArrIntegration,
+ selectedIdx: index
+ }); // eslint-disable-line
+ yield (0, _effects.put)({
+ type: _action_type.INTEGRATION.RESET_ALL_RDC,
+ payload
+ });
+ }
+ if (multiplicity) {
+ const {
+ multiplicities
+ } = multiplicitySt;
+ const newArrMultiplicities = [...multiplicities];
+ if (index < newArrMultiplicities.length) {
+ newArrMultiplicities[index] = multiplicity;
+ } else {
+ newArrMultiplicities.push(multiplicity);
+ }
+ const payload = Object.assign({}, multiplicitySt, {
+ multiplicities: newArrMultiplicities,
+ selectedIdx: index
+ }); // eslint-disable-line
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.RESET_ALL_RDC,
+ payload
+ });
+ }
+ if (simulation) {
+ yield (0, _effects.put)({
+ type: _action_type.SIMULATION.RESET_ALL_RDC,
+ payload: simulation
+ });
+ }
+ }
+ }
+}
+const multiEntitiesSagas = [(0, _effects.takeEvery)(_action_type.CURVE.SET_ALL_CURVES, setCyclicVoltametry), (0, _effects.takeEvery)(_action_type.CURVE.SET_ALL_CURVES, setInitIntegrations), (0, _effects.takeEvery)(_action_type.CYCLIC_VOLTA_METRY.SET_FACTOR, setCyclicVoltametryRef)];
+var _default = exports.default = multiEntitiesSagas;
\ No newline at end of file
diff --git a/dist/sagas/saga_multiplicity.js b/dist/sagas/saga_multiplicity.js
new file mode 100644
index 00000000..56645954
--- /dev/null
+++ b/dist/sagas/saga_multiplicity.js
@@ -0,0 +1,378 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _effects = require("redux-saga/effects");
+var _action_type = require("../constants/action_type");
+var _multiplicity_calc = require("../helpers/multiplicity_calc");
+var _multiplicity_manual = require("../helpers/multiplicity_manual");
+const getMetaSt = state => state.meta;
+const getCurveSt = state => state.curve;
+const getMultiplicitySt = state => state.multiplicity.present;
+function* selectMpy(action) {
+ const metaSt = yield (0, _effects.select)(getMetaSt);
+ const mpySt = yield (0, _effects.select)(getMultiplicitySt);
+ const {
+ newData,
+ curveIdx
+ } = action.payload;
+ const {
+ multiplicities
+ } = mpySt;
+ let selectedMulti = multiplicities[curveIdx];
+ if (selectedMulti === false || selectedMulti === undefined) {
+ selectedMulti = {
+ stack: [],
+ shift: 0,
+ smExtext: false,
+ edited: false
+ };
+ }
+ const {
+ xExtent,
+ yExtent,
+ dataPks
+ } = newData;
+ const {
+ shift,
+ stack
+ } = selectedMulti;
+ const {
+ xL,
+ xU
+ } = xExtent;
+ const {
+ yL,
+ yU
+ } = yExtent;
+ let peaks = dataPks.filter(p => xL <= p.x && p.x <= xU && yL <= p.y && p.y <= yU);
+ peaks = peaks.map(pk => ({
+ x: pk.x + shift,
+ y: pk.y
+ }));
+ const newXExtemt = {
+ xL: xL + shift,
+ xU: xU + shift
+ };
+ const coupling = (0, _multiplicity_calc.calcMpyCoup)(peaks, metaSt);
+ const m = {
+ peaks,
+ xExtent: newXExtemt,
+ yExtent,
+ mpyType: coupling.type,
+ js: coupling.js
+ };
+ const newStack = [...stack, m];
+ const newSelectedMulti = Object.assign(
+ // eslint-disable-line
+ {}, selectedMulti, {
+ stack: newStack,
+ smExtext: newXExtemt
+ });
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ const payload = Object.assign(
+ // eslint-disable-line
+ {}, mpySt, {
+ multiplicities: newMultiplicities,
+ selectedIdx: curveIdx
+ });
+ yield (0, _effects.put)({
+ type: _action_type.UI.SWEEP.SELECT_MULTIPLICITY_RDC,
+ payload
+ });
+}
+function* addUiPeakToStack(action) {
+ const metaSt = yield (0, _effects.select)(getMetaSt);
+ const mpySt = yield (0, _effects.select)(getMultiplicitySt);
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = mpySt;
+ const selectedMulti = multiplicities[curveIdx];
+ const {
+ shift,
+ stack,
+ smExtext
+ } = selectedMulti;
+ let {
+ x,
+ y
+ } = action.payload; // eslint-disable-line
+ if (!x || !y) return;
+ x += shift;
+ const newPeak = {
+ x,
+ y
+ };
+ const {
+ xL,
+ xU
+ } = smExtext;
+ if (x < xL || xU < x) return;
+ let isDuplicate = false;
+ const newStack = stack.map(k => {
+ if (k.xExtent.xL === xL && k.xExtent.xU === xU) {
+ const existXs = k.peaks.map(pk => pk.x);
+ if (existXs.indexOf(newPeak.x) >= 0) {
+ isDuplicate = true;
+ return k;
+ }
+ const newPks = [...k.peaks, newPeak];
+ const coupling = (0, _multiplicity_calc.calcMpyCoup)(newPks, metaSt);
+ return Object.assign(
+ // eslint-disable-line
+ {}, k, {
+ peaks: newPks,
+ mpyType: coupling.type,
+ js: coupling.js
+ });
+ }
+ return k;
+ });
+ if (isDuplicate) return;
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ stack: newStack
+ }); // eslint-disable-line
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ const payload = Object.assign({}, mpySt, {
+ multiplicities: newMultiplicities
+ }); // eslint-disable-line
+
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.PEAK_ADD_BY_UI_RDC,
+ payload
+ });
+}
+const rmPeakFromStack = (action, metaSt, mpySt, curveIdx = 0) => {
+ const {
+ peak,
+ xExtent
+ } = action.payload;
+ const {
+ multiplicities
+ } = mpySt;
+ const selectedMulti = multiplicities[curveIdx];
+ const {
+ stack
+ } = selectedMulti;
+ let newStack = stack.map(k => {
+ if (k.xExtent.xL === xExtent.xL && k.xExtent.xU === xExtent.xU) {
+ const newPks = k.peaks.filter(pk => pk.x !== peak.x);
+ const coupling = (0, _multiplicity_calc.calcMpyCoup)(newPks, metaSt);
+ return Object.assign(
+ // eslint-disable-line
+ {}, k, {
+ peaks: newPks,
+ mpyType: coupling.type,
+ js: coupling.js
+ });
+ }
+ return k;
+ });
+ newStack = newStack.filter(k => k.peaks.length !== 0);
+ if (newStack.length === 0) {
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ stack: newStack,
+ smExtext: false
+ }); // eslint-disable-line
+ multiplicities[curveIdx] = newSelectedMulti;
+ return Object.assign({}, mpySt, {
+ multiplicities
+ }); // eslint-disable-line
+ }
+ const noSmExtext = newStack.map(k => k.xExtent.xL === xExtent.xL && k.xExtent.xU === xExtent.xU ? 1 : 0).reduce((a, s) => a + s) === 0;
+ const newSmExtext = noSmExtext ? newStack[0].xExtent : xExtent;
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ stack: newStack,
+ smExtext: newSmExtext
+ }); // eslint-disable-line
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ return Object.assign({}, mpySt, {
+ multiplicities: newMultiplicities
+ }); // eslint-disable-line
+};
+function* rmPanelPeakFromStack(action) {
+ const metaSt = yield (0, _effects.select)(getMetaSt);
+ const mpySt = yield (0, _effects.select)(getMultiplicitySt);
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const payload = rmPeakFromStack(action, metaSt, mpySt, curveIdx);
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.PEAK_RM_BY_PANEL_RDC,
+ payload
+ });
+}
+function* rmUiPeakFromStack(action) {
+ const metaSt = yield (0, _effects.select)(getMetaSt);
+ const mpySt = yield (0, _effects.select)(getMultiplicitySt);
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = mpySt;
+ const selectedMulti = multiplicities[curveIdx];
+ const peak = action.payload;
+ const xExtent = selectedMulti.smExtext;
+ const newAction = Object.assign({}, action, {
+ payload: {
+ peak,
+ xExtent
+ }
+ }); // eslint-disable-line
+
+ const payload = rmPeakFromStack(newAction, metaSt, mpySt, curveIdx);
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.PEAK_RM_BY_UI_RDC,
+ payload
+ });
+}
+function* resetInitNmr(action) {
+ const {
+ multiplicity
+ } = action.payload;
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const mpySt = yield (0, _effects.select)(getMultiplicitySt);
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = mpySt;
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = multiplicity;
+ const payload = Object.assign({}, mpySt, {
+ multiplicities: newMultiplicities,
+ selectedIdx: curveIdx
+ }); // eslint-disable-line
+
+ if (multiplicity) {
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.RESET_ALL_RDC,
+ payload
+ });
+ }
+ // const metaSt = yield select(getMetaSt);
+ // const mpySt = yield select(getMultiplicitySt);
+
+ // if (!multiplicity) {
+ // yield put({
+ // type: MULTIPLICITY.RESET_ALL_RDC,
+ // payload: mpySt,
+ // });
+ // }
+
+ // const { stack } = multiplicity;
+ // const newStack = stack.map((k) => {
+ // const { peaks } = k;
+ // const coupling = calcMpyCoup(peaks, metaSt);
+ // return Object.assign(
+ // {},
+ // k,
+ // {
+ // peaks,
+ // mpyType: coupling.type,
+ // js: coupling.js,
+ // },
+ // );
+ // });
+ // const payload = Object.assign({}, mpySt, { stack: newStack });
+ // yield put({
+ // type: MULTIPLICITY.RESET_ALL_RDC,
+ // payload,
+ // });
+}
+function* resetOne(action) {
+ const xExtent = action.payload;
+ const metaSt = yield (0, _effects.select)(getMetaSt);
+ const mpySt = yield (0, _effects.select)(getMultiplicitySt);
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = mpySt;
+ const selectedMulti = multiplicities[curveIdx];
+ const {
+ stack
+ } = selectedMulti;
+ const newStack = stack.map(k => {
+ if (k.xExtent.xL === xExtent.xL && k.xExtent.xU === xExtent.xU) {
+ const {
+ peaks
+ } = k;
+ const coupling = (0, _multiplicity_calc.calcMpyCoup)(peaks, metaSt);
+ return Object.assign(
+ // eslint-disable-line
+ {}, k, {
+ peaks,
+ mpyType: coupling.type,
+ js: coupling.js
+ });
+ }
+ return k;
+ });
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ stack: newStack
+ }); // eslint-disable-line
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ const payload = Object.assign({}, mpySt, {
+ multiplicities: newMultiplicities
+ }); // eslint-disable-line
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.RESET_ONE_RDC,
+ payload
+ });
+}
+function* selectMpyType(action) {
+ const mpySt = yield (0, _effects.select)(getMultiplicitySt);
+ const metaSt = yield (0, _effects.select)(getMetaSt);
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ const {
+ multiplicities
+ } = mpySt;
+ const selectedMulti = multiplicities[curveIdx];
+ const {
+ mpyType,
+ xExtent
+ } = action.payload;
+ const {
+ stack
+ } = selectedMulti;
+ const newStack = stack.map(k => {
+ const isTargetStack = k.xExtent.xL === xExtent.xL && k.xExtent.xU === xExtent.xU;
+ if (isTargetStack) return (0, _multiplicity_manual.calcMpyManual)(k, mpyType, metaSt);
+ return k;
+ });
+ const newSelectedMulti = Object.assign({}, selectedMulti, {
+ stack: newStack
+ }); // eslint-disable-line
+ const newMultiplicities = [...multiplicities];
+ newMultiplicities[curveIdx] = newSelectedMulti;
+ const payload = Object.assign({}, mpySt, {
+ multiplicities: newMultiplicities
+ }); // eslint-disable-line
+
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.TYPE_SELECT_RDC,
+ payload
+ });
+}
+const multiplicitySagas = [(0, _effects.takeEvery)(_action_type.UI.SWEEP.SELECT_MULTIPLICITY, selectMpy), (0, _effects.takeEvery)(_action_type.MULTIPLICITY.PEAK_ADD_BY_UI_SAG, addUiPeakToStack), (0, _effects.takeEvery)(_action_type.MULTIPLICITY.PEAK_RM_BY_PANEL, rmPanelPeakFromStack), (0, _effects.takeEvery)(_action_type.MULTIPLICITY.PEAK_RM_BY_UI, rmUiPeakFromStack), (0, _effects.takeEvery)(_action_type.MULTIPLICITY.TYPE_SELECT, selectMpyType), (0, _effects.takeEvery)(_action_type.MULTIPLICITY.RESET_ONE, resetOne), (0, _effects.takeEvery)(_action_type.MANAGER.RESET_INIT_NMR, resetInitNmr)];
+var _default = exports.default = multiplicitySagas;
\ No newline at end of file
diff --git a/dist/sagas/saga_ui.js b/dist/sagas/saga_ui.js
new file mode 100644
index 00000000..adf16e94
--- /dev/null
+++ b/dist/sagas/saga_ui.js
@@ -0,0 +1,321 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _effects = require("redux-saga/effects");
+var _action_type = require("../constants/action_type");
+var _list_ui = require("../constants/list_ui");
+var _list_layout = require("../constants/list_layout");
+const getUiSt = state => state.ui;
+const getCurveSt = state => state.curve;
+const calcPeaks = payload => {
+ const {
+ xExtent,
+ yExtent,
+ dataPks
+ } = payload;
+ if (!dataPks) return [];
+ const {
+ xL,
+ xU
+ } = xExtent;
+ const {
+ yL,
+ yU
+ } = yExtent;
+ const peaks = dataPks.filter(p => xL <= p.x && p.x <= xU && yL <= p.y && p.y <= yU);
+ return peaks;
+};
+function* selectUiSweep(action) {
+ const uiSt = yield (0, _effects.select)(getUiSt);
+ const {
+ payload
+ } = action;
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ switch (uiSt.sweepType) {
+ case _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN:
+ yield (0, _effects.put)({
+ type: _action_type.UI.SWEEP.SELECT_ZOOMIN,
+ payload
+ });
+ break;
+ case _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET:
+ yield (0, _effects.put)({
+ type: _action_type.UI.SWEEP.SELECT_ZOOMRESET,
+ payload
+ });
+ break;
+ case _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD:
+ yield (0, _effects.put)({
+ type: _action_type.UI.SWEEP.SELECT_INTEGRATION,
+ payload: {
+ newData: payload,
+ curveIdx
+ }
+ });
+ break;
+ case _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_SWEEP_ADD:
+ const peaks = calcPeaks(payload); // eslint-disable-line
+ if (peaks.length === 0) {
+ break;
+ }
+ const newPayload = Object.assign({}, payload, {
+ peaks
+ }); // eslint-disable-line
+
+ yield (0, _effects.put)({
+ type: _action_type.UI.SWEEP.SELECT_INTEGRATION,
+ payload: {
+ newData: newPayload,
+ curveIdx
+ }
+ });
+ yield (0, _effects.put)({
+ type: _action_type.UI.SWEEP.SELECT_MULTIPLICITY,
+ payload: {
+ newData: newPayload,
+ curveIdx
+ }
+ });
+ break;
+ default:
+ break;
+ }
+ return null;
+}
+const getLayoutSt = state => state.layout;
+function* scrollUiWheel(action) {
+ const layoutSt = yield (0, _effects.select)(getLayoutSt);
+ const {
+ payload
+ } = action;
+ const {
+ xExtent,
+ yExtent,
+ direction
+ } = payload;
+ const {
+ yL,
+ yU
+ } = yExtent;
+ const [yeL, yeU] = [yL + (yU - yL) * 0.1, yU - (yU - yL) * 0.1];
+ const scale = direction ? 0.8 : 1.25;
+ let nextExtent = {
+ xExtent: false,
+ yExtent: false
+ };
+ let [nyeL, nyeU, h, nytL, nytU] = [0, 1, 1, 0, 1];
+ switch (layoutSt) {
+ case _list_layout.LIST_LAYOUT.IR:
+ case _list_layout.LIST_LAYOUT.RAMAN:
+ [nyeL, nyeU] = [yeL + (yeU - yeL) * (1 - scale), yeU];
+ h = nyeU - nyeL;
+ [nytL, nytU] = [nyeL - 0.125 * h, nyeU + 0.125 * h];
+ nextExtent = {
+ xExtent,
+ yExtent: {
+ yL: nytL,
+ yU: nytU
+ }
+ };
+ break;
+ case _list_layout.LIST_LAYOUT.MS:
+ [nyeL, nyeU] = [0, yeL + (yeU - yeL) * scale];
+ h = nyeU - nyeL;
+ [nytL, nytU] = [nyeL - 0.125 * h, nyeU + 0.125 * h];
+ nextExtent = {
+ xExtent,
+ yExtent: {
+ yL: nytL,
+ yU: nytU
+ }
+ };
+ break;
+ case _list_layout.LIST_LAYOUT.UVVIS:
+ case _list_layout.LIST_LAYOUT.HPLC_UVVIS:
+ case _list_layout.LIST_LAYOUT.TGA:
+ case _list_layout.LIST_LAYOUT.DSC:
+ case _list_layout.LIST_LAYOUT.XRD:
+ default:
+ [nyeL, nyeU] = [yeL, yeL + (yeU - yeL) * scale];
+ h = nyeU - nyeL;
+ [nytL, nytU] = [nyeL - 0.125 * h, nyeU + 0.125 * h];
+ nextExtent = {
+ xExtent,
+ yExtent: {
+ yL: nytL,
+ yU: nytU
+ }
+ };
+ break;
+ }
+ yield (0, _effects.put)({
+ type: _action_type.UI.SWEEP.SELECT_ZOOMIN,
+ payload: nextExtent
+ });
+}
+const getUiSweepType = state => state.ui.sweepType;
+function* clickUiTarget(action) {
+ const {
+ payload,
+ onPeak,
+ voltammetryPeakIdx,
+ onPecker
+ } = action;
+ const uiSweepType = yield (0, _effects.select)(getUiSweepType);
+ const curveSt = yield (0, _effects.select)(getCurveSt);
+ const {
+ curveIdx
+ } = curveSt;
+ if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD && !onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.EDITPEAK.ADD_POSITIVE,
+ payload: {
+ dataToAdd: payload,
+ curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_DELETE && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.EDITPEAK.ADD_NEGATIVE,
+ payload: {
+ dataToAdd: payload,
+ curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.SHIFT.SET_PEAK,
+ payload: {
+ dataToSet: payload,
+ curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_RM && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.INTEGRATION.RM_ONE,
+ payload: {
+ dataToRemove: payload,
+ curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_RM && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.INTEGRATION.RM_ONE,
+ payload: {
+ dataToRemove: payload,
+ curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.INTEGRATION.SET_REF,
+ payload: {
+ refData: payload,
+ curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_CLICK && onPeak) {
+ const {
+ xExtent,
+ xL,
+ xU
+ } = payload;
+ if (xExtent) {
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.ONE_CLICK_BY_UI,
+ payload: {
+ payloadData: xExtent,
+ curveIdx
+ }
+ });
+ } else if (xL && xU) {
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.ONE_CLICK_BY_UI,
+ payload: {
+ payloadData: {
+ xL,
+ xU
+ },
+ curveIdx
+ }
+ });
+ }
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_ADD) {
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.PEAK_ADD_BY_UI_SAG,
+ payload
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_RM && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.MULTIPLICITY.PEAK_RM_BY_UI,
+ payload
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MAX_PEAK && !onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_MAX_PEAK,
+ payload: {
+ peak: payload,
+ index: voltammetryPeakIdx,
+ jcampIdx: curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_MAX_PEAK,
+ payload: {
+ index: voltammetryPeakIdx,
+ jcampIdx: curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK && !onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_MIN_PEAK,
+ payload: {
+ peak: payload,
+ index: voltammetryPeakIdx,
+ jcampIdx: curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_MIN_PEAK,
+ payload: {
+ index: voltammetryPeakIdx,
+ jcampIdx: curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_PECKER && !onPecker) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.ADD_PECKER,
+ payload: {
+ peak: payload,
+ index: voltammetryPeakIdx,
+ jcampIdx: curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_PECKER && onPecker) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_PECKER,
+ payload: {
+ index: voltammetryPeakIdx,
+ jcampIdx: curveIdx
+ }
+ });
+ } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_SET_REF && onPeak) {
+ yield (0, _effects.put)({
+ type: _action_type.CYCLIC_VOLTA_METRY.SET_REF,
+ payload: {
+ index: voltammetryPeakIdx,
+ jcampIdx: curveIdx
+ }
+ });
+ }
+}
+const managerSagas = [(0, _effects.takeEvery)(_action_type.UI.CLICK_TARGET, clickUiTarget), (0, _effects.takeEvery)(_action_type.UI.SWEEP.SELECT, selectUiSweep), (0, _effects.takeEvery)(_action_type.UI.WHEEL.SCROLL, scrollUiWheel)];
+var _default = exports.default = managerSagas;
\ No newline at end of file
diff --git a/dist/setupTests.js b/dist/setupTests.js
new file mode 100644
index 00000000..fc453d7d
--- /dev/null
+++ b/dist/setupTests.js
@@ -0,0 +1,8 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+var _enzyme = _interopRequireDefault(require("enzyme"));
+var _enzymeAdapterReact = _interopRequireDefault(require("@wojtekmaj/enzyme-adapter-react-17"));
+_enzyme.default.configure({
+ adapter: new _enzymeAdapterReact.default()
+});
\ No newline at end of file
diff --git a/dist/third_party/jAnalyzer.js b/dist/third_party/jAnalyzer.js
new file mode 100644
index 00000000..7d25625b
--- /dev/null
+++ b/dist/third_party/jAnalyzer.js
@@ -0,0 +1,590 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+/* eslint-disable */
+// https://github.com/cheminfo-js/spectra/blob/master/packages/spectra-data/src/peakPicking/jAnalyzer.js
+
+/*
+ * This library implements the J analyser described by Cobas et al in the paper:
+ * A two-stage approach to automatic determination of 1H NMR coupling constants
+ */
+const patterns = ['s', 'd', 't', 'q', 'quint', 'h', 'sept', 'o', 'n'];
+let symRatio = 1.5;
+let maxErrorIter1 = 2.5; // Hz
+let maxErrorIter2 = 1; // Hz
+var _default = exports.default = {
+ /**
+ * The compilation process implements at the first stage a normalization procedure described by Golotvin et al.
+ * embedding in peak-component-counting method described by Hoyes et al.
+ * @param {object} signal
+ * @private
+ */
+ compilePattern: function compilePattern(signal) {
+ signal.multiplicity = 'm';
+ // 1.1 symmetrize
+ // It will add a set of peaks(signal.peaksComp) to the signal that will be used during
+ // the compilation process. The unit of those peaks will be in Hz
+ signal.symRank = symmetrizeChoiseBest(signal, maxErrorIter1, 1);
+ signal.asymmetric = true;
+ // Is the signal symmetric?
+ if (signal.symRank >= 0.95 && signal.peaksComp.length < 32) {
+ signal.asymmetric = false;
+ var i, j, n, P1, n2, maxFlagged;
+ let k = 1;
+ let Jc = [];
+
+ // Loop over the possible number of coupling contributing to the multiplet
+ for (n = 0; n < 9; n++) {
+ // 1.2 Normalize. It makes a deep copy of the peaks before to modify them.
+ let peaks = normalize(signal, n);
+ // signal.peaksCompX = peaks;
+ let validPattern = false; // It will change to true, when we find the good patter
+ // Lets check if the signal could be a singulet.
+ if (peaks.length === 1 && n === 0) {
+ validPattern = true;
+ } else {
+ if (peaks.length <= 1) {
+ continue;
+ }
+ }
+ // 1.3 Establish a range for the Heights Hi [peaks.intensity*0.85,peaks.intensity*1.15];
+ let ranges = getRanges(peaks);
+ n2 = Math.pow(2, n);
+
+ // 1.4 Find a combination of integer heights Hi, one from each Si, that sums to 2^n.
+ let heights = null;
+ let counter = 1;
+ while (!validPattern && (heights = getNextCombination(ranges, n2)) !== null && counter < 400) {
+ // 2.1 Number the components of the multiplet consecutively from 1 to 2n,
+ // starting at peak 1
+ let numbering = new Array(heights.length);
+ k = 1;
+ for (i = 0; i < heights.length; i++) {
+ numbering[i] = new Array(heights[i]);
+ for (j = 0; j < heights[i]; j++) {
+ numbering[i][j] = k++;
+ }
+ }
+ Jc = []; // The array to store the detected j-coupling
+ // 2.2 Set j = 1; J1 = P2 - P1. Flag components 1 and 2 as accounted for.
+ j = 1;
+ Jc.push(peaks[1].x - peaks[0].x);
+ P1 = peaks[0].x;
+ numbering[0].splice(0, 1); // Flagged
+ numbering[1].splice(0, 1); // Flagged
+ k = 1;
+ let nFlagged = 2;
+ maxFlagged = Math.pow(2, n) - 1;
+ while (Jc.length < n && nFlagged < maxFlagged && k < peaks.length) {
+ counter += 1;
+ // 4.1. Increment j. Set k to the number of the first unflagged component.
+ j++;
+ while (k < peaks.length && numbering[k].length === 0) {
+ k++;
+ }
+ if (k < peaks.length) {
+ // 4.2 Jj = Pk - P1.
+ Jc.push(peaks[k].x - peaks[0].x);
+ // Flag component k and, for each sum of the...
+ numbering[k].splice(0, 1); // Flageed
+ nFlagged++;
+ // Flag the other components of the multiplet
+ for (let u = 2; u <= j; u++) {
+ // TODO improve those loops
+ let jSum = 0;
+ for (i = 0; i < u; i++) {
+ jSum += Jc[i];
+ }
+ for (i = 1; i < numbering.length; i++) {
+ // Maybe 0.25 Hz is too much?
+ if (Math.abs(peaks[i].x - (P1 + jSum)) < 0.25) {
+ numbering[i].splice(0, 1); // Flageed
+ nFlagged++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ // Calculate the ideal patter by using the extracted j-couplings
+ let pattern = idealPattern(Jc);
+ // Compare the ideal pattern with the proposed intensities.
+ // All the intensities have to match to accept the multiplet
+ validPattern = true;
+ for (i = 0; i < pattern.length; i++) {
+ if (pattern[i].intensity !== heights[i]) {
+ validPattern = false;
+ }
+ }
+ }
+ // If we found a valid pattern we should inform about the pattern.
+ if (validPattern) {
+ updateSignal(signal, Jc);
+ }
+ }
+ }
+ // Before to return, change the units of peaksComp from Hz to PPM again
+ for (i = 0; i < signal.peaksComp.length; i++) {
+ signal.peaksComp[i].x /= signal.observe;
+ }
+ }
+};
+/**
+ * @private
+ * update the signal
+ * @param {*} signal
+ * @param {*} Jc
+ */
+function updateSignal(signal, Jc) {
+ // Update the limits of the signal
+ let peaks = signal.peaksComp; // Always in Hz
+ let nbPeaks = peaks.length;
+ signal.startX = peaks[0].x / signal.observe - peaks[0].width;
+ signal.stopX = peaks[nbPeaks - 1].x / signal.observe + peaks[nbPeaks - 1].width;
+
+ // signal.integralData.from = peaks[0].x / signal.observe - peaks[0].width * 3;
+ // signal.integralData.to =
+ // peaks[nbPeaks - 1].x / signal.observe + peaks[nbPeaks - 1].width * 3;
+
+ // Compile the pattern and format the constant couplings
+ signal.maskPattern = signal.mask2;
+ signal.multiplicity = abstractPattern(signal, Jc);
+ signal.pattern = signal.multiplicity; // Our library depends on this parameter, but it is old
+ // console.log(signal);
+ /* if (DEBUG) {
+ console.log('Final j-couplings: ' + JSON.stringify(Jc));
+ }*/
+}
+
+/**
+ * Returns the multiplet in the compact format
+ * @param {object} signal
+ * @param {object} Jc
+ * @return {string}
+ * @private
+ */
+function abstractPattern(signal, Jc) {
+ let tol = 0.05;
+ let i;
+ let pattern = '';
+ let cont = 1;
+ let newNmrJs = [];
+ if (Jc && Jc.length > 0) {
+ Jc.sort(function (a, b) {
+ return Math.abs(b) - Math.abs(a);
+ });
+ for (i = 0; i < Jc.length - 1; i++) {
+ if (Math.abs(Jc[i] - Jc[i + 1]) < tol) {
+ cont++;
+ } else {
+ newNmrJs.push({
+ coupling: Math.abs(Jc[i]),
+ multiplicity: patterns[cont]
+ });
+ pattern += patterns[cont];
+ cont = 1;
+ }
+ }
+ newNmrJs.push({
+ coupling: Math.abs(Jc[i]),
+ multiplicity: patterns[cont]
+ });
+ pattern += patterns[cont];
+ signal.nmrJs = newNmrJs;
+ } else {
+ pattern = 's';
+ // if (Math.abs(signal.startX - signal.stopX) * signal.observe > 16) {
+ // pattern = 'br s';
+ // }
+ }
+ return pattern;
+}
+
+/**
+ * This function creates an ideal pattern from the given J-couplings
+ * @private
+ * @param {Array} Jc
+ * @return {*[]}
+ * @private
+ */
+function idealPattern(Jc) {
+ let hsum = Math.pow(2, Jc.length);
+ let i, j;
+ let pattern = [{
+ x: 0,
+ intensity: hsum
+ }];
+ // To split the initial height
+ for (i = 0; i < Jc.length; i++) {
+ for (j = pattern.length - 1; j >= 0; j--) {
+ pattern.push({
+ x: pattern[j].x + Jc[i] / 2,
+ intensity: pattern[j].intensity / 2
+ });
+ pattern[j].x = pattern[j].x - Jc[i] / 2;
+ pattern[j].intensity = pattern[j].intensity / 2;
+ }
+ }
+ // To sum the heights in the same positions
+ pattern.sort(function compare(a, b) {
+ return a.x - b.x;
+ });
+ for (j = pattern.length - 2; j >= 0; j--) {
+ if (Math.abs(pattern[j].x - pattern[j + 1].x) < 0.1) {
+ pattern[j].intensity += pattern[j + 1].intensity;
+ pattern.splice(j + 1, 1);
+ }
+ }
+ return pattern;
+}
+
+/**
+ * Find a combination of integer heights Hi, one from each Si, that sums to 2n.
+ * @param {object} ranges
+ * @param {number} value
+ * @return {*}
+ * @private
+ */
+function getNextCombination(ranges, value) {
+ let half = Math.ceil(ranges.values.length * 0.5);
+ let lng = ranges.values.length;
+ let sum = 0;
+ let i, ok;
+ while (sum !== value) {
+ // Update the indexes to point at the next possible combination
+ ok = false;
+ while (!ok) {
+ ok = true;
+ ranges.currentIndex[ranges.active]++;
+ if (ranges.currentIndex[ranges.active] >= ranges.values[ranges.active].length) {
+ // In this case, there is no more possible combinations
+ if (ranges.active + 1 === half) {
+ return null;
+ } else {
+ // If this happens we need to try the next active peak
+ ranges.currentIndex[ranges.active] = 0;
+ ok = false;
+ ranges.active++;
+ }
+ } else {
+ ranges.active = 0;
+ }
+ }
+ // Sum the heights for this combination
+ sum = 0;
+ for (i = 0; i < half; i++) {
+ sum += ranges.values[i][ranges.currentIndex[i]] * 2;
+ }
+ if (ranges.values.length % 2 !== 0) {
+ sum -= ranges.values[half - 1][ranges.currentIndex[half - 1]];
+ }
+ }
+ // If the sum is equal to the expected value, fill the array to return
+ if (sum === value) {
+ let heights = new Array(lng);
+ for (i = 0; i < half; i++) {
+ heights[i] = ranges.values[i][ranges.currentIndex[i]];
+ heights[lng - i - 1] = ranges.values[i][ranges.currentIndex[i]];
+ }
+ return heights;
+ }
+ return null;
+}
+
+/**
+ * This function generates the possible values that each peak can contribute
+ * to the multiplet.
+ * @param {Array} peaks Array of objects with peaks information {intensity}
+ * @return {{values: Array, currentIndex: Array, active: number}}
+ * @private
+ */
+function getRanges(peaks) {
+ let ranges = new Array(peaks.length);
+ let currentIndex = new Array(peaks.length);
+ let min, max;
+ ranges[0] = [1];
+ ranges[peaks.length - 1] = [1];
+ currentIndex[0] = -1;
+ currentIndex[peaks.length - 1] = 0;
+ for (let i = 1; i < peaks.length - 1; i++) {
+ min = Math.round(peaks[i].intensity * 0.85);
+ max = Math.round(peaks[i].intensity * 1.15);
+ ranges[i] = [];
+ for (let j = min; j <= max; j++) {
+ ranges[i].push(j);
+ }
+ currentIndex[i] = 0;
+ }
+ return {
+ values: ranges,
+ currentIndex: currentIndex,
+ active: 0
+ };
+}
+/**
+ * Performs a symmetrization of the signal by using different aproximations to the center.
+ * It will return the result of the symmetrization that removes less peaks from the signal
+ * @param {object} signal
+ * @param {number} maxError
+ * @param {number} iteration
+ * @return {*}
+ * @private
+ */
+function symmetrizeChoiseBest(signal, maxError, iteration) {
+ let symRank1 = symmetrize(signal, maxError, iteration);
+ let tmpPeaks = signal.peaksComp;
+ let tmpMask = signal.mask;
+ let cs = signal.delta1;
+ signal.delta1 = (signal.peaks[0].x + signal.peaks[signal.peaks.length - 1].x) / 2;
+ let symRank2 = symmetrize(signal, maxError, iteration);
+ if (signal.peaksComp.length > tmpPeaks.length) {
+ return symRank2;
+ } else {
+ signal.delta1 = cs;
+ signal.peaksComp = tmpPeaks;
+ signal.mask = tmpMask;
+ return symRank1;
+ }
+}
+
+/**
+ * This function will return a set of symmetric peaks that will
+ * be the enter point for the patter compilation process.
+ * @param {object} signal
+ * @param {number} maxError
+ * @param {number} iteration
+ * @return {number}
+ * @private
+ */
+function symmetrize(signal, maxError, iteration) {
+ // Before to symmetrize we need to keep only the peaks that possibly conforms the multiplete
+ let max, min, avg, ratio, avgWidth, i;
+ let peaks = new Array(signal.peaks.length);
+ // Make a deep copy of the peaks and convert PPM ot HZ
+ for (i = 0; i < peaks.length; i++) {
+ peaks[i] = {
+ x: signal.peaks[i].x * signal.observe,
+ intensity: signal.peaks[i].intensity,
+ width: signal.peaks[i].width
+ };
+ }
+ // Join the peaks that are closer than 0.25 Hz
+ for (i = peaks.length - 2; i >= 0; i--) {
+ if (Math.abs(peaks[i].x - peaks[i + 1].x) < 0.25) {
+ peaks[i].x = peaks[i].x * peaks[i].intensity + peaks[i + 1].x * peaks[i + 1].intensity;
+ peaks[i].intensity = peaks[i].intensity + peaks[i + 1].intensity;
+ peaks[i].x /= peaks[i].intensity;
+ peaks[i].intensity /= 2;
+ peaks[i].width += peaks[i + 1].width;
+ peaks.splice(i + 1, 1);
+ }
+ }
+ signal.peaksComp = peaks;
+ let nbPeaks = peaks.length;
+ let mask = new Array(nbPeaks);
+ signal.mask = mask;
+ let left = 0;
+ let right = peaks.length - 1;
+ let cs = signal.delta1 * signal.observe;
+ let middle = [(peaks[0].x + peaks[nbPeaks - 1].x) / 2, 1];
+ maxError = error(Math.abs(cs - middle[0]));
+ let heightSum = 0;
+ // We try to symmetrize the extreme peaks. We consider as candidates for symmetricing those which have
+ // ratio smaller than 3
+ for (i = 0; i < nbPeaks; i++) {
+ mask[i] = true;
+ heightSum += signal.peaks[i].intensity;
+ }
+ while (left <= right) {
+ mask[left] = true;
+ mask[right] = true;
+ if (left === right) {
+ if (nbPeaks > 2 && Math.abs(peaks[left].x - cs) > maxError) {
+ mask[left] = false;
+ }
+ } else {
+ max = Math.max(peaks[left].intensity, peaks[right].intensity);
+ min = Math.min(peaks[left].intensity, peaks[right].intensity);
+ ratio = max / min;
+ if (ratio > symRatio) {
+ if (peaks[left].intensity === min) {
+ mask[left] = false;
+ right++;
+ } else {
+ mask[right] = false;
+ left--;
+ }
+ } else {
+ let diffL = Math.abs(peaks[left].x - cs);
+ let diffR = Math.abs(peaks[right].x - cs);
+ if (Math.abs(diffL - diffR) < maxError) {
+ avg = Math.min(peaks[left].intensity, peaks[right].intensity);
+ avgWidth = Math.min(peaks[left].width, peaks[right].width);
+ peaks[left].intensity = peaks[right].intensity = avg;
+ peaks[left].width = peaks[right].width = avgWidth;
+ middle = [middle[0] + (peaks[right].x + peaks[left].x) / 2, middle[1] + 1];
+ } else {
+ if (Math.max(diffL, diffR) === diffR) {
+ mask[right] = false;
+ left--;
+ } else {
+ mask[left] = false;
+ right++;
+ }
+ }
+ }
+ }
+ left++;
+ right--;
+ // Only alter cs if it is the first iteration of the sym process.
+ if (iteration === 1) {
+ cs = chemicalShift(peaks, mask);
+ // There is not more available peaks
+ if (isNaN(cs)) {
+ return 0;
+ }
+ }
+ maxError = error(Math.abs(cs - middle[0] / middle[1]));
+ }
+ // To remove the weak peaks and recalculate the cs
+ for (i = nbPeaks - 1; i >= 0; i--) {
+ if (mask[i] === false) {
+ peaks.splice(i, 1);
+ }
+ }
+ cs = chemicalShift(peaks);
+ if (isNaN(cs)) {
+ return 0;
+ }
+ signal.delta1 = cs / signal.observe;
+ // Now, the peak should be symmetric in heights, but we need to know if it is symmetric in x
+ let symFactor = 0;
+ let weight = 0;
+ if (peaks.length > 1) {
+ for (i = Math.ceil(peaks.length / 2) - 1; i >= 0; i--) {
+ symFactor += (3 + Math.min(Math.abs(peaks[i].x - cs), Math.abs(peaks[peaks.length - 1 - i].x - cs))) / (3 + Math.max(Math.abs(peaks[i].x - cs), Math.abs(peaks[peaks.length - 1 - i].x - cs))) * peaks[i].intensity;
+ weight += peaks[i].intensity;
+ }
+ symFactor /= weight;
+ } else {
+ if (peaks.length === 1) {
+ symFactor = 1;
+ }
+ }
+ let newSumHeights = 0;
+ for (i = 0; i < peaks.length; i++) {
+ newSumHeights += peaks[i].intensity;
+ }
+ symFactor -= (heightSum - newSumHeights) / heightSum * 0.12; // Removed peaks penalty
+ // Sometimes we need a second opinion after the first symmetrization.
+ if (symFactor > 0.8 && symFactor < 0.97 && iteration < 2) {
+ return symmetrize(signal, maxErrorIter2, 2);
+ } else {
+ // Center the given pattern at cs and symmetrize x
+ if (peaks.length > 1) {
+ let dxi;
+ for (i = Math.ceil(peaks.length / 2) - 1; i >= 0; i--) {
+ dxi = (peaks[i].x - peaks[peaks.length - 1 - i].x) / 2.0;
+ peaks[i].x = cs + dxi;
+ peaks[peaks.length - 1 - i].x = cs - dxi;
+ }
+ }
+ }
+ return symFactor;
+}
+/**
+ * Error validator
+ * @param {number} value
+ * @return {number}
+ * @private
+ */
+function error(value) {
+ let maxError = value * 2.5;
+ if (maxError < 0.75) {
+ maxError = 0.75;
+ }
+ if (maxError > 3) {
+ maxError = 3;
+ }
+ return maxError;
+}
+/**
+ * @private
+ * 2 stages normalizarion of the peaks heights to Math.pow(2,n).
+ * Creates a new mask with the peaks that could contribute to the multiplete
+ * @param {object} signal
+ * @param {number} n
+ * @return {*}
+ */
+function normalize(signal, n) {
+ // Perhaps this is slow
+ let peaks = JSON.parse(JSON.stringify(signal.peaksComp));
+ let norm = 0;
+ let norm2 = 0;
+ for (var i = 0; i < peaks.length; i++) {
+ norm += peaks[i].intensity;
+ }
+ norm = Math.pow(2, n) / norm;
+ signal.mask2 = JSON.parse(JSON.stringify(signal.mask));
+ let index = signal.mask2.length - 1;
+ for (i = peaks.length - 1; i >= 0; i--) {
+ peaks[i].intensity *= norm;
+ while (index >= 0 && signal.mask2[index] === false) {
+ index--;
+ }
+ if (peaks[i].intensity < 0.75) {
+ peaks.splice(i, 1);
+ signal.mask2[index] = false;
+ } else {
+ norm2 += peaks[i].intensity;
+ }
+ index--;
+ }
+ norm2 = Math.pow(2, n) / norm2;
+ for (i = peaks.length - 1; i >= 0; i--) {
+ peaks[i].intensity *= norm2;
+ }
+ return peaks;
+}
+
+/**
+ * @private
+ * Calculates the chemical shift as the weighted sum of the peaks
+ * @param {Array} peaks
+ * @param {Array} mask
+ * @return {number}
+ */
+function chemicalShift(peaks, mask) {
+ let sum = 0;
+ let cs = 0;
+ let i, area;
+ if (mask) {
+ for (i = 0; i < peaks.length; i++) {
+ if (mask[i] === true) {
+ area = getArea(peaks[i]);
+ sum += area;
+ cs += area * peaks[i].x;
+ }
+ }
+ } else {
+ for (i = 0; i < peaks.length; i++) {
+ area = getArea(peaks[i]);
+ sum += area;
+ cs += area * peaks[i].x;
+ }
+ }
+ return cs / sum;
+}
+
+/**
+ * Return the area of a Lorentzian function
+ * @param {object} peak - object with peak information
+ * @return {number}
+ * @private
+ */
+function getArea(peak) {
+ return Math.abs(peak.intensity * peak.width * 1.57); // 1.772453851);
+}
\ No newline at end of file
diff --git a/dist/third_party/peakInterval.js b/dist/third_party/peakInterval.js
new file mode 100644
index 00000000..406996d0
--- /dev/null
+++ b/dist/third_party/peakInterval.js
@@ -0,0 +1,105 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.getPeakIntervals = void 0;
+var _mlSavitzkyGolayGeneralized = _interopRequireDefault(require("ml-savitzky-golay-generalized"));
+// https://github.com/mljs/global-spectral-deconvolution/blob/master/src/gsd.js
+
+/* eslint-disable no-plusplus, operator-linebreak */
+
+const options = {
+ sgOptions: {
+ windowSize: 9,
+ polynomial: 3
+ },
+ minMaxRatio: 0.00025,
+ broadRatio: 0.0,
+ maxCriteria: true,
+ smoothY: true,
+ realTopDetection: false,
+ heightFactor: 0,
+ boundaries: false,
+ derivativeThreshold: -1
+};
+const getPeakIntervals = entity => {
+ const data = entity.spectra[0].data[0];
+ const X = data.x;
+ const dX = X[1] - X[0];
+ const Y = (0, _mlSavitzkyGolayGeneralized.default)(data.y, data.x, {
+ windowSize: options.sgOptions.windowSize,
+ polynomial: options.sgOptions.polynomial,
+ derivative: 0
+ });
+ const dY = (0, _mlSavitzkyGolayGeneralized.default)(data.y, data.x, {
+ windowSize: options.sgOptions.windowSize,
+ polynomial: options.sgOptions.polynomial,
+ derivative: 1
+ });
+ const ddY = (0, _mlSavitzkyGolayGeneralized.default)(data.y, data.x, {
+ windowSize: options.sgOptions.windowSize,
+ polynomial: options.sgOptions.polynomial,
+ derivative: 2
+ });
+ let maxDdy = 0;
+ let maxY = 0;
+ for (let i = 0; i < Y.length; i++) {
+ if (Math.abs(ddY[i]) > maxDdy) {
+ maxDdy = Math.abs(ddY[i]);
+ }
+ if (Math.abs(Y[i]) > maxY) {
+ maxY = Math.abs(Y[i]);
+ }
+ }
+ let lastMax = null;
+ let lastMin = null;
+ const minddY = new Array(Y.length - 2);
+ const intervalL = new Array(Y.length);
+ const intervalR = new Array(Y.length);
+ const broadMask = new Array(Y.length - 2);
+ let minddYLen = 0;
+ let intervalLLen = 0;
+ let intervalRLen = 0;
+ let broadMaskLen = 0;
+ for (let i = 1; i < Y.length - 1; ++i) {
+ // filter based on derivativeThreshold
+ if (Math.abs(dY[i]) > options.derivativeThreshold) {
+ // Minimum in first derivative
+ if (dY[i] < dY[i - 1] && dY[i] <= dY[i + 1] || dY[i] <= dY[i - 1] && dY[i] < dY[i + 1]) {
+ lastMin = {
+ x: X[i],
+ index: i
+ };
+ if (dX > 0 && lastMax !== null) {
+ intervalL[intervalLLen++] = lastMax;
+ intervalR[intervalRLen++] = lastMin;
+ }
+ }
+
+ // Maximum in first derivative
+ if (dY[i] >= dY[i - 1] && dY[i] > dY[i + 1] || dY[i] > dY[i - 1] && dY[i] >= dY[i + 1]) {
+ lastMax = {
+ x: X[i],
+ index: i
+ };
+ if (dX < 0 && lastMin !== null) {
+ intervalL[intervalLLen++] = lastMax;
+ intervalR[intervalRLen++] = lastMin;
+ }
+ }
+ }
+ // Minimum in second derivative
+ if (ddY[i] < ddY[i - 1] && ddY[i] < ddY[i + 1]) {
+ // TODO should we change this to have 3 arrays ? Huge overhead creating arrays
+ minddY[minddYLen++] = i; // ( [X[i], Y[i], i] );
+ broadMask[broadMaskLen++] = Math.abs(ddY[i]) <= options.broadRatio * maxDdy;
+ }
+ }
+ return {
+ intervalL,
+ intervalR
+ };
+};
+exports.getPeakIntervals = getPeakIntervals;
\ No newline at end of file
diff --git a/src/__tests__/units/actions/integration.test.tsx b/src/__tests__/units/actions/integration.test.tsx
index 859f35ac..125af940 100644
--- a/src/__tests__/units/actions/integration.test.tsx
+++ b/src/__tests__/units/actions/integration.test.tsx
@@ -1,5 +1,10 @@
import {
- clearIntegrationAll, setIntegrationFkr, sweepIntegration,
+ addVisualSplitLine,
+ clearIntegrationAll,
+ removeVisualSplitLine,
+ setIntegrationFkr,
+ splitIntegration,
+ sweepIntegration,
} from "../../../actions/integration";
import { INTEGRATION } from "../../../constants/action_type";
@@ -23,4 +28,22 @@ describe('Test redux action for integrations', () => {
expect(type).toEqual(INTEGRATION.CLEAR_ALL)
expect(payload).toEqual(payloadToBeSent)
})
+
+ it('Split integration', () => {
+ const { type, payload } = splitIntegration(payloadToBeSent)
+ expect(type).toEqual(INTEGRATION.SPLIT)
+ expect(payload).toEqual(payloadToBeSent)
+ })
+
+ it('Add visual split line', () => {
+ const { type, payload } = addVisualSplitLine(payloadToBeSent)
+ expect(type).toEqual(INTEGRATION.ADD_VISUAL_SPLIT)
+ expect(payload).toEqual(payloadToBeSent)
+ })
+
+ it('Remove visual split line', () => {
+ const { type, payload } = removeVisualSplitLine(payloadToBeSent)
+ expect(type).toEqual(INTEGRATION.RM_VISUAL_SPLIT)
+ expect(payload).toEqual(payloadToBeSent)
+ })
})
diff --git a/src/__tests__/units/helpers/chem.test.tsx b/src/__tests__/units/helpers/chem.test.tsx
index 743fad87..1a801491 100644
--- a/src/__tests__/units/helpers/chem.test.tsx
+++ b/src/__tests__/units/helpers/chem.test.tsx
@@ -3,6 +3,7 @@ import {
ToFrequency, Convert2Scan, Convert2Thres, GetComparisons, Convert2DValue,
GetCyclicVoltaRatio, GetCyclicVoltaPeakSeparate, convertTopic,
Convert2MaxMinPeak, Feature2MaxMinPeak, GetCyclicVoltaShiftOffset, GetCyclicVoltaPreviousShift,
+ buildIntegFeature,
} from "../../../helpers/chem";
import nmr1HJcamp from "../../fixtures/nmr1h_jcamp";
import aifJcamp1 from "../../fixtures/aif_jcamp_1";
@@ -519,6 +520,82 @@ describe('Test for chem helper', () => {
})
})
+ describe('Test build integration feature with persistent visualSplitGroupId', () => {
+ const linearSpectra = [{ data: [{ x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], y: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0] }] }]
+ const buildJcamp = (records: Record) => ({
+ info: { ...records },
+ spectra: [{}],
+ })
+
+ it('returns integrations without groupId for legacy JCAMPs', () => {
+ const jcamp: any = buildJcamp({
+ $OBSERVEDINTEGRALS: '\n0, 10, 5, 5',
+ })
+ const feature = buildIntegFeature(jcamp, linearSpectra)
+ expect(feature.stack).toHaveLength(1)
+ expect(feature.stack[0]).toMatchObject({ xL: 0, xU: 10 })
+ expect(feature.stack[0].visualSplitGroupId).toBeUndefined()
+ })
+
+ it('attaches a visualSplitGroupId from the JCAMP record', () => {
+ const jcamp: any = buildJcamp({
+ $OBSERVEDINTEGRALS: '\n0, 4, 2, 2\n4, 10, 3, 3',
+ $OBSERVEDINTEGRALSGROUPS: '\n0, vsg-abc-1\n1, vsg-abc-1',
+ })
+ const feature = buildIntegFeature(jcamp, linearSpectra)
+ expect(feature.stack[0].visualSplitGroupId).toBe('vsg-abc-1')
+ expect(feature.stack[1].visualSplitGroupId).toBe('vsg-abc-1')
+ })
+
+ it('preserves alphanumeric and dash characters in the groupId token', () => {
+ const jcamp: any = buildJcamp({
+ $OBSERVEDINTEGRALS: '\n0, 10, 5, 5',
+ $OBSERVEDINTEGRALSGROUPS: '\n0, vsg-token_42-XYZ',
+ })
+ const feature = buildIntegFeature(jcamp, linearSpectra)
+ expect(feature.stack[0].visualSplitGroupId).toBe('vsg-token_42-XYZ')
+ })
+
+ it('ignores groupId rows pointing to non existing integrations', () => {
+ const jcamp: any = buildJcamp({
+ $OBSERVEDINTEGRALS: '\n0, 10, 5, 5',
+ $OBSERVEDINTEGRALSGROUPS: '\n5, vsg-orphan',
+ })
+ const feature = buildIntegFeature(jcamp, linearSpectra)
+ expect(feature.stack[0].visualSplitGroupId).toBeUndefined()
+ })
+
+ it('keeps the groupId after the area normalisation pass', () => {
+ const jcamp: any = buildJcamp({
+ $OBSERVEDINTEGRALS: '\n0, 10, 5, 5',
+ $OBSERVEDINTEGRALSGROUPS: '\n0, vsg-abc',
+ })
+ const feature = buildIntegFeature(jcamp, linearSpectra)
+ expect(feature.stack[0].visualSplitGroupId).toBe('vsg-abc')
+ expect(feature.stack[0].area).toBeDefined()
+ })
+
+ it('parses GROUPS records that have no leading newline (header-less convention)', () => {
+ const jcamp: any = buildJcamp({
+ $OBSERVEDINTEGRALS: '\n0, 4, 2, 2\n4, 10, 3, 3',
+ $OBSERVEDINTEGRALSGROUPS: '0, vsg-headerless\n1, vsg-headerless',
+ })
+ const feature = buildIntegFeature(jcamp, linearSpectra)
+ expect(feature.stack[0].visualSplitGroupId).toBe('vsg-headerless')
+ expect(feature.stack[1].visualSplitGroupId).toBe('vsg-headerless')
+ })
+
+ it('ignores an arbitrary header line and still maps all valid rows', () => {
+ const jcamp: any = buildJcamp({
+ $OBSERVEDINTEGRALS: '\n0, 4, 2, 2\n4, 10, 3, 3',
+ $OBSERVEDINTEGRALSGROUPS: ' (X Y)\n0, vsg-hdr\n1, vsg-hdr',
+ })
+ const feature = buildIntegFeature(jcamp, linearSpectra)
+ expect(feature.stack[0].visualSplitGroupId).toBe('vsg-hdr')
+ expect(feature.stack[1].visualSplitGroupId).toBe('vsg-hdr')
+ })
+ })
+
describe('Test get previous offset CV layout', () => {
const voltaData = {"spectraList":[{"list":[{"min":{"x":-1.5404,"y":-0.00000307144},"max":{"x":0.10003,"y":0.00000285434},"isRef":true,"e12":-0.720185,"pecker":{"x":0.380242,"y":0.00000164361}}],"selectedIdx":0,"isWorkMaxPeak":true,"jcampIdx":0,"shift":{"ref":{"min":{"x":-1.5404,"y":-0.00000307144},"max":{"x":0.10003,"y":0.00000285434},"isRef":true,"e12":-0.720185,"pecker":{"x":0.380242,"y":0.00000164361}},"val":0, "prevValue":0.5},"hasRefPeak":true},{"list":[{"min":{"x":-1.48904,"y":-0.000033747399999999995},"max":{"x":0.929483,"y":0.00023741},"isRef":true,"e12":-0.27977849999999993}],"selectedIdx":0,"isWorkMaxPeak":true,"jcampIdx":1,"shift":{"ref":{"min":{"x":-1.48904,"y":-0.000033747399999999995},"max":{"x":0.929483,"y":0.00023741},"isRef":true,"e12":-0.27977849999999993},"val":1.5}},{"list":[{"min":{"x":0.45977,"y":-0.000226347},"max":{"x":1.00943,"y":0.000371349},"isRef":false,"e12":0.7346}],"selectedIdx":0,"isWorkMaxPeak":true,"jcampIdx":2,"shift":{"ref":null,"val":0}}]}
const voltaDataNoRef = {"spectraList":[{"list":[{"min":{"x":-1.5404,"y":-0.00000307144},"max":{"x":0.10003,"y":0.00000285434},"isRef":false,"e12":-0.720185,"pecker":{"x":0.380242,"y":0.00000164361}}],"selectedIdx":0,"isWorkMaxPeak":true,"jcampIdx":0,"shift":{"ref":null,"val":0, "prevValue":0.5},"hasRefPeak":false},{"list":[{"min":{"x":-1.48904,"y":-0.000033747399999999995},"max":{"x":0.929483,"y":0.00023741},"isRef":true,"e12":-0.27977849999999993}],"selectedIdx":0,"isWorkMaxPeak":true,"jcampIdx":1,"shift":{"ref":null,"val":1.5}},{"list":[{"min":{"x":0.45977,"y":-0.000226347},"max":{"x":1.00943,"y":0.000371349},"isRef":false,"e12":0.7346}],"selectedIdx":0,"isWorkMaxPeak":true,"jcampIdx":2,"shift":{"ref":null,"val":0}}]}
diff --git a/src/__tests__/units/helpers/integration.test.tsx b/src/__tests__/units/helpers/integration.test.tsx
index 4a46892b..8c28da53 100644
--- a/src/__tests__/units/helpers/integration.test.tsx
+++ b/src/__tests__/units/helpers/integration.test.tsx
@@ -1,4 +1,18 @@
-import { calcArea, getAbsoluteArea, getArea } from "../../../helpers/integration";
+import {
+ buildSplitIntervals,
+ calcArea,
+ generateVisualSplitGroupId,
+ getAbsoluteArea,
+ getAbsoluteAreaWithBaseline,
+ getArea,
+ getIntegrationPoints,
+ getLinearBaseline,
+ getSplitAreas,
+ getVisualSplitGroupBoundaries,
+ getVisualSplitGroups,
+ normalizeSplitLines,
+ splitAreaProportionally,
+} from "../../../helpers/integration";
describe('Test helper for integration', () => {
describe('Test get area', () => {
@@ -25,6 +39,171 @@ describe('Test helper for integration', () => {
})
})
+ describe('Test AUC baseline', () => {
+ it('starts the baseline at the first integration point, not at y=0', () => {
+ const points = getIntegrationPoints(0, 3, [
+ {x: 1, y: 10},
+ {x: 2, y: 12},
+ ]);
+ const baselineY = getLinearBaseline(points);
+
+ expect(baselineY(points[0])).toEqual(points[0].y);
+ expect(baselineY(points[1])).toEqual(points[1].y);
+ })
+
+ it('uses a deterministic linear baseline for interior points', () => {
+ const points = getIntegrationPoints(0, 4, [
+ {x: 1, y: 10},
+ {x: 2, y: 14},
+ {x: 3, y: 12},
+ ]);
+ const baselineY = getLinearBaseline(points);
+
+ expect(baselineY(points[1])).toEqual(11);
+ })
+ })
+
+ describe('Test visual split areas', () => {
+ const splitData = [
+ {x: 1, y: 0, k: 1},
+ {x: 2, y: 4, k: 2},
+ {x: 3, y: 4, k: 3},
+ {x: 4, y: 4, k: 4},
+ {x: 5, y: 0, k: 5},
+ ];
+
+ it('builds sorted intervals from internal split lines only', () => {
+ expect(buildSplitIntervals(0, 10, [8, -1, 4, 11])).toEqual([
+ { xL: 0, xU: 4 },
+ { xL: 4, xU: 8 },
+ { xL: 8, xU: 10 },
+ ]);
+ })
+
+ it('calculates split areas with the global integration baseline', () => {
+ const mainPoints = getIntegrationPoints(0, 6, splitData);
+ const baselineY = getLinearBaseline(mainPoints);
+
+ expect(getAbsoluteAreaWithBaseline(2.5, 6, splitData, baselineY)).toEqual(4);
+ expect(getSplitAreas(0, 6, [2.5], splitData)).toEqual([
+ { xL: 0, xU: 2.5, area: 1, absoluteArea: 4 },
+ { xL: 2.5, xU: 6, area: 2, absoluteArea: 4 },
+ ]);
+ })
+ })
+
+ describe('Test visual split groups', () => {
+ it('returns no groups for an empty stack', () => {
+ expect(getVisualSplitGroups([])).toEqual([])
+ expect(getVisualSplitGroups(null as any)).toEqual([])
+ })
+
+ it('returns singleton groups for items without groupId', () => {
+ const stack = [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0 },
+ { xL: 5, xU: 9, area: 4, absoluteArea: 0 },
+ ]
+ const groups = getVisualSplitGroups(stack)
+ expect(groups).toHaveLength(2)
+ expect(groups[0].isMerged).toBe(false)
+ expect(groups[1].isMerged).toBe(false)
+ })
+
+ it('groups consecutive items sharing a visualSplitGroupId', () => {
+ const stack = [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 7, area: 3, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 8, xU: 10, area: 2, absoluteArea: 0 },
+ ]
+ const groups = getVisualSplitGroups(stack)
+ expect(groups).toHaveLength(2)
+ expect(groups[0].items).toHaveLength(2)
+ expect(groups[0].xL).toEqual(0)
+ expect(groups[0].xU).toEqual(7)
+ expect(groups[0].isMerged).toBe(true)
+ expect(groups[1].isMerged).toBe(false)
+ })
+
+ it('treats non-consecutive items with the same id as separate groups', () => {
+ const stack = [
+ { xL: 0, xU: 3, area: 3, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 6, area: 2, absoluteArea: 0 },
+ { xL: 7, xU: 10, area: 3, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ]
+ const groups = getVisualSplitGroups(stack)
+ expect(groups).toHaveLength(3)
+ expect(groups[0].isMerged).toBe(false)
+ expect(groups[2].isMerged).toBe(false)
+ })
+
+ it('returns the internal boundaries between merged items', () => {
+ const stack = [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 7, area: 3, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 7, xU: 10, area: 3, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ]
+ const groups = getVisualSplitGroups(stack)
+ expect(getVisualSplitGroupBoundaries(groups[0])).toEqual([4, 7])
+ })
+
+ it('returns no boundaries for non-merged groups', () => {
+ const groups = getVisualSplitGroups([{ xL: 0, xU: 4, area: 4, absoluteArea: 0 }])
+ expect(getVisualSplitGroupBoundaries(groups[0])).toEqual([])
+ })
+ })
+
+ describe('Test generate visual split group id', () => {
+ it('produces unique stable ids', () => {
+ const a = generateVisualSplitGroupId()
+ const b = generateVisualSplitGroupId()
+ expect(typeof a).toBe('string')
+ expect(a.startsWith('vsg-')).toBe(true)
+ expect(a).not.toEqual(b)
+ })
+ })
+
+ describe('Test normalize split lines', () => {
+ it('returns an empty array when value is missing or invalid', () => {
+ expect(normalizeSplitLines(undefined)).toEqual([])
+ expect(normalizeSplitLines(null as any)).toEqual([])
+ expect(normalizeSplitLines('foo' as any)).toEqual([])
+ expect(normalizeSplitLines([NaN, undefined, null, 'x'] as any)).toEqual([])
+ })
+
+ it('keeps finite values, deduplicates them and returns ascending order', () => {
+ expect(normalizeSplitLines([4, 2, 4, 1.5, NaN, '3' as any])).toEqual([1.5, 2, 3, 4])
+ })
+ })
+
+ describe('Test split area proportionally', () => {
+ it('preserves the original total exactly while keeping the data ratio', () => {
+ const result = splitAreaProportionally(300, 200, 40)
+ expect(result.left + result.right).toBeCloseTo(300, 9)
+ expect(result.left / result.right).toBeCloseTo(200 / 40, 9)
+ })
+
+ it('returns zeros when the original total is zero', () => {
+ expect(splitAreaProportionally(0, 10, 20)).toEqual({ left: 0, right: 0 })
+ })
+
+ it('splits evenly when the raw measurements cannot infer a proportion', () => {
+ expect(splitAreaProportionally(8, 0, 0)).toEqual({ left: 4, right: 4 })
+ })
+
+ it('handles a single non-zero side by giving all the mass to it', () => {
+ const result = splitAreaProportionally(10, 0, 4)
+ expect(result.left).toEqual(0)
+ expect(result.right).toEqual(10)
+ })
+
+ it('gracefully treats non finite inputs as zero', () => {
+ expect(splitAreaProportionally(NaN as any, 1, 1)).toEqual({ left: 0, right: 0 })
+ const result = splitAreaProportionally(10, NaN as any, 5)
+ expect(result.left).toEqual(0)
+ expect(result.right).toEqual(10)
+ })
+ })
+
describe('Test calculate area', () => {
it('Do not ignore ref', () => {
const data = { area: 0.5 }
diff --git a/src/__tests__/units/helpers/integration_draft.test.tsx b/src/__tests__/units/helpers/integration_draft.test.tsx
new file mode 100644
index 00000000..ab4cca80
--- /dev/null
+++ b/src/__tests__/units/helpers/integration_draft.test.tsx
@@ -0,0 +1,50 @@
+import {
+ clearPendingIntegrationDraft,
+ confirmCancelPendingIntegration,
+ forgetPendingIntegrationDraft,
+ hasPendingIntegrationDraft,
+ setPendingIntegrationDraft,
+} from "../../../helpers/integration_draft";
+
+describe('Test helper for pending integration draft', () => {
+ afterEach(() => {
+ jest.restoreAllMocks();
+ forgetPendingIntegrationDraft();
+ });
+
+ it('tracks pending draft state', () => {
+ expect(hasPendingIntegrationDraft()).toBe(false);
+
+ setPendingIntegrationDraft({});
+
+ expect(hasPendingIntegrationDraft()).toBe(true);
+ });
+
+ it('clears a draft and invokes its cancel callback', () => {
+ const cancel = jest.fn();
+ setPendingIntegrationDraft({ cancel });
+
+ clearPendingIntegrationDraft();
+
+ expect(cancel).toHaveBeenCalledTimes(1);
+ expect(hasPendingIntegrationDraft()).toBe(false);
+ });
+
+ it('keeps a draft when cancellation is refused', () => {
+ jest.spyOn(window, 'confirm').mockReturnValue(false);
+ setPendingIntegrationDraft({});
+
+ expect(confirmCancelPendingIntegration()).toBe(false);
+ expect(hasPendingIntegrationDraft()).toBe(true);
+ });
+
+ it('clears a draft when cancellation is accepted', () => {
+ const cancel = jest.fn();
+ jest.spyOn(window, 'confirm').mockReturnValue(true);
+ setPendingIntegrationDraft({ cancel });
+
+ expect(confirmCancelPendingIntegration()).toBe(true);
+ expect(cancel).toHaveBeenCalledTimes(1);
+ expect(hasPendingIntegrationDraft()).toBe(false);
+ });
+});
diff --git a/src/__tests__/units/helpers/integration_split.test.tsx b/src/__tests__/units/helpers/integration_split.test.tsx
new file mode 100644
index 00000000..7c9d4dc3
--- /dev/null
+++ b/src/__tests__/units/helpers/integration_split.test.tsx
@@ -0,0 +1,193 @@
+import {
+ NMR_SPLIT_PREVIEW_EXTENT,
+ getIntegrationBounds,
+ getIntegrationSplitTarget,
+ getVisualSplitLineAtX,
+ getVisualSplitLines,
+ interpolateY,
+ isAlreadyVisuallySplit,
+ isMergedVisualSplitGroup,
+ resolveSplitPreviewExtent,
+} from "../../../helpers/integration_split";
+
+describe('Test helper for integration split preview', () => {
+ const data = [
+ { x: 0, y: 0 },
+ { x: 2, y: 4 },
+ { x: 4, y: 2 },
+ { x: 6, y: 0 },
+ ];
+
+ it('resolves shifted integration bounds in data coordinates', () => {
+ expect(getIntegrationBounds({ xL: 1, xU: 7 }, 1)).toEqual([0, 6]);
+ });
+
+ it('finds a split target only when the x position is inside an integration', () => {
+ const focus = {
+ integrationSplitTargets: {
+ stack: [{ xL: 0, xU: 3 }, { xL: 5, xU: 8 }],
+ shift: 0,
+ },
+ };
+
+ expect(getIntegrationSplitTarget(focus, 2)).toEqual({ xL: 0, xU: 3 });
+ expect(getIntegrationSplitTarget(focus, 4)).toBeUndefined();
+ });
+
+ it('interpolates y values between neighbouring points', () => {
+ expect(interpolateY(data, 3)).toEqual(3);
+ });
+
+ it('resolves visual split boundaries from the stack groups in data coordinates', () => {
+ const stack = [
+ { xL: 1, xU: 4, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 6, visualSplitGroupId: 'g1' },
+ ];
+ expect(getVisualSplitLines(stack, 1)).toEqual([3]);
+ });
+
+ it('returns no visual split lines when no group is merged', () => {
+ const stack = [
+ { xL: 0, xU: 4 },
+ { xL: 4, xU: 6 },
+ ];
+ expect(getVisualSplitLines(stack, 0)).toEqual([]);
+ });
+
+ it('finds an existing visual split line by screen tolerance', () => {
+ const focus = {
+ scales: { x: (value: number) => value * 10 },
+ };
+ const stack = [
+ { xL: 0, xU: 3, visualSplitGroupId: 'g1' },
+ { xL: 3, xU: 6, visualSplitGroupId: 'g1' },
+ ];
+
+ expect(getVisualSplitLineAtX(focus, stack, 3.4, 0, 5)).toEqual(3);
+ expect(getVisualSplitLineAtX(focus, stack, 3.7, 0, 5)).toBeNull();
+ });
+
+ it('uses fixed NMR preview bounds and rejects edge positions', () => {
+ const focus = { scales: { y: (value: number) => value }, data };
+ const target = { xL: 0, xU: 6 };
+
+ expect(resolveSplitPreviewExtent(focus, target, 3, 0, false)).toEqual(NMR_SPLIT_PREVIEW_EXTENT);
+ expect(resolveSplitPreviewExtent(focus, target, 0, 0, false)).toBeNull();
+ });
+
+ describe('isAlreadyVisuallySplit', () => {
+ it('returns false for a pristine integration that has never been split', () => {
+ expect(isAlreadyVisuallySplit({ xL: 0, xU: 10 })).toBe(false);
+ });
+
+ it('returns true for a child stack item that carries a visualSplitGroupId', () => {
+ expect(isAlreadyVisuallySplit({ xL: 0, xU: 4, visualSplitGroupId: 'g1' })).toBe(true);
+ });
+
+ it('returns true for a merged group container exposed to the UI', () => {
+ expect(isAlreadyVisuallySplit({
+ xL: 0, xU: 10, isMerged: true, groupId: 'g1',
+ })).toBe(true);
+ });
+
+ it('returns false for a singleton group container', () => {
+ expect(isAlreadyVisuallySplit({
+ xL: 0, xU: 10, isMerged: false, groupId: null,
+ })).toBe(false);
+ });
+
+ it('returns false for nullish or empty input', () => {
+ expect(isAlreadyVisuallySplit(null as any)).toBe(false);
+ expect(isAlreadyVisuallySplit(undefined as any)).toBe(false);
+ });
+ });
+
+ describe('isMergedVisualSplitGroup', () => {
+ it('returns true only for a merged group container', () => {
+ expect(isMergedVisualSplitGroup({
+ xL: 0, xU: 10, isMerged: true, groupId: 'g1',
+ })).toBe(true);
+ });
+
+ it('returns false for a raw child stack item carrying a groupId', () => {
+ expect(isMergedVisualSplitGroup({ xL: 0, xU: 4, visualSplitGroupId: 'g1' })).toBe(false);
+ });
+
+ it('returns false for a pristine integration and for nullish input', () => {
+ expect(isMergedVisualSplitGroup({ xL: 0, xU: 10 })).toBe(false);
+ expect(isMergedVisualSplitGroup(null as any)).toBe(false);
+ expect(isMergedVisualSplitGroup(undefined as any)).toBe(false);
+ });
+ });
+
+ it('resolves HPLC preview bounds between baseline and curve', () => {
+ const focus = {
+ scales: { y: (value: number) => value },
+ data: [
+ { x: 0, y: 0 },
+ { x: 2, y: 4 },
+ { x: 3, y: 6 },
+ { x: 4, y: 4 },
+ { x: 6, y: 0 },
+ ],
+ };
+
+ const extent = resolveSplitPreviewExtent(focus, { xL: 0, xU: 6 }, 3, 0, true);
+
+ expect(extent).toEqual({ y1: 4, y2: 6 });
+ });
+
+ it('uses the merged group bounds for the baseline when previewing on a visual split child', () => {
+ const stack = [
+ { xL: 0, xU: 3, visualSplitGroupId: 'g1' },
+ { xL: 3, xU: 6, visualSplitGroupId: 'g1' },
+ ];
+ const focus: any = {
+ scales: { y: (value: number) => value },
+ data: [
+ { x: 0, y: 0 },
+ { x: 1, y: 2 },
+ { x: 2, y: 4 },
+ { x: 3, y: 6 },
+ { x: 4, y: 4 },
+ { x: 5, y: 2 },
+ { x: 6, y: 0 },
+ ],
+ integrationSplitTargets: { stack, shift: 0, ignoreRef: true },
+ };
+
+ const childExtent = resolveSplitPreviewExtent(focus, stack[1], 4, 0, true);
+ const groupExtent = resolveSplitPreviewExtent(
+ focus,
+ { xL: 0, xU: 6, isMerged: true },
+ 4,
+ 0,
+ true,
+ );
+
+ expect(childExtent).toEqual(groupExtent);
+ expect(childExtent).toEqual({ y1: 2, y2: 4 });
+ });
+
+ it('falls back to the local target bounds when no visual split context is available', () => {
+ const focus: any = {
+ scales: { y: (value: number) => value },
+ data: [
+ { x: 0, y: 10 },
+ { x: 1, y: 2 },
+ { x: 2, y: 4 },
+ { x: 3, y: 6 },
+ { x: 4, y: 4 },
+ { x: 5, y: 2 },
+ { x: 6, y: 10 },
+ ],
+ };
+
+ const targetOnly = resolveSplitPreviewExtent(focus, { xL: 1, xU: 5 }, 3, 0, true);
+ const fullData = resolveSplitPreviewExtent(focus, { xL: 0, xU: 6 }, 3, 0, true);
+
+ expect(targetOnly).not.toBeNull();
+ expect(fullData).not.toBeNull();
+ expect(targetOnly).not.toEqual(fullData);
+ });
+});
diff --git a/src/__tests__/units/helpers/sweep.test.tsx b/src/__tests__/units/helpers/sweep.test.tsx
new file mode 100644
index 00000000..3e2037a9
--- /dev/null
+++ b/src/__tests__/units/helpers/sweep.test.tsx
@@ -0,0 +1,42 @@
+import { buildSweepPayloadFromXBounds } from "../../../helpers/sweep";
+
+describe('Test helper for sweep payloads', () => {
+ const data = [{ x: 0, y: 1, k: 0 }, { x: 2, y: 2, k: 1 }];
+ const dataPks = [{ x: 1, y: 2 }];
+
+ it('builds the same integration sweep shape from two x bounds', () => {
+ const focus = {
+ data,
+ dataPks,
+ currentExtent: {
+ yExtent: { yL: -1, yU: 3 },
+ },
+ };
+
+ const payload = buildSweepPayloadFromXBounds(focus, 2, 0);
+
+ expect(payload).toEqual({
+ xExtent: { xL: 0, xU: 2 },
+ yExtent: { yL: -1, yU: 3 },
+ data,
+ dataPks,
+ });
+ });
+
+ it('accepts zero as a valid lower x bound', () => {
+ const focus = {
+ data,
+ dataPks,
+ h: 10,
+ scales: {
+ y: {
+ invert: (value) => value,
+ },
+ },
+ };
+
+ const payload = buildSweepPayloadFromXBounds(focus, 0, 1);
+
+ expect(payload.xExtent).toEqual({ xL: 0, xU: 1 });
+ });
+});
diff --git a/src/__tests__/units/reducers/reducer_integration.test.tsx b/src/__tests__/units/reducers/reducer_integration.test.tsx
new file mode 100644
index 00000000..602d30e0
--- /dev/null
+++ b/src/__tests__/units/reducers/reducer_integration.test.tsx
@@ -0,0 +1,840 @@
+import { INTEGRATION } from "../../../constants/action_type";
+import undoableIntegrationReducer, { integrationReducer } from "../../../reducers/reducer_integration";
+import { ActionCreators, newHistory } from "redux-undo";
+
+describe('Test redux reducer for integrations', () => {
+ const data = [
+ { x: 0, y: 0, k: 0 },
+ { x: 2, y: 3, k: 2 },
+ { x: 4, y: 4, k: 4 },
+ { x: 6, y: 2, k: 6 },
+ { x: 8, y: 1, k: 8 },
+ { x: 10, y: 0, k: 10 },
+ ];
+
+ it('splits one integration into two calculated integrations atomically', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 2,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ expect(newState.integrations[0].stack).toHaveLength(2);
+ expect(newState.integrations[0].stack[0]).toMatchObject({ xL: 0, xU: 4, area: 4 });
+ expect(newState.integrations[0].stack[1]).toMatchObject({ xL: 4, xU: 10, area: 6 });
+ expect(newState.integrations[0].refArea).toEqual(10);
+ expect(newState.integrations[0].refFactor).toEqual(2);
+ });
+
+ it('keeps shifted stored bounds while calculating with data coordinates', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 1, xU: 11, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 1,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 1, xU: 11 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ expect(newState.integrations[0].stack[0]).toMatchObject({ xL: 1, xU: 5, area: 4 });
+ expect(newState.integrations[0].stack[1]).toMatchObject({ xL: 5, xU: 11, area: 6 });
+ });
+
+ it('rejects splits that do not leave enough data resolution on both sides', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 1,
+ data,
+ },
+ });
+
+ expect(newState).toBe(state);
+ });
+
+ it('removes an integration whose lower x bound is zero', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 10, area: 10, absoluteArea: 0 },
+ { xL: 12, xU: 14, area: 2, absoluteArea: 0 },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.RM_ONE,
+ payload: {
+ curveIdx: 0,
+ dataToRemove: { xL: 0, xU: 10 },
+ },
+ });
+
+ expect(newState.integrations[0].stack).toEqual([{ xL: 12, xU: 14, area: 2, absoluteArea: 0 }]);
+ });
+
+ it('undoes a split in one step', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+ const splitPresent = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 4,
+ data,
+ },
+ });
+ const splitState: any = newHistory([state], splitPresent, []);
+ const undoneState = undoableIntegrationReducer(splitState, ActionCreators.undo());
+
+ expect(splitState.present.integrations[0].stack).toHaveLength(2);
+ expect(undoneState.present.integrations[0].stack).toEqual(state.integrations[0].stack);
+ });
+
+ it('undoes the very first integration added after a fresh load', () => {
+ const freshPresent = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [],
+ refArea: 1,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+ const fresh: any = newHistory([], freshPresent, []);
+
+ const afterAdd = undoableIntegrationReducer(fresh, {
+ type: 'UI_SWEEP_SELECT_INTEGRATION',
+ payload: {
+ curveIdx: 0,
+ newData: { xExtent: { xL: 2, xU: 8 }, data },
+ },
+ });
+
+ expect(afterAdd.past).toHaveLength(1);
+ expect(afterAdd.present.integrations[0].stack).toHaveLength(1);
+
+ const undone = undoableIntegrationReducer(afterAdd, ActionCreators.undo());
+ expect(undone.present.integrations[0].stack).toHaveLength(0);
+
+ const redone = undoableIntegrationReducer(undone, ActionCreators.redo());
+ expect(redone.present.integrations[0].stack).toHaveLength(1);
+ });
+
+ it('records a split in the undoable history when dispatched through the undoable reducer', () => {
+ const seed: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+ const seedHistory: any = newHistory([], seed, []);
+
+ const afterSplit = undoableIntegrationReducer(seedHistory, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ expect(afterSplit.past).toHaveLength(1);
+ expect(afterSplit.present.integrations[0].stack).toHaveLength(2);
+
+ const undone = undoableIntegrationReducer(afterSplit, ActionCreators.undo());
+ expect(undone.present.integrations[0].stack).toEqual(seed.integrations[0].stack);
+
+ const redone = undoableIntegrationReducer(undone, ActionCreators.redo());
+ expect(redone.present.integrations[0].stack).toEqual(afterSplit.present.integrations[0].stack);
+ });
+
+ it('adds a visual split line by splitting the target into two grouped stack items', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ expect(newState.integrations[0].stack).toHaveLength(2);
+ expect(newState.integrations[0].stack[0]).toMatchObject({ xL: 0, xU: 4, area: 4 });
+ expect(newState.integrations[0].stack[1]).toMatchObject({ xL: 4, xU: 10, area: 6 });
+ const groupId = newState.integrations[0].stack[0].visualSplitGroupId;
+ expect(typeof groupId).toBe('string');
+ expect(newState.integrations[0].stack[1].visualSplitGroupId).toBe(groupId);
+ });
+
+ it('stores shifted visual split bounds consistently with the integration stack item', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 1, xU: 11, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 1,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 1, xU: 11 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ expect(newState.integrations[0].stack[0]).toMatchObject({ xL: 1, xU: 5 });
+ expect(newState.integrations[0].stack[1]).toMatchObject({ xL: 5, xU: 11 });
+ expect(newState.integrations[0].stack[0].visualSplitGroupId)
+ .toBe(newState.integrations[0].stack[1].visualSplitGroupId);
+ });
+
+ it('rejects splitting a child item that already belongs to a visual split group', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 6, area: 6, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 6, xU: 10, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 6 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ expect(newState).toBe(state);
+ });
+
+ it('rejects a second visual split on a previously split integration restored from storage', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'persisted-vsg' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 0, visualSplitGroupId: 'persisted-vsg' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 4, xU: 10 },
+ splitX: 6,
+ data,
+ },
+ });
+
+ expect(newState).toBe(state);
+ });
+
+ it('preserves the original stored area when visually splitting a JCAMP-loaded integration', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 300, absoluteArea: 60 }],
+ refArea: 300,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ const [leftChild, rightChild] = newState.integrations[0].stack;
+ expect(leftChild.area + rightChild.area).toBeCloseTo(300, 9);
+ expect(leftChild.absoluteArea + rightChild.absoluteArea).toBeCloseTo(60, 9);
+ expect(leftChild.area).toBeGreaterThan(0);
+ expect(rightChild.area).toBeGreaterThan(0);
+ });
+
+ it('recomputes each side from raw data on a regular split (independent integrations)', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 300, absoluteArea: 60 }],
+ refArea: 300,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 4,
+ data,
+ },
+ });
+
+ const [leftChild, rightChild] = newState.integrations[0].stack;
+ expect(leftChild).toMatchObject({ xL: 0, xU: 4, area: 4 });
+ expect(rightChild).toMatchObject({ xL: 4, xU: 10, area: 6 });
+ expect(leftChild.area + rightChild.area).toBeCloseTo(10, 9);
+ });
+
+ it('restores the exact total area when removing a visual split line', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 300, absoluteArea: 60 }],
+ refArea: 300,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const split = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0, target: { xL: 0, xU: 10 }, splitX: 4, data,
+ },
+ });
+ expect(split.integrations[0].stack).toHaveLength(2);
+
+ const merged = integrationReducer(split, {
+ type: INTEGRATION.RM_VISUAL_SPLIT,
+ payload: { curveIdx: 0, splitX: 4, data },
+ });
+
+ expect(merged.integrations[0].stack).toHaveLength(1);
+ expect(merged.integrations[0].stack[0].area).toBeCloseTo(300, 9);
+ expect(merged.integrations[0].stack[0].absoluteArea).toBeCloseTo(60, 9);
+ });
+
+ it('allows visually splitting again after the only split line has been removed', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const merged = integrationReducer(state, {
+ type: INTEGRATION.RM_VISUAL_SPLIT,
+ payload: { curveIdx: 0, splitX: 4, data },
+ });
+ expect(merged.integrations[0].stack).toHaveLength(1);
+ expect(merged.integrations[0].stack[0].visualSplitGroupId).toBeUndefined();
+
+ const reSplit = integrationReducer(merged, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 6,
+ data,
+ },
+ });
+
+ expect(reSplit.integrations[0].stack).toHaveLength(2);
+ expect(reSplit.integrations[0].stack[0]).toMatchObject({ xL: 0, xU: 6 });
+ expect(reSplit.integrations[0].stack[1]).toMatchObject({ xL: 6, xU: 10 });
+ const newGroupId = reSplit.integrations[0].stack[0].visualSplitGroupId;
+ expect(typeof newGroupId).toBe('string');
+ expect(reSplit.integrations[0].stack[1].visualSplitGroupId).toBe(newGroupId);
+ });
+
+ it('removes a visual split line by merging the two adjacent grouped items', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 6, area: 2, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 6, xU: 10, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.RM_VISUAL_SPLIT,
+ payload: { curveIdx: 0, splitX: 4, data },
+ });
+
+ expect(newState.integrations[0].stack).toHaveLength(2);
+ expect(newState.integrations[0].stack[0]).toMatchObject({ xL: 0, xU: 6, visualSplitGroupId: 'g1' });
+ expect(newState.integrations[0].stack[1]).toMatchObject({ xL: 6, xU: 10, visualSplitGroupId: 'g1' });
+ });
+
+ it('strips the orphan groupId when one child of a visual split group is removed', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const afterRemove = integrationReducer(state, {
+ type: INTEGRATION.RM_ONE,
+ payload: { curveIdx: 0, dataToRemove: { xL: 0, xU: 4 } },
+ });
+
+ expect(afterRemove.integrations[0].stack).toHaveLength(1);
+ expect(afterRemove.integrations[0].stack[0]).toMatchObject({ xL: 4, xU: 10 });
+ expect(afterRemove.integrations[0].stack[0].visualSplitGroupId).toBeUndefined();
+
+ const reSplit = integrationReducer(afterRemove, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 4, xU: 10 },
+ splitX: 6,
+ data,
+ },
+ });
+ expect(reSplit.integrations[0].stack).toHaveLength(2);
+ const reSplitGroupId = reSplit.integrations[0].stack[0].visualSplitGroupId;
+ expect(typeof reSplitGroupId).toBe('string');
+ expect(reSplit.integrations[0].stack[1].visualSplitGroupId).toBe(reSplitGroupId);
+ });
+
+ it('extracts the outer part of a left visual split child and keeps the inner part in the group', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 40, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 60, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const afterSplit = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 4 },
+ splitX: 2,
+ data,
+ },
+ });
+
+ expect(afterSplit.integrations[0].stack).toHaveLength(3);
+ const [extracted, kept, sibling] = afterSplit.integrations[0].stack;
+
+ expect(extracted).toMatchObject({ xL: 0, xU: 2 });
+ expect(extracted.visualSplitGroupId).toBeUndefined();
+
+ expect(kept).toMatchObject({ xL: 2, xU: 4, visualSplitGroupId: 'g1' });
+ expect(sibling).toMatchObject({ xL: 4, xU: 10, visualSplitGroupId: 'g1' });
+
+ expect(extracted.area + kept.area).toBeCloseTo(4);
+ expect(extracted.absoluteArea + kept.absoluteArea).toBeCloseTo(40);
+ });
+
+ it('extracts the outer part of a right visual split child and keeps the inner part in the group', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 40, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 60, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const afterSplit = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 4, xU: 10 },
+ splitX: 8,
+ data,
+ },
+ });
+
+ expect(afterSplit.integrations[0].stack).toHaveLength(3);
+ const [sibling, kept, extracted] = afterSplit.integrations[0].stack;
+
+ expect(sibling).toMatchObject({ xL: 0, xU: 4, visualSplitGroupId: 'g1' });
+ expect(kept).toMatchObject({ xL: 4, xU: 8, visualSplitGroupId: 'g1' });
+ expect(extracted).toMatchObject({ xL: 8, xU: 10 });
+ expect(extracted.visualSplitGroupId).toBeUndefined();
+
+ expect(kept.area + extracted.area).toBeCloseTo(6);
+ expect(kept.absoluteArea + extracted.absoluteArea).toBeCloseTo(60);
+ });
+
+ it('keeps both halves in the group when regular-splitting a middle child', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 2, area: 2, absoluteArea: 20, visualSplitGroupId: 'g1' },
+ { xL: 2, xU: 8, area: 6, absoluteArea: 60, visualSplitGroupId: 'g1' },
+ { xL: 8, xU: 10, area: 2, absoluteArea: 20, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const afterSplit = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 2, xU: 8 },
+ splitX: 5,
+ data,
+ },
+ });
+
+ expect(afterSplit.integrations[0].stack).toHaveLength(4);
+ expect(afterSplit.integrations[0].stack.every((it: any) => it.visualSplitGroupId === 'g1')).toBe(true);
+ });
+
+ it('drops the groupId when removing the last visual split line of a group', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.RM_VISUAL_SPLIT,
+ payload: { curveIdx: 0, splitX: 4, data },
+ });
+
+ expect(newState.integrations[0].stack).toHaveLength(1);
+ expect(newState.integrations[0].stack[0]).toMatchObject({ xL: 0, xU: 10 });
+ expect(newState.integrations[0].stack[0].visualSplitGroupId).toBeUndefined();
+ });
+
+ it('undoes adding a visual split line in one step', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+ const splitPresent = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 4,
+ data,
+ },
+ });
+ const splitState: any = newHistory([state], splitPresent, []);
+ const undoneState = undoableIntegrationReducer(splitState, ActionCreators.undo());
+
+ expect(splitState.present.integrations[0].stack).toHaveLength(2);
+ expect(undoneState.present.integrations[0].stack).toEqual(state.integrations[0].stack);
+ });
+
+ it('undoes extracting a child from a visual split group in one step', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 40, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 60, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+ const splitPresent = integrationReducer(state, {
+ type: INTEGRATION.SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 4 },
+ splitX: 2,
+ data,
+ },
+ });
+ const splitState: any = newHistory([state], splitPresent, []);
+ const undoneState = undoableIntegrationReducer(splitState, ActionCreators.undo());
+
+ expect(splitState.present.integrations[0].stack).toHaveLength(3);
+ expect(splitState.present.integrations[0].stack[0].visualSplitGroupId).toBeUndefined();
+ expect(splitState.present.integrations[0].stack[1].visualSplitGroupId).toBe('g1');
+ expect(splitState.present.integrations[0].stack[2].visualSplitGroupId).toBe('g1');
+
+ expect(undoneState.present.integrations[0].stack).toEqual(state.integrations[0].stack);
+ expect(undoneState.present.integrations[0].stack[0].visualSplitGroupId).toBe('g1');
+ expect(undoneState.present.integrations[0].stack[1].visualSplitGroupId).toBe('g1');
+
+ const redoneState = undoableIntegrationReducer(undoneState, ActionCreators.redo());
+ expect(redoneState.present.integrations[0].stack).toEqual(splitPresent.integrations[0].stack);
+ });
+
+ it('undoes removing a visual split line in one step', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [
+ { xL: 0, xU: 4, area: 4, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ { xL: 4, xU: 10, area: 6, absoluteArea: 0, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+ const removedPresent = integrationReducer(state, {
+ type: INTEGRATION.RM_VISUAL_SPLIT,
+ payload: { curveIdx: 0, splitX: 4, data },
+ });
+ const removedState: any = newHistory([state], removedPresent, []);
+ const undoneState = undoableIntegrationReducer(removedState, ActionCreators.undo());
+
+ expect(removedState.present.integrations[0].stack).toHaveLength(1);
+ expect(undoneState.present.integrations[0].stack).toEqual(state.integrations[0].stack);
+ });
+
+ it('preserves visualSplitGroupId metadata when restoring integrations via RESET_ALL_RDC', () => {
+ const initial: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [],
+ refArea: 1,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+ const restored = integrationReducer(initial, {
+ type: INTEGRATION.RESET_ALL_RDC,
+ payload: {
+ selectedIdx: 0,
+ integrations: [
+ {
+ stack: [
+ { xL: 0, xU: 3, area: 3, absoluteArea: 1, visualSplitGroupId: 'g1' },
+ { xL: 3, xU: 10, area: 7, absoluteArea: 4, visualSplitGroupId: 'g1' },
+ ],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ },
+ ],
+ },
+ });
+
+ expect(restored.integrations[0].stack[0]).toMatchObject({
+ xL: 0, xU: 3, visualSplitGroupId: 'g1',
+ });
+ expect(restored.integrations[0].stack[1]).toMatchObject({
+ xL: 3, xU: 10, visualSplitGroupId: 'g1',
+ });
+ });
+
+ it('preserves visualSplitGroupId across multi-curve integrations via RESET_ALL_RDC', () => {
+ const initial: any = {
+ selectedIdx: 0,
+ integrations: [
+ { stack: [], refArea: 1, refFactor: 1, shift: 0, edited: false },
+ { stack: [], refArea: 1, refFactor: 1, shift: 0, edited: false },
+ ],
+ };
+ const restored = integrationReducer(initial, {
+ type: INTEGRATION.RESET_ALL_RDC,
+ payload: {
+ selectedIdx: 1,
+ integrations: [
+ {
+ stack: [{ xL: 0, xU: 4, area: 4, absoluteArea: 2 }],
+ refArea: 4,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ },
+ {
+ stack: [
+ { xL: 5, xU: 7, area: 2, absoluteArea: 1, visualSplitGroupId: 'g2' },
+ { xL: 7, xU: 9, area: 2, absoluteArea: 1, visualSplitGroupId: 'g2' },
+ ],
+ refArea: 4,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ },
+ ],
+ },
+ });
+
+ expect(restored.integrations[0].stack[0].visualSplitGroupId).toBeUndefined();
+ expect(restored.integrations[1].stack[0].visualSplitGroupId).toBe('g2');
+ expect(restored.integrations[1].stack[1].visualSplitGroupId).toBe('g2');
+ });
+
+ it('rejects visual split lines too close to an integration edge', () => {
+ const state: any = {
+ selectedIdx: 0,
+ integrations: [{
+ stack: [{ xL: 0, xU: 10, area: 10, absoluteArea: 0 }],
+ refArea: 10,
+ refFactor: 1,
+ shift: 0,
+ edited: false,
+ }],
+ };
+
+ const newState = integrationReducer(state, {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload: {
+ curveIdx: 0,
+ target: { xL: 0, xU: 10 },
+ splitX: 0,
+ data,
+ },
+ });
+
+ expect(newState).toBe(state);
+ });
+});
diff --git a/src/actions/integration.js b/src/actions/integration.js
index b594b852..0d25e9e8 100644
--- a/src/actions/integration.js
+++ b/src/actions/integration.js
@@ -21,8 +21,32 @@ const clearIntegrationAll = (payload) => (
}
);
+const splitIntegration = (payload) => (
+ {
+ type: INTEGRATION.SPLIT,
+ payload,
+ }
+);
+
+const addVisualSplitLine = (payload) => (
+ {
+ type: INTEGRATION.ADD_VISUAL_SPLIT,
+ payload,
+ }
+);
+
+const removeVisualSplitLine = (payload) => (
+ {
+ type: INTEGRATION.RM_VISUAL_SPLIT,
+ payload,
+ }
+);
+
export {
+ addVisualSplitLine,
sweepIntegration,
setIntegrationFkr,
clearIntegrationAll,
+ removeVisualSplitLine,
+ splitIntegration,
}; // eslint-disable-line
diff --git a/src/actions/ui.js b/src/actions/ui.js
index 46424f92..4e9a8c51 100644
--- a/src/actions/ui.js
+++ b/src/actions/ui.js
@@ -1,19 +1,38 @@
import { UI } from '../constants/action_type';
+import { LIST_UI_SWEEP_TYPE } from '../constants/list_ui';
+import { confirmCancelPendingIntegration } from '../helpers/integration_draft.js'; // eslint-disable-line import/extensions
-const setUiViewerType = (payload) => (
- {
+const keepIntegrationMode = (jcampIdx = 0) => ({
+ type: UI.SWEEP.SET_TYPE,
+ payload: LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ jcampIdx,
+});
+
+const setUiViewerType = (payload) => {
+ if (!confirmCancelPendingIntegration()) {
+ return keepIntegrationMode();
+ }
+
+ return {
type: UI.VIEWER.SET_TYPE,
payload,
+ };
+};
+
+const setUiSweepType = (payload, jcampIdx = 0) => {
+ if (
+ payload !== LIST_UI_SWEEP_TYPE.INTEGRATION_ADD
+ && !confirmCancelPendingIntegration()
+ ) {
+ return keepIntegrationMode(jcampIdx);
}
-);
-const setUiSweepType = (payload, jcampIdx = 0) => (
- {
+ return {
type: UI.SWEEP.SET_TYPE,
payload,
jcampIdx,
- }
-);
+ };
+};
const selectUiSweep = (payload) => (
{
diff --git a/src/components/cmd_bar/04_integration.js b/src/components/cmd_bar/04_integration.js
index 77356585..c3388c29 100644
--- a/src/components/cmd_bar/04_integration.js
+++ b/src/components/cmd_bar/04_integration.js
@@ -12,7 +12,7 @@ import Tooltip from '@mui/material/Tooltip';
import TextField from '@mui/material/TextField';
import Icon from '@mdi/react';
-import { mdiReflectVertical, mdiMathIntegral } from '@mdi/js';
+import { mdiClose, mdiReflectVertical, mdiMathIntegral } from '@mdi/js';
import {
clearIntegrationAll, setIntegrationFkr,
@@ -21,6 +21,7 @@ import { setUiSweepType } from '../../actions/ui';
import {
LIST_UI_SWEEP_TYPE,
} from '../../constants/list_ui';
+import { clearPendingIntegrationDraft } from '../../helpers/integration_draft.js'; // eslint-disable-line import/extensions
import Cfg from '../../helpers/cfg';
import TriBtn from './tri_btn';
import { MuButton, commonStyle, focusStyle } from './common';
@@ -34,6 +35,13 @@ const styles = () => (
},
txtIcon: {
},
+ cancelBtn: {
+ borderColor: '#d32f2f',
+ color: '#d32f2f',
+ '&:hover': {
+ backgroundColor: '#ffebee',
+ },
+ },
},
commonStyle,
)
@@ -92,13 +100,36 @@ const iconColor = (criteria) => (criteria ? '#fff' : '#000');
const Integration = ({
classes, ignoreRef,
isDisableSt, isFocusAddIntgSt, isFocusRmIntgSt, isFocusSetRefSt,
+ isFocusSplitIntgSt, isFocusVisualSplitIntgSt,
setUiSweepTypeAct, setIntegrationFkrAct, clearIntegrationAllAct,
curveSt, integrationSt,
}) => {
- const onSweepIntegtAdd = () => setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.INTEGRATION_ADD);
+ const { curveIdx } = curveSt;
+ const onCancelTool = () => setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.ZOOMIN, curveIdx);
+ const onSweepIntegtAdd = () => {
+ if (isFocusAddIntgSt) {
+ clearPendingIntegrationDraft();
+ onCancelTool();
+ return;
+ }
+ setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.INTEGRATION_ADD, curveIdx);
+ };
const onSweepIntegtRm = () => setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.INTEGRATION_RM);
const onSweepIntegtSR = () => setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF);
- const { curveIdx } = curveSt;
+ const onSweepIntegtSplit = () => {
+ if (isFocusSplitIntgSt) {
+ onCancelTool();
+ return;
+ }
+ setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, curveIdx);
+ };
+ const onSweepIntegtVisualSplit = () => {
+ if (isFocusVisualSplitIntgSt) {
+ onCancelTool();
+ return;
+ }
+ setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, curveIdx);
+ };
const onClearAll = () => clearIntegrationAllAct({ curveIdx });
return (
@@ -108,7 +139,7 @@ const Integration = ({
- +
+ {
+ isFocusAddIntgSt
+ ? null
+ : +
+ }
@@ -147,24 +182,82 @@ const Integration = ({
- Set Integration Reference}>
+ {
+ ignoreRef
+ ? null
+ : (
+ Set Integration Reference}>
+
+
+
+
+
+
+ )
+ }
+ Split Integration}>
+
+
+
+ {
+ isFocusSplitIntgSt
+ ? null
+ : /
+ }
+
+
+
+ Visual Split Integration}>
+ {
+ isFocusVisualSplitIntgSt
+ ? null
+ : |
+ }
@@ -197,6 +290,8 @@ const mapStateToProps = (state, props) => ( // eslint-disable-line
isFocusAddIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
isFocusRmIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_RM,
isFocusSetRefSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF,
+ isFocusSplitIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT,
+ isFocusVisualSplitIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT,
ignoreRef: Format.isHplcUvVisLayout(state.layout),
curveSt: state.curve,
integrationSt: state.integration.present,
@@ -217,6 +312,8 @@ Integration.propTypes = {
isFocusAddIntgSt: PropTypes.bool.isRequired,
isFocusRmIntgSt: PropTypes.bool.isRequired,
isFocusSetRefSt: PropTypes.bool.isRequired,
+ isFocusSplitIntgSt: PropTypes.bool.isRequired,
+ isFocusVisualSplitIntgSt: PropTypes.bool.isRequired,
ignoreRef: PropTypes.bool.isRequired,
setUiSweepTypeAct: PropTypes.func.isRequired,
setIntegrationFkrAct: PropTypes.func.isRequired,
diff --git a/src/components/d3_line/index.js b/src/components/d3_line/index.js
index d42c2796..ebe1a4c7 100644
--- a/src/components/d3_line/index.js
+++ b/src/components/d3_line/index.js
@@ -10,6 +10,9 @@ import {
} from '../../helpers/chem';
import { resetAll } from '../../actions/manager';
import { selectUiSweep, scrollUiWheel, clickUiTarget } from '../../actions/ui';
+import {
+ addVisualSplitLine, removeVisualSplitLine, splitIntegration,
+} from '../../actions/integration';
import LineFocus from './line_focus';
import {
drawMain, drawLabel, drawDisplay, drawDestroy,
@@ -24,23 +27,35 @@ class ViewerLine extends React.Component {
constructor(props) {
super(props);
- const { clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct } = props;
+ const {
+ clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, splitIntegrationAct,
+ addVisualSplitLineAct, removeVisualSplitLineAct,
+ } = props;
this.rootKlass = '.d3Line';
this.focus = new LineFocus({
- W, H, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct,
+ W,
+ H,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct,
+ addVisualSplitLineAct,
+ removeVisualSplitLineAct,
});
this.normChange = this.normChange.bind(this);
+ this.syncFocusActions = this.syncFocusActions.bind(this);
}
componentDidMount() {
const {
seed, peak, cLabel, xLabel, yLabel, feature, freq, comparisons,
tTrEndPts, tSfPeaks, editPeakSt, layoutSt, integationSt, mtplySt,
- sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt,
isHidden, wavelength, axesUnitsSt,
resetAllAct,
} = this.props;
+ this.syncFocusActions();
drawDestroy(this.rootKlass);
resetAllAct(feature);
@@ -71,6 +86,8 @@ class ViewerLine extends React.Component {
mtplySt,
sweepExtentSt,
isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiVisualSplitIntgSt,
isUiNoBrushSt,
wavelength,
});
@@ -82,9 +99,10 @@ class ViewerLine extends React.Component {
const {
seed, peak, cLabel, xLabel, yLabel, freq, comparisons,
tTrEndPts, tSfPeaks, editPeakSt, layoutSt, integationSt, mtplySt,
- sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt,
isHidden, wavelength, axesUnitsSt,
} = this.props;
+ this.syncFocusActions();
this.normChange(prevProps);
let xxLabel = xLabel;
@@ -113,6 +131,8 @@ class ViewerLine extends React.Component {
mtplySt,
sweepExtentSt,
isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiVisualSplitIntgSt,
isUiNoBrushSt,
wavelength,
});
@@ -124,6 +144,22 @@ class ViewerLine extends React.Component {
drawDestroy(this.rootKlass);
}
+ syncFocusActions() {
+ if (!this.focus) return;
+ const {
+ clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct,
+ splitIntegrationAct, addVisualSplitLineAct, removeVisualSplitLineAct,
+ } = this.props;
+ Object.assign(this.focus, {
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct,
+ addVisualSplitLineAct,
+ removeVisualSplitLineAct,
+ });
+ }
+
normChange(prevProps) {
const { feature, resetAllAct } = this.props;
const oldFeature = prevProps.feature;
@@ -153,6 +189,8 @@ const mapStateToProps = (state, props) => (
mtplySt: state.multiplicity.present,
sweepExtentSt: state.ui.sweepExtent,
isUiAddIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ isUiSplitIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT,
+ isUiVisualSplitIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT,
isUiNoBrushSt: LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0,
wavelength: state.wavelength,
axesUnitsSt: state.axesUnits,
@@ -165,6 +203,9 @@ const mapDispatchToProps = (dispatch) => (
clickUiTargetAct: clickUiTarget,
selectUiSweepAct: selectUiSweep,
scrollUiWheelAct: scrollUiWheel,
+ splitIntegrationAct: splitIntegration,
+ addVisualSplitLineAct: addVisualSplitLine,
+ removeVisualSplitLineAct: removeVisualSplitLine,
addNewCylicVoltaPairPeakAct: addNewCylicVoltaPairPeak,
addCylicVoltaMaxPeakAct: addCylicVoltaMaxPeak,
addCylicVoltaMinPeakAct: addCylicVoltaMinPeak,
@@ -191,11 +232,16 @@ ViewerLine.propTypes = {
mtplySt: PropTypes.object.isRequired,
sweepExtentSt: PropTypes.object.isRequired,
isUiAddIntgSt: PropTypes.bool.isRequired,
+ isUiSplitIntgSt: PropTypes.bool.isRequired,
+ isUiVisualSplitIntgSt: PropTypes.bool.isRequired,
isUiNoBrushSt: PropTypes.bool.isRequired,
resetAllAct: PropTypes.func.isRequired,
clickUiTargetAct: PropTypes.func.isRequired,
selectUiSweepAct: PropTypes.func.isRequired,
scrollUiWheelAct: PropTypes.func.isRequired,
+ splitIntegrationAct: PropTypes.func.isRequired,
+ addVisualSplitLineAct: PropTypes.func.isRequired,
+ removeVisualSplitLineAct: PropTypes.func.isRequired,
isHidden: PropTypes.bool.isRequired,
wavelength: PropTypes.object.isRequired,
axesUnitsSt: PropTypes.object.isRequired,
diff --git a/src/components/d3_line/line_focus.js b/src/components/d3_line/line_focus.js
index b308e9d3..ca37975b 100644
--- a/src/components/d3_line/line_focus.js
+++ b/src/components/d3_line/line_focus.js
@@ -8,14 +8,24 @@ import {
} from '../../helpers/mount';
import MountBrush from '../../helpers/brush';
import { TfRescale, MountCompass } from '../../helpers/compass';
+import {
+ clearIntegrationSplitPreview,
+ drawIntegrationSplitPreview,
+ drawIntegrationVisualSplitLines,
+ getSplitXFromEvent,
+ getVisualSplitLineAtX,
+ isAlreadyVisuallySplit,
+ isMergedVisualSplitGroup,
+} from '../../helpers/integration_split';
import { PksEdit } from '../../helpers/converter';
import { itgIdTag, mpyIdTag } from '../../helpers/focus';
-import { calcArea } from '../../helpers/integration';
+import {
+ calcArea, getIntegrationPoints, getLinearBaseline, getVisualSplitGroups,
+} from '../../helpers/integration';
import { calcMpyCenter } from '../../helpers/multiplicity_calc';
import Format from '../../helpers/format';
import Cfg from '../../helpers/cfg';
import { LIST_LAYOUT } from '../../constants/list_layout';
-import { calcSlope } from '../../helpers/calc';
const d3 = require('d3');
@@ -23,6 +33,7 @@ class LineFocus {
constructor(props) {
const {
W, H, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct,
+ splitIntegrationAct, addVisualSplitLineAct, removeVisualSplitLineAct,
} = props;
this.jcampIdx = 0;
@@ -38,6 +49,9 @@ class LineFocus {
this.clickUiTargetAct = clickUiTargetAct;
this.selectUiSweepAct = selectUiSweepAct;
this.scrollUiWheelAct = scrollUiWheelAct;
+ this.splitIntegrationAct = splitIntegrationAct;
+ this.addVisualSplitLineAct = addVisualSplitLineAct;
+ this.removeVisualSplitLineAct = removeVisualSplitLineAct;
this.brush = d3.brush();
this.brushX = d3.brushX();
@@ -63,6 +77,11 @@ class LineFocus {
this.shouldUpdate = {};
this.freq = false;
this.layout = LIST_LAYOUT.H1;
+ this.isUiAddIntgSt = false;
+ this.isUiSplitIntgSt = false;
+ this.isUiVisualSplitIntgSt = false;
+ this.integrationSplitTargets = null;
+ this.firstIntegrationPoint = null;
this.getShouldUpdate = this.getShouldUpdate.bind(this);
this.resetShouldUpdate = this.resetShouldUpdate.bind(this);
@@ -81,6 +100,11 @@ class LineFocus {
this.drawMtply = this.drawMtply.bind(this);
this.drawComparisons = this.drawComparisons.bind(this);
this.onClickTarget = this.onClickTarget.bind(this);
+ this.onClickIntegrationTarget = this.onClickIntegrationTarget.bind(this);
+ this.onClickVisualSplitLine = this.onClickVisualSplitLine.bind(this);
+ this.onIntegrationMouseMove = this.onIntegrationMouseMove.bind(this);
+ this.clearSplitPreview = this.clearSplitPreview.bind(this);
+ this.drawVisualSplitLines = this.drawVisualSplitLines.bind(this);
this.mergedPeaks = this.mergedPeaks.bind(this);
this.isFirefox = typeof InstallTrigger !== 'undefined';
@@ -233,40 +257,119 @@ class LineFocus {
this.clickUiTargetAct(data, onPeak);
}
+ clearSplitPreview() {
+ clearIntegrationSplitPreview(this);
+ }
+
+ onIntegrationMouseMove(event, data, shift, ignoreRef) {
+ if (!this.isUiSplitIntgSt && !this.isUiVisualSplitIntgSt) return;
+ if (this.isUiVisualSplitIntgSt && isAlreadyVisuallySplit(data)) {
+ this.clearSplitPreview();
+ return;
+ }
+ if (this.isUiSplitIntgSt && isMergedVisualSplitGroup(data)) {
+ this.clearSplitPreview();
+ return;
+ }
+ const splitX = getSplitXFromEvent(event, this);
+ drawIntegrationSplitPreview(this, data, splitX, shift, ignoreRef);
+ }
+
+ onClickIntegrationTarget(event, data) {
+ if (!this.isUiSplitIntgSt && !this.isUiVisualSplitIntgSt) {
+ this.onClickTarget(event, data);
+ return;
+ }
+
+ event.stopPropagation();
+ event.preventDefault();
+ const splitX = getSplitXFromEvent(event, this);
+ this.clearSplitPreview();
+ if (this.isUiVisualSplitIntgSt) {
+ const { stack = [], shift = 0 } = this.integrationSplitTargets || {};
+ const existingSplitX = getVisualSplitLineAtX(this, stack, splitX, shift);
+ if (Number.isFinite(existingSplitX)) {
+ if (typeof this.removeVisualSplitLineAct !== 'function') return;
+ this.removeVisualSplitLineAct({
+ curveIdx: this.jcampIdx,
+ splitX: existingSplitX,
+ data: this.data,
+ });
+ return;
+ }
+ if (isAlreadyVisuallySplit(data)) return;
+ if (typeof this.addVisualSplitLineAct !== 'function') return;
+ this.addVisualSplitLineAct({
+ curveIdx: this.jcampIdx,
+ target: data,
+ splitX,
+ data: this.data,
+ });
+ return;
+ }
+
+ if (isMergedVisualSplitGroup(data)) return;
+ this.splitIntegrationAct({
+ curveIdx: this.jcampIdx,
+ target: data,
+ splitX,
+ data: this.data,
+ });
+ }
+
+ onClickVisualSplitLine(event, splitX) {
+ event.stopPropagation();
+ event.preventDefault();
+ this.clearSplitPreview();
+ if (typeof this.removeVisualSplitLineAct !== 'function') return;
+ this.removeVisualSplitLineAct({
+ curveIdx: this.jcampIdx,
+ splitX,
+ data: this.data,
+ });
+ }
+
+ drawVisualSplitLines(stack, shift, ignoreRef) {
+ drawIntegrationVisualSplitLines(
+ this,
+ stack,
+ shift,
+ ignoreRef,
+ this.isUiVisualSplitIntgSt,
+ this.onClickVisualSplitLine,
+ );
+ }
+
mergedPeaks(editPeakSt) {
if (!editPeakSt) return this.dataPks;
this.dataPks = PksEdit(this.dataPks, editPeakSt);
return this.dataPks;
}
- drawAUC(stack) {
+ drawAUC(stack, shift = 0) {
const { xt, yt } = TfRescale(this);
- const auc = this.tags.aucPath.selectAll('path').data(stack);
+ const groups = getVisualSplitGroups(stack).map((group) => ({
+ xL: group.xL,
+ xU: group.xU,
+ isMerged: group.isMerged,
+ groupId: group.groupId,
+ target: group.items[0],
+ }));
+ const auc = this.tags.aucPath.selectAll('path').data(groups);
auc.exit()
.attr('class', 'exit')
.remove();
const integCurve = (border) => {
const { xL, xU } = border;
- const ps = this.data.filter((d) => d.x > xL && d.x < xU);
+ const ps = getIntegrationPoints(xL - shift, xU - shift, this.data);
if (!ps[0]) return null;
- const point1 = ps[0];
- const point2 = ps[ps.length - 1];
- const slope = calcSlope(point1.x, point1.y, point2.x, point2.y);
- let lastDY = point1.y;
+ const baselineY = getLinearBaseline(ps);
return d3.area()
.x((d) => xt(d.x))
- .y0((d, index) => {
- if (index > 0) {
- const lastD = ps[index - 1];
- const y = slope * (d.x - lastD.x) + lastDY;
- lastDY = y;
- return yt(y);
- }
- return yt(0);
- })
+ .y0((d) => yt(baselineY(d)))
.y1((d) => yt(d.y))(ps);
};
@@ -295,8 +398,10 @@ class LineFocus {
.style('fill', 'red');
d3.select(`#auc${itgIdTag(d)}`)
.style('fill-opacity', 0.2);
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, true))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
}
drawPeaks(editPeakSt) {
@@ -394,12 +499,23 @@ class LineFocus {
const isDisable = Cfg.btnCmdIntg(this.layout);
const ignoreRef = Format.isHplcUvVisLayout(this.layout);
const itgs = isDisable ? [] : stack;
+ Object.assign(this, {
+ integrationSplitTargets: { stack: itgs, shift, ignoreRef },
+ });
- const igbp = this.tags.igbPath.selectAll('path').data(itgs);
+ const igGroups = getVisualSplitGroups(itgs).map((group) => ({
+ xL: group.xL,
+ xU: group.xU,
+ isMerged: group.isMerged,
+ groupId: group.groupId,
+ target: group.items[0],
+ }));
+
+ const igbp = this.tags.igbPath.selectAll('path').data(igGroups);
igbp.exit()
.attr('class', 'exit')
.remove();
- const igcp = this.tags.igcPath.selectAll('path').data(itgs);
+ const igcp = this.tags.igcPath.selectAll('path').data(igGroups);
igcp.exit()
.attr('class', 'exit')
.remove();
@@ -416,11 +532,12 @@ class LineFocus {
.attr('class', 'exit')
.remove();
auc.merge(auc);
+ this.drawVisualSplitLines([], shift, ignoreRef);
return;
}
if (ignoreRef) {
- this.drawAUC(stack);
+ this.drawAUC(stack, shift);
} else {
// rescale for zoom
const { xt } = TfRescale(this);
@@ -461,8 +578,10 @@ class LineFocus {
.attr('stroke', '#228B22');
d3.select(`#igtp${itgIdTag(d)}`)
.style('fill', '#228B22');
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
const integCurve = (border) => {
const { xL, xU } = border;
@@ -505,8 +624,10 @@ class LineFocus {
.attr('stroke', '#228B22');
d3.select(`#igtp${itgIdTag(d)}`)
.style('fill', '#228B22');
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
igtp.enter()
.append('text')
@@ -534,9 +655,12 @@ class LineFocus {
.attr('stroke', '#228B22');
d3.select(`#igtp${itgIdTag(d)}`)
.style('fill', '#228B22');
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
}
+ this.drawVisualSplitLines(itgs, shift, ignoreRef);
}
drawMtply(mtplySt) {
@@ -793,7 +917,7 @@ class LineFocus {
create({
filterSeed, filterPeak, tTrEndPts, tSfPeaks, freq, comparisons,
editPeakSt, layoutSt, integationSt, mtplySt,
- sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt,
wavelength,
}) {
this.svg = d3.select('.d3Svg');
@@ -804,6 +928,8 @@ class LineFocus {
this.scales = InitScale(this, this.reverseXAxis(layoutSt));
this.setTip();
this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, freq, layoutSt, wavelength);
+ Object.assign(this, { isUiSplitIntgSt, isUiVisualSplitIntgSt });
+ if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview();
MountCompass(this);
this.axis = MountAxis(this);
@@ -833,12 +959,14 @@ class LineFocus {
update({
filterSeed, filterPeak, tTrEndPts, tSfPeaks, freq, comparisons,
editPeakSt, layoutSt, integationSt, mtplySt,
- sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt,
wavelength,
}) {
this.root = d3.select(this.rootKlass).selectAll('.focus-main');
this.scales = InitScale(this, this.reverseXAxis(layoutSt));
this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, freq, layoutSt, wavelength);
+ Object.assign(this, { isUiSplitIntgSt, isUiVisualSplitIntgSt });
+ if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview();
if (this.data && this.data.length > 0) {
this.setConfig(sweepExtentSt);
diff --git a/src/components/d3_multi/index.js b/src/components/d3_multi/index.js
index d95c8928..573ab341 100644
--- a/src/components/d3_multi/index.js
+++ b/src/components/d3_multi/index.js
@@ -12,7 +12,10 @@ import {
import Format from '../../helpers/format';
import { resetAll } from '../../actions/manager';
import { selectUiSweep, scrollUiWheel, clickUiTarget } from '../../actions/ui';
-import { LIST_NON_BRUSH_TYPES } from '../../constants/list_ui';
+import {
+ addVisualSplitLine, removeVisualSplitLine, splitIntegration,
+} from '../../actions/integration';
+import { LIST_UI_SWEEP_TYPE, LIST_NON_BRUSH_TYPES } from '../../constants/list_ui';
import { addNewCylicVoltaPairPeak, addCylicVoltaMaxPeak, addCylicVoltaMinPeak } from '../../actions/cyclic_voltammetry';
import MultiFocus from './multi_focus';
@@ -29,7 +32,8 @@ class ViewerMulti extends React.Component {
super(props);
const {
- entities, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct,
+ entities, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, splitIntegrationAct,
+ addVisualSplitLineAct, removeVisualSplitLineAct,
} = this.props;
this.rootKlass = '.d3Line';
this.containerRef = React.createRef();
@@ -37,21 +41,31 @@ class ViewerMulti extends React.Component {
this.resizeObserver = null;
this.focus = new MultiFocus({
- W, H, entities, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct,
+ W,
+ H,
+ entities,
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct,
+ addVisualSplitLineAct,
+ removeVisualSplitLineAct,
});
this.normChange = this.normChange.bind(this);
this.handleResize = this.handleResize.bind(this);
+ this.syncFocusActions = this.syncFocusActions.bind(this);
}
componentDidMount() {
+ this.syncFocusActions();
this.renderChart(this.props, true);
this.setupResizeObserver();
const {
curveSt,
seed, peak, cLabel, xLabel, yLabel, feature,
tTrEndPts, tSfPeaks, editPeakSt, layoutSt,
- sweepExtentSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt,
isHidden, resetAllAct, cyclicvoltaSt,
integationSt, mtplySt, axesUnitsSt,
} = this.props;
@@ -93,6 +107,9 @@ class ViewerMulti extends React.Component {
editPeakSt,
layoutSt,
sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiVisualSplitIntgSt,
isUiNoBrushSt,
cyclicvoltaSt,
integationSt,
@@ -108,10 +125,11 @@ class ViewerMulti extends React.Component {
entities, curveSt,
seed, peak, cLabel, xLabel, yLabel,
tTrEndPts, tSfPeaks, editPeakSt, layoutSt,
- sweepExtentSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt,
isHidden, cyclicvoltaSt,
integationSt, mtplySt, axesUnitsSt,
} = this.props;
+ this.syncFocusActions();
this.normChange(prevProps);
let xxLabel = xLabel;
@@ -151,6 +169,9 @@ class ViewerMulti extends React.Component {
editPeakSt,
layoutSt,
sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
+ isUiVisualSplitIntgSt,
isUiNoBrushSt,
cyclicvoltaSt,
integationSt,
@@ -201,6 +222,22 @@ class ViewerMulti extends React.Component {
this.resizeObserver.observe(this.containerRef.current);
}
+ syncFocusActions() {
+ if (!this.focus) return;
+ const {
+ clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct,
+ splitIntegrationAct, addVisualSplitLineAct, removeVisualSplitLineAct,
+ } = this.props;
+ Object.assign(this.focus, {
+ clickUiTargetAct,
+ selectUiSweepAct,
+ scrollUiWheelAct,
+ splitIntegrationAct,
+ addVisualSplitLineAct,
+ removeVisualSplitLineAct,
+ });
+ }
+
teardownResizeObserver() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
@@ -221,10 +258,10 @@ class ViewerMulti extends React.Component {
curveSt,
seed, peak, cLabel, xLabel, yLabel, feature,
tTrEndPts, tSfPeaks, editPeakSt, layoutSt,
- sweepExtentSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiNoBrushSt,
isHidden, resetAllAct, cyclicvoltaSt,
integationSt, mtplySt, axesUnitsSt,
- entities, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct,
+ entities, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, splitIntegrationAct,
} = props;
const size = this.getTargetSize(layoutSt);
@@ -260,6 +297,7 @@ class ViewerMulti extends React.Component {
clickUiTargetAct,
selectUiSweepAct,
scrollUiWheelAct,
+ splitIntegrationAct,
});
drawMain(this.rootKlass, size.width, size.height);
@@ -272,6 +310,8 @@ class ViewerMulti extends React.Component {
editPeakSt,
layoutSt,
sweepExtentSt,
+ isUiAddIntgSt,
+ isUiSplitIntgSt,
isUiNoBrushSt,
cyclicvoltaSt,
integationSt,
@@ -305,6 +345,9 @@ const mapStateToProps = (state, props) => (
editPeakSt: state.editPeak.present,
layoutSt: state.layout,
sweepExtentSt: state.ui.sweepExtent,
+ isUiAddIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_ADD,
+ isUiSplitIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT,
+ isUiVisualSplitIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT,
isUiNoBrushSt: LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0,
cyclicvoltaSt: state.cyclicvolta,
maxminPeakSt: Feature2MaxMinPeak(state, props),
@@ -320,6 +363,9 @@ const mapDispatchToProps = (dispatch) => (
clickUiTargetAct: clickUiTarget,
selectUiSweepAct: selectUiSweep,
scrollUiWheelAct: scrollUiWheel,
+ splitIntegrationAct: splitIntegration,
+ addVisualSplitLineAct: addVisualSplitLine,
+ removeVisualSplitLineAct: removeVisualSplitLine,
addNewCylicVoltaPairPeakAct: addNewCylicVoltaPairPeak,
addCylicVoltaMaxPeakAct: addCylicVoltaMaxPeak,
addCylicVoltaMinPeakAct: addCylicVoltaMinPeak,
@@ -341,11 +387,17 @@ ViewerMulti.propTypes = {
integationSt: PropTypes.object.isRequired,
mtplySt: PropTypes.object.isRequired,
sweepExtentSt: PropTypes.object.isRequired,
+ isUiAddIntgSt: PropTypes.bool.isRequired,
+ isUiSplitIntgSt: PropTypes.bool.isRequired,
+ isUiVisualSplitIntgSt: PropTypes.bool.isRequired,
isUiNoBrushSt: PropTypes.bool.isRequired,
resetAllAct: PropTypes.func.isRequired,
clickUiTargetAct: PropTypes.func.isRequired,
selectUiSweepAct: PropTypes.func.isRequired,
scrollUiWheelAct: PropTypes.func.isRequired,
+ splitIntegrationAct: PropTypes.func.isRequired,
+ addVisualSplitLineAct: PropTypes.func.isRequired,
+ removeVisualSplitLineAct: PropTypes.func.isRequired,
isHidden: PropTypes.bool,
cyclicvoltaSt: PropTypes.object.isRequired,
maxminPeakSt: PropTypes.object,
diff --git a/src/components/d3_multi/multi_focus.js b/src/components/d3_multi/multi_focus.js
index 22a76a34..e44423f5 100644
--- a/src/components/d3_multi/multi_focus.js
+++ b/src/components/d3_multi/multi_focus.js
@@ -11,6 +11,15 @@ import {
import { PksEdit, PeckersEdit } from '../../helpers/converter';
import MountBrush from '../../helpers/brush';
import { TfRescale, MountCompass } from '../../helpers/compass';
+import {
+ clearIntegrationSplitPreview,
+ drawIntegrationSplitPreview,
+ drawIntegrationVisualSplitLines,
+ getSplitXFromEvent,
+ getVisualSplitLineAtX,
+ isAlreadyVisuallySplit,
+ isMergedVisualSplitGroup,
+} from '../../helpers/integration_split';
import { LIST_LAYOUT } from '../../constants/list_layout';
import Format from '../../helpers/format';
import {
@@ -18,9 +27,10 @@ import {
} from '../../helpers/chem';
import Cfg from '../../helpers/cfg';
import { itgIdTag, mpyIdTag } from '../../helpers/focus';
-import { calcArea } from '../../helpers/integration';
+import {
+ calcArea, getIntegrationPoints, getLinearBaseline, getVisualSplitGroups,
+} from '../../helpers/integration';
import { calcMpyCenter } from '../../helpers/multiplicity_calc';
-import { calcSlope } from '../../helpers/calc';
const d3 = require('d3');
@@ -28,6 +38,7 @@ class MultiFocus {
constructor(props) {
const {
W, H, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, entities,
+ splitIntegrationAct, addVisualSplitLineAct, removeVisualSplitLineAct,
} = props;
this.entities = entities;
@@ -45,6 +56,9 @@ class MultiFocus {
this.clickUiTargetAct = clickUiTargetAct;
this.selectUiSweepAct = selectUiSweepAct;
this.scrollUiWheelAct = scrollUiWheelAct;
+ this.splitIntegrationAct = splitIntegrationAct;
+ this.addVisualSplitLineAct = addVisualSplitLineAct;
+ this.removeVisualSplitLineAct = removeVisualSplitLineAct;
this.brush = d3.brush();
this.brushX = d3.brushX();
@@ -72,6 +86,11 @@ class MultiFocus {
this.shouldUpdate = {};
// this.freq = false;
this.layout = LIST_LAYOUT.CYCLIC_VOLTAMMETRY;
+ this.isUiAddIntgSt = false;
+ this.isUiSplitIntgSt = false;
+ this.isUiVisualSplitIntgSt = false;
+ this.integrationSplitTargets = null;
+ this.firstIntegrationPoint = null;
this.getShouldUpdate = this.getShouldUpdate.bind(this);
this.resetShouldUpdate = this.resetShouldUpdate.bind(this);
@@ -90,6 +109,11 @@ class MultiFocus {
this.drawMtply = this.drawMtply.bind(this);
this.drawAUC = this.drawAUC.bind(this);
this.onClickTarget = this.onClickTarget.bind(this);
+ this.onClickIntegrationTarget = this.onClickIntegrationTarget.bind(this);
+ this.onClickVisualSplitLine = this.onClickVisualSplitLine.bind(this);
+ this.onIntegrationMouseMove = this.onIntegrationMouseMove.bind(this);
+ this.clearSplitPreview = this.clearSplitPreview.bind(this);
+ this.drawVisualSplitLines = this.drawVisualSplitLines.bind(this);
this.mergedPeaks = this.mergedPeaks.bind(this);
this.setDataPecker = this.setDataPecker.bind(this);
this.drawPeckers = this.drawPeckers.bind(this);
@@ -338,6 +362,89 @@ class MultiFocus {
}
}
+ clearSplitPreview() {
+ clearIntegrationSplitPreview(this);
+ }
+
+ onIntegrationMouseMove(event, data, shift, ignoreRef) {
+ if (!this.isUiSplitIntgSt && !this.isUiVisualSplitIntgSt) return;
+ if (this.isUiVisualSplitIntgSt && isAlreadyVisuallySplit(data)) {
+ this.clearSplitPreview();
+ return;
+ }
+ if (this.isUiSplitIntgSt && isMergedVisualSplitGroup(data)) {
+ this.clearSplitPreview();
+ return;
+ }
+ const splitX = getSplitXFromEvent(event, this);
+ drawIntegrationSplitPreview(this, data, splitX, shift, ignoreRef);
+ }
+
+ onClickIntegrationTarget(event, data) {
+ if (!this.isUiSplitIntgSt && !this.isUiVisualSplitIntgSt) {
+ this.onClickTarget(event, data);
+ return;
+ }
+
+ event.stopPropagation();
+ event.preventDefault();
+ const splitX = getSplitXFromEvent(event, this);
+ this.clearSplitPreview();
+ if (this.isUiVisualSplitIntgSt) {
+ const { stack = [], shift = 0 } = this.integrationSplitTargets || {};
+ const existingSplitX = getVisualSplitLineAtX(this, stack, splitX, shift);
+ if (Number.isFinite(existingSplitX)) {
+ if (typeof this.removeVisualSplitLineAct !== 'function') return;
+ this.removeVisualSplitLineAct({
+ curveIdx: this.jcampIdx,
+ splitX: existingSplitX,
+ data: this.data,
+ });
+ return;
+ }
+ if (isAlreadyVisuallySplit(data)) return;
+ if (typeof this.addVisualSplitLineAct !== 'function') return;
+ this.addVisualSplitLineAct({
+ curveIdx: this.jcampIdx,
+ target: data,
+ splitX,
+ data: this.data,
+ });
+ return;
+ }
+
+ if (isMergedVisualSplitGroup(data)) return;
+ this.splitIntegrationAct({
+ curveIdx: this.jcampIdx,
+ target: data,
+ splitX,
+ data: this.data,
+ });
+ }
+
+ onClickVisualSplitLine(event, splitX) {
+ event.stopPropagation();
+ event.preventDefault();
+ this.clearSplitPreview();
+ if (typeof this.removeVisualSplitLineAct !== 'function') return;
+ this.removeVisualSplitLineAct({
+ curveIdx: this.jcampIdx,
+ splitX,
+ data: this.data,
+ });
+ }
+
+ drawVisualSplitLines(stack, shift, ignoreRef) {
+ drawIntegrationVisualSplitLines(
+ this,
+ stack,
+ shift,
+ ignoreRef,
+ this.isUiVisualSplitIntgSt,
+ this.onClickVisualSplitLine,
+ );
+ }
+
onClickPecker(event, data) {
event.stopPropagation();
event.preventDefault();
@@ -371,34 +478,30 @@ class MultiFocus {
return this.dataPeckers;
}
- drawAUC(stack) {
+ drawAUC(stack, shift = 0) {
const { xt, yt } = TfRescale(this);
- const auc = this.tags.aucPath.selectAll('path').data(stack);
+ const groups = getVisualSplitGroups(stack).map((group) => ({
+ xL: group.xL,
+ xU: group.xU,
+ isMerged: group.isMerged,
+ groupId: group.groupId,
+ target: group.items[0],
+ }));
+ const auc = this.tags.aucPath.selectAll('path').data(groups);
auc.exit()
.attr('class', 'exit')
.remove();
const integCurve = (border) => {
const { xL, xU } = border;
- const ps = this.data.filter((d) => d.x > xL && d.x < xU);
+ const ps = getIntegrationPoints(xL - shift, xU - shift, this.data);
if (!ps[0]) return null;
- const point1 = ps[0];
- const point2 = ps[ps.length - 1];
- const slope = calcSlope(point1.x, point1.y, point2.x, point2.y);
- let lastDY = point1.y;
+ const baselineY = getLinearBaseline(ps);
return d3.area()
.x((d) => xt(d.x))
- .y0((d, index) => {
- if (index > 0) {
- const lastD = ps[index - 1];
- const y = slope * (d.x - lastD.x) + lastDY;
- lastDY = y;
- return yt(y);
- }
- return yt(0);
- })
+ .y0((d) => yt(baselineY(d)))
.y1((d) => yt(d.y))(ps);
};
@@ -427,8 +530,10 @@ class MultiFocus {
.style('fill', 'red');
d3.select(`#auc${itgIdTag(d)}`)
.style('fill-opacity', 0.2);
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, true))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
}
drawPeaks(editPeakSt) {
@@ -612,6 +717,9 @@ class MultiFocus {
const { integrations } = integationSt;
const selectedIntegration = integrations[this.jcampIdx];
if (selectedIntegration === false || selectedIntegration === undefined) {
+ Object.assign(this, {
+ integrationSplitTargets: { stack: [], shift: 0, ignoreRef: false },
+ });
const itgs = [];
const igbp = this.tags.igbPath.selectAll('path').data(itgs);
igbp.exit()
@@ -626,6 +734,7 @@ class MultiFocus {
igtp.exit()
.attr('class', 'exit')
.remove();
+ this.drawVisualSplitLines([], 0, false);
return;
}
@@ -636,12 +745,23 @@ class MultiFocus {
const isDisable = Cfg.btnCmdIntg(this.layout);
const ignoreRef = Format.isHplcUvVisLayout(this.layout);
const itgs = isDisable ? [] : stack;
+ Object.assign(this, {
+ integrationSplitTargets: { stack: itgs, shift, ignoreRef },
+ });
+
+ const igGroups = getVisualSplitGroups(itgs).map((group) => ({
+ xL: group.xL,
+ xU: group.xU,
+ isMerged: group.isMerged,
+ groupId: group.groupId,
+ target: group.items[0],
+ }));
- const igbp = this.tags.igbPath.selectAll('path').data(itgs);
+ const igbp = this.tags.igbPath.selectAll('path').data(igGroups);
igbp.exit()
.attr('class', 'exit')
.remove();
- const igcp = this.tags.igcPath.selectAll('path').data(itgs);
+ const igcp = this.tags.igcPath.selectAll('path').data(igGroups);
igcp.exit()
.attr('class', 'exit')
.remove();
@@ -658,11 +778,12 @@ class MultiFocus {
.attr('class', 'exit')
.remove();
auc.merge(auc);
+ this.drawVisualSplitLines([], shift, ignoreRef);
return;
}
if (ignoreRef) {
- this.drawAUC(stack);
+ this.drawAUC(stack, shift);
} else {
// rescale for zoom
const { xt } = TfRescale(this);
@@ -703,8 +824,10 @@ class MultiFocus {
.attr('stroke', '#228B22');
d3.select(`#igtp${itgIdTag(d)}`)
.style('fill', '#228B22');
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
const integCurve = (border) => {
const { xL, xU } = border;
@@ -747,8 +870,10 @@ class MultiFocus {
.attr('stroke', '#228B22');
d3.select(`#igtp${itgIdTag(d)}`)
.style('fill', '#228B22');
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
igtp.enter()
.append('text')
@@ -776,9 +901,12 @@ class MultiFocus {
.attr('stroke', '#228B22');
d3.select(`#igtp${itgIdTag(d)}`)
.style('fill', '#228B22');
+ this.clearSplitPreview();
})
- .on('click', (event, d) => this.onClickTarget(event, d));
+ .on('mousemove', (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef))
+ .on('click', (event, d) => this.onClickIntegrationTarget(event, d));
}
+ this.drawVisualSplitLines(itgs, shift, ignoreRef);
}
drawMtply(mtplySt) {
@@ -1050,7 +1178,7 @@ class MultiFocus {
curveSt,
filterSeed, filterPeak, tTrEndPts, tSfPeaks,
editPeakSt, layoutSt,
- sweepExtentSt, isUiNoBrushSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt,
cyclicvoltaSt,
integationSt, mtplySt,
}) {
@@ -1066,6 +1194,8 @@ class MultiFocus {
this.scales = InitScale(this, this.reverseXAxis(layoutSt));
this.setTip();
this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx);
+ Object.assign(this, { isUiSplitIntgSt, isUiVisualSplitIntgSt });
+ if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview();
MountCompass(this);
this.axis = MountAxis(this);
@@ -1089,7 +1219,7 @@ class MultiFocus {
this.drawInteg(integationSt);
this.drawMtply(mtplySt);
}
- MountBrush(this, false, isUiNoBrushSt);
+ MountBrush(this, isUiAddIntgSt, isUiNoBrushSt);
this.resetShouldUpdate(editPeakSt);
}
@@ -1097,7 +1227,7 @@ class MultiFocus {
entities, curveSt,
filterSeed, filterPeak, tTrEndPts, tSfPeaks,
editPeakSt, layoutSt,
- sweepExtentSt, isUiNoBrushSt, cyclicvoltaSt,
+ sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt,
integationSt, mtplySt,
}) {
this.root = d3.select(this.rootKlass).selectAll('.focus-main');
@@ -1109,6 +1239,8 @@ class MultiFocus {
this.entities = entities;
this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx);
+ Object.assign(this, { isUiSplitIntgSt, isUiVisualSplitIntgSt });
+ if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview();
if (this.data && this.data.length > 0) {
this.setConfig(sweepExtentSt);
@@ -1123,7 +1255,7 @@ class MultiFocus {
this.drawInteg(integationSt);
this.drawMtply(mtplySt);
}
- MountBrush(this, false, isUiNoBrushSt);
+ MountBrush(this, isUiAddIntgSt, isUiNoBrushSt);
this.resetShouldUpdate(editPeakSt);
}
}
diff --git a/src/components/d3_rect/rect_focus.js b/src/components/d3_rect/rect_focus.js
index 650c3370..a33d364f 100644
--- a/src/components/d3_rect/rect_focus.js
+++ b/src/components/d3_rect/rect_focus.js
@@ -51,6 +51,8 @@ class RectFocus {
this.factor = 0.125;
this.currentExtent = null;
this.layout = LIST_LAYOUT.MS;
+ this.isUiAddIntgSt = false;
+ this.firstIntegrationPoint = null;
this.setTip = this.setTip.bind(this);
this.setDataParams = this.setDataParams.bind(this);
diff --git a/src/components/panel/graph_selection.js b/src/components/panel/graph_selection.js
index ab65afa2..56f2054b 100644
--- a/src/components/panel/graph_selection.js
+++ b/src/components/panel/graph_selection.js
@@ -55,12 +55,13 @@ const GraphSelectionPanel = ({
if (subLayoutsInfo) {
subLayoutValues = Object.keys(subLayoutsInfo);
}
+ const subLayoutKey = subLayoutValues.join('|');
const [selectedSubLayout, setSelectedSublayout] = useState(subLayoutValues[0]);
useEffect(() => {
setSelectedSublayout(subLayoutValues[0]);
- }, subLayoutValues);
+ }, [subLayoutKey]);
if (!curveSt) {
return ();
diff --git a/src/constants/action_type.js b/src/constants/action_type.js
index 1781efa7..29c0bb9a 100644
--- a/src/constants/action_type.js
+++ b/src/constants/action_type.js
@@ -88,6 +88,9 @@ const INTEGRATION = {
RESET_ALL_RDC: 'INTEGRATION_RESET_ALL_RDC',
CLEAR_ALL: 'INTEGRATION_CLEAR_ALL',
SWEEP: 'INTEGRATION_SWEEP',
+ SPLIT: 'INTEGRATION_SPLIT',
+ ADD_VISUAL_SPLIT: 'INTEGRATION_ADD_VISUAL_SPLIT',
+ RM_VISUAL_SPLIT: 'INTEGRATION_RM_VISUAL_SPLIT',
};
const SIMULATION = {
diff --git a/src/constants/list_ui.js b/src/constants/list_ui.js
index c8aab9bd..f3ad16f0 100644
--- a/src/constants/list_ui.js
+++ b/src/constants/list_ui.js
@@ -10,6 +10,8 @@ const LIST_UI_SWEEP_TYPE = {
INTEGRATION_RM: 'integration remove',
INTEGRATION_REF: 'integration reference',
INTEGRATION_SET_REF: 'integration set ref',
+ INTEGRATION_SPLIT: 'integration split',
+ INTEGRATION_VISUAL_SPLIT: 'integration visual split',
MULTIPLICITY_SWEEP_ADD: 'multiplicity sweep add',
MULTIPLICITY_ONE_CLICK: 'multiplicity one click',
MULTIPLICITY_ONE_RM: 'multiplicity one remove',
@@ -34,6 +36,8 @@ const LIST_NON_BRUSH_TYPES = [
LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT,
LIST_UI_SWEEP_TYPE.INTEGRATION_RM,
LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF,
+ LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT,
+ LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT,
LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_ADD,
LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_RM,
LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_CLICK,
diff --git a/src/helpers/brush.js b/src/helpers/brush.js
index e4e63e5d..4b4f36db 100644
--- a/src/helpers/brush.js
+++ b/src/helpers/brush.js
@@ -1,9 +1,16 @@
/* eslint-disable prefer-object-spread */
-import { MouseMove } from './compass';
+import { clearIntegrationPreview, MouseMove } from './compass';
+import { clearPendingIntegrationDraft } from './integration_draft.js'; // eslint-disable-line import/extensions
+import { buildSweepPayloadFromXBounds } from './sweep.js'; // eslint-disable-line import/extensions
const d3 = require('d3');
+const selectBrushLayer = (focus, selector) => {
+ const svg = focus.svg || d3.select('.d3Svg');
+ return svg.selectAll(selector);
+};
+
const wheeled = (focus, event) => {
const { currentExtent, scrollUiWheelAct } = focus;
// WORKAROUND: firefox wheel compatibilty
@@ -14,7 +21,7 @@ const wheeled = (focus, event) => {
const brushed = (focus, isUiAddIntgSt, event) => {
const {
- selectUiSweepAct, data, dataPks, brush, w, h, scales,
+ selectUiSweepAct, data, dataPks, brush, brushX, w, h, scales,
} = focus;
const selection = event.selection && event.selection.reverse();
if (!selection) return;
@@ -23,53 +30,60 @@ const brushed = (focus, isUiAddIntgSt, event) => {
let xExtent = { xL: xes[0], xU: xes[1] };
let yExtent = { yL: yes[0], yU: yes[1] };
if (isUiAddIntgSt) {
- xes = selection.map(scales.x.invert).sort((a, b) => a - b);
- xExtent = { xL: xes[0], xU: xes[1] };
- } else {
- const [begPt, endPt] = selection;
- xes = [begPt[0], endPt[0]].map(scales.x.invert).sort((a, b) => a - b);
- yes = [begPt[1], endPt[1]].map(scales.y.invert).sort((a, b) => a - b);
- xExtent = { xL: xes[0], xU: xes[1] };
- yExtent = { yL: yes[0], yU: yes[1] };
+ const payload = buildSweepPayloadFromXBounds(
+ focus,
+ scales.x.invert(selection[0]),
+ scales.x.invert(selection[1]),
+ );
+ selectUiSweepAct(payload);
+ if (brushX) {
+ selectBrushLayer(focus, '.brushX').call(brushX.move, null);
+ }
+ return;
}
+ const [begPt, endPt] = selection;
+ xes = [begPt[0], endPt[0]].map(scales.x.invert).sort((a, b) => a - b);
+ yes = [begPt[1], endPt[1]].map(scales.y.invert).sort((a, b) => a - b);
+ xExtent = { xL: xes[0], xU: xes[1] };
+ yExtent = { yL: yes[0], yU: yes[1] };
selectUiSweepAct({
xExtent, yExtent, data, dataPks,
});
- d3.select('.d3Svg').selectAll('.brush').call(brush.move, null);
+ selectBrushLayer(focus, '.brush').call(brush.move, null);
};
const MountBrush = (focus, isUiAddIntgSt, isUiNoBrushSt) => {
const {
- root, svg, brush, brushX, w, h,
+ root, svg, brush, w, h,
} = focus;
svg.selectAll('.brush').remove();
svg.selectAll('.brushX').remove();
+ Object.assign(focus, { isUiAddIntgSt });
+ const { firstIntegrationPoint, data, jcampIdx } = focus;
+ const isSameIntegrationDraft = firstIntegrationPoint
+ && firstIntegrationPoint.jcampIdx === jcampIdx
+ && firstIntegrationPoint.dataLength === data.length;
+ if (!isUiAddIntgSt || (firstIntegrationPoint && !isSameIntegrationDraft)) {
+ clearPendingIntegrationDraft();
+ Object.assign(focus, { firstIntegrationPoint: null });
+ clearIntegrationPreview(focus);
+ }
const brushedCb = (event) => brushed(focus, isUiAddIntgSt, event);
const wheeledCb = (event) => wheeled(focus, event);
- if (isUiNoBrushSt) {
- const target = isUiAddIntgSt ? brushX : brush;
- target.handleSize(10)
+ if (isUiNoBrushSt && !isUiAddIntgSt) {
+ brush.handleSize(10)
.extent([[0, 0], [w, h]])
.on('end', brushedCb);
- // append brush components
- const klass = isUiAddIntgSt ? 'brushX' : 'brush';
root.append('g')
- .attr('class', klass)
+ .attr('class', 'brush')
.on('mousemove', (event) => MouseMove(event, focus))
- .call(target);
+ .call(brush);
}
svg.on('wheel', wheeledCb);
};
export default MountBrush;
-
-// const resetedCb = () => reseted(main);
-// main.svg.on('dblclick', resetedCb);
-// const reseted = (main) => {
-// const { selectUiSweepAct } = main;
-// selectUiSweepAct({ xExtent: false, yExtent: false });
-// };
diff --git a/src/helpers/chem.js b/src/helpers/chem.js
index 491a1529..16dca3f2 100644
--- a/src/helpers/chem.js
+++ b/src/helpers/chem.js
@@ -511,20 +511,42 @@ const calcIntgRefArea = (spectra, stack) => {
return { raw2realRatio };
};
+const parseObservedIntegralGroups = (rawValue) => {
+ if (!rawValue) return {};
+ const tokenRegx = /[^A-Za-z0-9._-]/g;
+ const groupsByIdx = {};
+ rawValue.split('\n').forEach((line) => {
+ const cells = line.split(',').map((c) => c.replace(tokenRegx, ''));
+ if (cells.length < 2) return;
+ const idx = parseInt(cells[0], 10);
+ const groupId = cells[1];
+ if (!Number.isInteger(idx) || idx < 0 || !groupId) return;
+ groupsByIdx[idx] = groupId;
+ });
+ return groupsByIdx;
+};
+
const buildIntegFeature = (jcamp, spectra) => {
- const { $OBSERVEDINTEGRALS, $OBSERVEDMULTIPLETS } = jcamp.info;
+ const {
+ $OBSERVEDINTEGRALS, $OBSERVEDMULTIPLETS, $OBSERVEDINTEGRALSGROUPS,
+ } = jcamp.info;
const regx = /[^0-9.,-]/g;
let stack = [];
if ($OBSERVEDINTEGRALS) {
const its = $OBSERVEDINTEGRALS.split('\n').slice(1);
- const itStack = its.map((t) => {
+ const groupsByIdx = parseObservedIntegralGroups($OBSERVEDINTEGRALSGROUPS);
+ const itStack = its.map((t, idx) => {
const ts = t.replace(regx, '').split(',');
- return {
+ const item = {
xL: parseFloat(ts[0]),
xU: parseFloat(ts[1]),
area: parseFloat(ts[2]),
absoluteArea: parseFloat(ts[3]),
};
+ const groupId = groupsByIdx[idx];
+ return groupId
+ ? Object.assign({}, item, { visualSplitGroupId: groupId })
+ : item;
});
stack = [...stack, ...itStack];
}
@@ -787,7 +809,7 @@ const ExtractJcamp = (source) => {
source,
{
xy: true,
- keepRecordsRegExp: /(\$CSTHRESHOLD|\$CSSCANAUTOTARGET|\$CSSCANEDITTARGET|\$CSSCANCOUNT|\$CSSOLVENTNAME|\$CSSOLVENTVALUE|\$CSSOLVENTX|\$CSCATEGORY|\$CSITAREA|\$CSITFACTOR|\$OBSERVEDINTEGRALS|\$OBSERVEDMULTIPLETS|\$OBSERVEDMULTIPLETSPEAKS|\.SOLVENTNAME|\.OBSERVEFREQUENCY|\$CSSIMULATIONPEAKS|\$CSUPPERTHRESHOLD|\$CSLOWERTHRESHOLD|\$CSCYCLICVOLTAMMETRYDATA|UNITS|SYMBOL|\$CSAUTOMETADATA|\$DETECTOR|MN|MW|D|MP|MELTINGPOINT|TG|\$CSSCANRATE|\$CSSPECTRUMDIRECTION|\$CSWEAREAVALUE|\$CSWEAREAUNIT|\$CSCURRENTMODE)/, // eslint-disable-line
+ keepRecordsRegExp: /(\$CSTHRESHOLD|\$CSSCANAUTOTARGET|\$CSSCANEDITTARGET|\$CSSCANCOUNT|\$CSSOLVENTNAME|\$CSSOLVENTVALUE|\$CSSOLVENTX|\$CSCATEGORY|\$CSITAREA|\$CSITFACTOR|\$OBSERVEDINTEGRALS|\$OBSERVEDINTEGRALSGROUPS|\$OBSERVEDMULTIPLETS|\$OBSERVEDMULTIPLETSPEAKS|\.SOLVENTNAME|\.OBSERVEFREQUENCY|\$CSSIMULATIONPEAKS|\$CSUPPERTHRESHOLD|\$CSLOWERTHRESHOLD|\$CSCYCLICVOLTAMMETRYDATA|UNITS|SYMBOL|\$CSAUTOMETADATA|\$DETECTOR|MN|MW|D|MP|MELTINGPOINT|TG|\$CSSCANRATE|\$CSSPECTRUMDIRECTION|\$CSWEAREAVALUE|\$CSWEAREAUNIT|\$CSCURRENTMODE)/, // eslint-disable-line
},
);
const layout = readLayout(jcamp);
@@ -886,4 +908,5 @@ export {
GetCyclicVoltaRatio, GetCyclicVoltaPeakSeparate,
Feature2MaxMinPeak, convertTopic, Convert2MaxMinPeak,
GetCyclicVoltaShiftOffset, GetCyclicVoltaPreviousShift,
+ buildIntegFeature,
};
diff --git a/src/helpers/compass.js b/src/helpers/compass.js
index 038faaff..2a4c76d6 100644
--- a/src/helpers/compass.js
+++ b/src/helpers/compass.js
@@ -1,5 +1,17 @@
import Format from './format';
import { Convert2DValue } from './chem';
+import { buildSweepPayloadFromXBounds } from './sweep.js'; // eslint-disable-line import/extensions
+import {
+ forgetPendingIntegrationDraft,
+ setPendingIntegrationDraft,
+} from './integration_draft.js'; // eslint-disable-line import/extensions
+import {
+ clearIntegrationSplitPreview,
+ drawIntegrationSplitPreview,
+ getIntegrationSplitTargetFromEvent,
+ getVisualSplitLineAtX,
+ isAlreadyVisuallySplit,
+} from './integration_split';
const d3 = require('d3');
@@ -10,26 +22,17 @@ const TfRescale = (focus) => {
};
const fetchPt = (event, focus, xt) => {
- // const rawMouseX = focus.isFirefox // WORKAROUND d3.mouse firefox compatibility
- // ? d3.event.offsetX
- // : d3.mouse(focus.root.node())[0];
const rawMouseX = d3.pointer(event, focus.root.node())[0];
const mouseX = xt.invert(rawMouseX);
const bisectDate = d3.bisector((d) => +d.x).left;
const dt = focus.data;
const ls = dt.length;
- const sortData = ls > 0 && dt[0].x > dt[ls - 1].x ? dt.reverse() : dt;
+ const sortData = ls > 0 && dt[0].x > dt[ls - 1].x ? [...dt].reverse() : dt;
const idx = bisectDate(sortData, +mouseX);
- return sortData[idx];
+ return sortData[Math.min(idx, ls - 1)];
};
const fetchFreePt = (event, focus, xt, yt) => {
- // const rawMouseX = focus.isFirefox // WORKAROUND d3.mouse firefox compatibility
- // ? d3.event.offsetX
- // : d3.mouse(focus.root.node())[0];
- // const rawMouseY = focus.isFirefox // WORKAROUND d3.mouse firefox compatibility
- // ? d3.event.offsetY
- // : d3.mouse(focus.root.node())[1];
const rawMouseX = d3.pointer(event, focus.root.node())[0];
const rawMouseY = d3.pointer(event, focus.root.node())[1];
const mouseX = xt.invert(rawMouseX);
@@ -55,6 +58,73 @@ const fetchFreePt = (event, focus, xt, yt) => {
return selectPoint;
};
+const clearIntegrationPreview = (focus) => {
+ if (!focus || !focus.root) return;
+ focus.root.select('.integration-preview-line').remove();
+};
+
+const drawIntegrationPreview = (focus, firstPoint, nextPoint) => {
+ if (!firstPoint || !nextPoint) return;
+ const { xt, yt } = TfRescale(focus);
+ const preview = focus.root.select('.integration-preview');
+ const line = preview.selectAll('.integration-preview-line').data([{
+ firstPoint,
+ nextPoint,
+ }]);
+
+ line.enter()
+ .append('line')
+ .attr('class', 'integration-preview-line')
+ .attr('stroke', 'red')
+ .attr('stroke-width', 2)
+ .attr('stroke-dasharray', '4,3')
+ .style('pointer-events', 'none')
+ .merge(line)
+ .attr('x1', (d) => xt(d.firstPoint.x))
+ .attr('y1', (d) => yt(d.firstPoint.y))
+ .attr('x2', (d) => xt(d.nextPoint.x))
+ .attr('y2', (d) => yt(d.nextPoint.y));
+};
+
+const getCurvePointFromEvent = (event, focus) => {
+ const { xt, yt } = TfRescale(focus);
+ if (Format.isCyclicVoltaLayout(focus.layout)) {
+ return fetchFreePt(event, focus, xt, yt);
+ }
+ return fetchPt(event, focus, xt);
+};
+
+const cancelIntegrationDraft = (focus) => {
+ Object.assign(focus, { firstIntegrationPoint: null });
+ clearIntegrationPreview(focus);
+ forgetPendingIntegrationDraft();
+};
+
+const updateIntegrationPreview = (event, focus) => {
+ if (!focus.isUiAddIntgSt || !focus.firstIntegrationPoint) return;
+ const pt = getCurvePointFromEvent(event, focus);
+ if (!pt) return;
+ drawIntegrationPreview(focus, focus.firstIntegrationPoint, pt);
+};
+
+const updateIntegrationSplitPreview = (event, focus) => {
+ if (!focus.isUiSplitIntgSt && !focus.isUiVisualSplitIntgSt) return;
+
+ const { splitX, target } = getIntegrationSplitTargetFromEvent(event, focus);
+ if (!target) {
+ clearIntegrationSplitPreview(focus);
+ return;
+ }
+
+ if (focus.isUiVisualSplitIntgSt && isAlreadyVisuallySplit(target)) {
+ clearIntegrationSplitPreview(focus);
+ return;
+ }
+
+ const { shift = 0, ignoreRef = false } = focus.integrationSplitTargets || {};
+ drawIntegrationSplitPreview(focus, target, splitX, shift, ignoreRef);
+};
+
const MouseMove = (event, focus) => {
const { xt, yt } = TfRescale(focus);
const { freq, layout, wavelength } = focus;
@@ -117,11 +187,92 @@ const MouseMove = (event, focus) => {
}
}
}
+ updateIntegrationPreview(event, focus);
+ updateIntegrationSplitPreview(event, focus);
+};
+
+const clickIntegrationPoint = (event, focus) => {
+ const pt = getCurvePointFromEvent(event, focus);
+ if (!pt) return;
+
+ const { firstIntegrationPoint, selectUiSweepAct } = focus;
+ if (!firstIntegrationPoint) {
+ // Keep the draft local to D3; the second click emits the existing sweep payload.
+ const draftPoint = {
+ x: pt.x,
+ y: pt.y,
+ jcampIdx: focus.jcampIdx,
+ dataLength: focus.data.length,
+ };
+ Object.assign(focus, { firstIntegrationPoint: draftPoint });
+ setPendingIntegrationDraft({
+ jcampIdx: focus.jcampIdx,
+ dataLength: focus.data.length,
+ cancel: () => cancelIntegrationDraft(focus),
+ });
+ drawIntegrationPreview(focus, draftPoint, draftPoint);
+ return;
+ }
+
+ cancelIntegrationDraft(focus);
+ if (firstIntegrationPoint.x === pt.x) {
+ return;
+ }
+
+ selectUiSweepAct(buildSweepPayloadFromXBounds(
+ focus,
+ firstIntegrationPoint.x,
+ pt.x,
+ ));
};
const ClickCompass = (event, focus) => {
event.stopPropagation();
event.preventDefault();
+ if (focus.isUiAddIntgSt) {
+ clickIntegrationPoint(event, focus);
+ return;
+ }
+ if (focus.isUiSplitIntgSt) {
+ const { splitX, target } = getIntegrationSplitTargetFromEvent(event, focus);
+ if (!target) return;
+
+ clearIntegrationSplitPreview(focus);
+ focus.splitIntegrationAct({
+ curveIdx: focus.jcampIdx,
+ target,
+ splitX,
+ data: focus.data,
+ });
+ return;
+ }
+ if (focus.isUiVisualSplitIntgSt) {
+ const { splitX, target } = getIntegrationSplitTargetFromEvent(event, focus);
+ if (!target) return;
+
+ const { stack = [], shift = 0 } = focus.integrationSplitTargets || {};
+ const existingSplitX = getVisualSplitLineAtX(focus, stack, splitX, shift);
+ clearIntegrationSplitPreview(focus);
+ if (Number.isFinite(existingSplitX)) {
+ if (typeof focus.removeVisualSplitLineAct !== 'function') return;
+ focus.removeVisualSplitLineAct({
+ curveIdx: focus.jcampIdx,
+ splitX: existingSplitX,
+ data: focus.data,
+ });
+ return;
+ }
+ if (isAlreadyVisuallySplit(target)) return;
+ if (typeof focus.addVisualSplitLineAct !== 'function') return;
+ focus.addVisualSplitLineAct({
+ curveIdx: focus.jcampIdx,
+ target,
+ splitX,
+ data: focus.data,
+ });
+ return;
+ }
+
const { xt, yt } = TfRescale(focus);
let pt = fetchPt(event, focus, xt);
const { layout, cyclicvoltaSt, jcampIdx } = focus;
@@ -147,6 +298,9 @@ const MountCompass = (focus) => {
.attr('class', 'compass');
const cursor = root.append('g')
.attr('class', 'cursor');
+ const preview = root.append('g')
+ .attr('class', 'integration-preview')
+ .attr('clip-path', 'url(#clip)');
const overlay = root.append('rect')
.attr('class', 'overlay-focus')
.attr('width', w)
@@ -174,6 +328,8 @@ const MountCompass = (focus) => {
.style('text-anchor', 'middle')
.style('fill', '#D68910');
+ preview.selectAll('*').remove();
+
overlay
.on('mousemove', (event) => MouseMove(event, focus))
.on('click', (event) => ClickCompass(event, focus));
@@ -184,4 +340,6 @@ export {
TfRescale,
ClickCompass,
MouseMove,
+ getCurvePointFromEvent,
+ clearIntegrationPreview,
};
diff --git a/src/helpers/integration.js b/src/helpers/integration.js
index 8fbfc1ab..865066e0 100644
--- a/src/helpers/integration.js
+++ b/src/helpers/integration.js
@@ -14,23 +14,35 @@ const getArea = (xL, xU, data) => {
return Math.abs(data[iU].k - data[iL].k);
};
+const getIntegrationPoints = (xL, xU, data) => data.filter((d) => (
+ d
+ && Number.isFinite(d.x)
+ && Number.isFinite(d.y)
+ && d.x > xL
+ && d.x < xU
+));
+
+const getLinearBaseline = (points) => {
+ if (!points || !points[0]) return () => 0;
+
+ const point1 = points[0];
+ const point2 = points[points.length - 1];
+ const slope = calcSlope(point1.x, point1.y, point2.x, point2.y);
+
+ return (point) => point1.y + slope * (point.x - point1.x);
+};
+
const getAbsoluteArea = (xL, xU, data) => {
- const ps = data.filter((d) => d.x > xL && d.x < xU);
- if (!ps[0]) return 0;
+ const ps = getIntegrationPoints(xL, xU, data);
+ if (ps.length < 2) return 0;
+ const baselineY = getLinearBaseline(ps);
let area = 0;
- const point1 = ps[0];
- const point2 = ps[ps.length - 1];
- const slope = calcSlope(point1.x, point1.y, point2.x, point2.y);
- let lastDY = point1.y;
if (ps.length > 1) {
for (let i = 1; i < ps.length; i += 1) {
const pt = ps[i];
- const lastD = ps[i - 1];
- const y = slope * (pt.x - lastD.x) + lastDY;
- lastDY = y;
- const delta = Math.abs(pt.y - y);
+ const delta = Math.abs(pt.y - baselineY(pt));
area += delta;
}
}
@@ -38,6 +50,57 @@ const getAbsoluteArea = (xL, xU, data) => {
return area;
};
+const normalizeSplitLines = (splitLines) => {
+ if (!Array.isArray(splitLines)) return [];
+ const finiteValues = splitLines
+ .map((value) => parseFloat(value))
+ .filter((value) => Number.isFinite(value));
+ return [...new Set(finiteValues)].sort((a, b) => a - b);
+};
+
+const buildSplitIntervals = (xL, xU, splitLines = []) => {
+ if (!Number.isFinite(xL) || !Number.isFinite(xU)) return [];
+
+ const [lower, upper] = [xL, xU].sort((a, b) => a - b);
+ if (lower === upper) return [];
+
+ const sortedSplitLines = normalizeSplitLines(splitLines)
+ .filter((splitX) => splitX > lower && splitX < upper);
+
+ return [lower, ...sortedSplitLines, upper].slice(1).map((right, index, bounds) => ({
+ xL: index === 0 ? lower : bounds[index - 1],
+ xU: right,
+ }));
+};
+
+const getAbsoluteAreaWithBaseline = (xL, xU, data, baselineY) => {
+ const ps = getIntegrationPoints(xL, xU, data);
+ if (ps.length < 2 || typeof baselineY !== 'function') return 0;
+
+ let area = 0;
+ for (let i = 1; i < ps.length; i += 1) {
+ const pt = ps[i];
+ const baselineValue = baselineY(pt);
+ if (Number.isFinite(baselineValue)) {
+ area += Math.abs(pt.y - baselineValue);
+ }
+ }
+ return area;
+};
+
+const getSplitAreas = (xL, xU, splitLines, data) => {
+ const intervals = buildSplitIntervals(xL, xU, splitLines);
+ const mainPoints = getIntegrationPoints(xL, xU, data);
+ const baselineY = getLinearBaseline(mainPoints);
+
+ return intervals.map((interval) => ({
+ xL: interval.xL,
+ xU: interval.xU,
+ area: getArea(interval.xL, interval.xU, data),
+ absoluteArea: getAbsoluteAreaWithBaseline(interval.xL, interval.xU, data, baselineY),
+ }));
+};
+
const calcArea = (d, refArea, refFactor, ignoreRef = false) => {
if (ignoreRef) {
const { absoluteArea } = d;
@@ -46,4 +109,84 @@ const calcArea = (d, refArea, refFactor, ignoreRef = false) => {
return (d.area * refFactor / refArea).toFixed(2);
};
-export { getArea, calcArea, getAbsoluteArea }; // eslint-disable-line
+const splitAreaProportionally = (totalArea, leftRaw, rightRaw) => {
+ const safeTotal = Number.isFinite(totalArea) ? totalArea : 0;
+ if (safeTotal === 0) return { left: 0, right: 0 };
+
+ const safeLeft = Number.isFinite(leftRaw) ? Math.max(leftRaw, 0) : 0;
+ const safeRight = Number.isFinite(rightRaw) ? Math.max(rightRaw, 0) : 0;
+ const rawSum = safeLeft + safeRight;
+ if (rawSum <= 0) {
+ const half = safeTotal / 2;
+ return { left: half, right: half };
+ }
+
+ const ratio = safeTotal / rawSum;
+ return { left: safeLeft * ratio, right: safeRight * ratio };
+};
+
+let visualSplitGroupCounter = 0;
+const generateVisualSplitGroupId = () => {
+ visualSplitGroupCounter += 1;
+ const seed = (typeof Date !== 'undefined' && Date.now)
+ ? Date.now().toString(36)
+ : Math.random().toString(36).slice(2);
+ return `vsg-${seed}-${visualSplitGroupCounter}`;
+};
+
+const getVisualSplitGroups = (stack = []) => {
+ if (!Array.isArray(stack) || stack.length === 0) return [];
+ const groups = [];
+ let current = null;
+ stack.forEach((item) => {
+ const groupId = item && item.visualSplitGroupId;
+ if (groupId && current && current.groupId === groupId) {
+ current.items.push(item);
+ current.xL = Math.min(current.xL, item.xL);
+ current.xU = Math.max(current.xU, item.xU);
+ } else {
+ current = {
+ groupId: groupId || null,
+ items: [item],
+ xL: item.xL,
+ xU: item.xU,
+ isMerged: false,
+ };
+ groups.push(current);
+ }
+ });
+ groups.forEach((group) => {
+ // eslint-disable-next-line no-param-reassign
+ group.isMerged = !!group.groupId && group.items.length > 1;
+ });
+ return groups;
+};
+
+const getVisualSplitGroupBoundaries = (group) => {
+ if (!group || !group.isMerged) return [];
+ const sortedItems = [...group.items].sort((a, b) => a.xL - b.xL);
+ const boundaries = [];
+ for (let i = 0; i < sortedItems.length - 1; i += 1) {
+ const current = sortedItems[i];
+ const next = sortedItems[i + 1];
+ const boundary = (current.xU + next.xL) / 2;
+ if (Number.isFinite(boundary)) boundaries.push(boundary);
+ }
+ return boundaries;
+};
+
+export {
+ buildSplitIntervals,
+ calcArea,
+ generateVisualSplitGroupId,
+ getAbsoluteArea,
+ getAbsoluteAreaWithBaseline,
+ getArea,
+ getIntegrationPoints,
+ getLinearBaseline,
+ getSplitAreas,
+ getVisualSplitGroupBoundaries,
+ getVisualSplitGroups,
+ normalizeSplitLines,
+ splitAreaProportionally,
+}; // eslint-disable-line
diff --git a/src/helpers/integration_draft.js b/src/helpers/integration_draft.js
new file mode 100644
index 00000000..b911c1e9
--- /dev/null
+++ b/src/helpers/integration_draft.js
@@ -0,0 +1,45 @@
+let pendingIntegrationDraft = null;
+
+const cancelMessage = 'You are currently creating an integration. Are you sure you want to cancel it?';
+
+const hasPendingIntegrationDraft = () => !!pendingIntegrationDraft;
+
+const setPendingIntegrationDraft = (draft) => {
+ pendingIntegrationDraft = draft;
+};
+
+const forgetPendingIntegrationDraft = () => {
+ pendingIntegrationDraft = null;
+};
+
+const clearPendingIntegrationDraft = () => {
+ const draft = pendingIntegrationDraft;
+ pendingIntegrationDraft = null;
+ if (draft && typeof draft.cancel === 'function') {
+ draft.cancel();
+ }
+};
+
+const confirmCancelPendingIntegration = () => {
+ if (!hasPendingIntegrationDraft()) return true;
+
+ const shouldCancel = typeof window === 'undefined'
+ || typeof window.confirm !== 'function'
+ // This confirmation intentionally protects an in-progress two-click integration.
+ // eslint-disable-next-line no-alert
+ || window.confirm(cancelMessage);
+
+ if (shouldCancel) {
+ clearPendingIntegrationDraft();
+ }
+
+ return shouldCancel;
+};
+
+export {
+ clearPendingIntegrationDraft,
+ confirmCancelPendingIntegration,
+ forgetPendingIntegrationDraft,
+ hasPendingIntegrationDraft,
+ setPendingIntegrationDraft,
+};
diff --git a/src/helpers/integration_split.js b/src/helpers/integration_split.js
new file mode 100644
index 00000000..4331c577
--- /dev/null
+++ b/src/helpers/integration_split.js
@@ -0,0 +1,242 @@
+import {
+ getIntegrationPoints,
+ getLinearBaseline,
+ getVisualSplitGroupBoundaries,
+ getVisualSplitGroups,
+} from './integration';
+
+const d3 = require('d3');
+
+const SPLIT_PREVIEW_CLASS = 'integration-split-preview-line';
+const VISUAL_SPLIT_CLASS = 'integration-visual-split-line';
+const VISUAL_SPLIT_HIT_TOLERANCE_PX = 6;
+const NMR_SPLIT_PREVIEW_EXTENT = { y1: 38, y2: 55 };
+
+const getIntegrationBounds = (target, shift = 0) => (
+ [target.xL - shift, target.xU - shift].sort((a, b) => a - b)
+);
+
+const getSplitXFromEvent = (event, focus) => {
+ const rawMouseX = d3.pointer(event, focus.root.node())[0];
+ return focus.scales.x.invert(rawMouseX);
+};
+
+const clearIntegrationSplitPreview = (focus) => {
+ if (!focus || !focus.root) return;
+ focus.root.select(`.${SPLIT_PREVIEW_CLASS}`).remove();
+};
+
+const isAlreadyVisuallySplit = (target) => {
+ if (!target) return false;
+ return !!target.visualSplitGroupId || target.isMerged === true;
+};
+
+const isMergedVisualSplitGroup = (target) => !!(target && target.isMerged === true);
+
+const resolveBaselineContextBounds = (focus, target, shift) => {
+ if (target && target.isMerged === true) {
+ return getIntegrationBounds(target, shift);
+ }
+ const groupId = target && target.visualSplitGroupId;
+ const stack = focus && focus.integrationSplitTargets && focus.integrationSplitTargets.stack;
+ if (groupId && Array.isArray(stack)) {
+ const siblings = stack.filter((item) => item && item.visualSplitGroupId === groupId);
+ if (siblings.length > 1) {
+ const lower = Math.min(...siblings.map((item) => item.xL)) - shift;
+ const upper = Math.max(...siblings.map((item) => item.xU)) - shift;
+ return [lower, upper].sort((a, b) => a - b);
+ }
+ }
+ return getIntegrationBounds(target, shift);
+};
+
+const getIntegrationSplitTarget = (focus, splitX) => {
+ const splitTargets = focus && focus.integrationSplitTargets;
+ if (!splitTargets || !Number.isFinite(splitX)) return null;
+
+ const { stack = [], shift = 0 } = splitTargets;
+ return stack.find((target) => {
+ const [xL, xU] = getIntegrationBounds(target, shift);
+ return splitX > xL && splitX < xU;
+ });
+};
+
+const getIntegrationSplitTargetFromEvent = (event, focus) => {
+ const splitX = getSplitXFromEvent(event, focus);
+ const target = getIntegrationSplitTarget(focus, splitX);
+
+ return { splitX, target };
+};
+
+const getVisualSplitLines = (stack = [], shift = 0) => {
+ if (!Array.isArray(stack)) return [];
+ return getVisualSplitGroups(stack)
+ .filter((group) => group.isMerged)
+ .reduce((acc, group) => {
+ getVisualSplitGroupBoundaries(group).forEach((boundary) => {
+ const value = boundary - shift;
+ if (Number.isFinite(value)) acc.push(value);
+ });
+ return acc;
+ }, []);
+};
+
+const getVisualSplitLineAtX = (
+ focus,
+ stack,
+ splitX,
+ shift = 0,
+ pixelTolerance = VISUAL_SPLIT_HIT_TOLERANCE_PX,
+) => {
+ if (!focus || !focus.scales || !focus.scales.x || !Number.isFinite(splitX)) return null;
+
+ const xt = focus.scales.x;
+ const splitXPx = xt(splitX);
+ const nearest = getVisualSplitLines(stack, shift).reduce((acc, lineX) => {
+ const distance = Math.abs(xt(lineX) - splitXPx);
+ if (!acc || distance < acc.distance) {
+ return { splitX: lineX, distance };
+ }
+ return acc;
+ }, null);
+
+ return nearest && nearest.distance <= pixelTolerance ? nearest.splitX : null;
+};
+
+const interpolateY = (points, x) => {
+ if (!points || points.length === 0) return null;
+ const sortedPoints = [...points].sort((a, b) => a.x - b.x);
+ const upperIndex = sortedPoints.findIndex((point) => point.x >= x);
+ if (upperIndex < 0) return sortedPoints[sortedPoints.length - 1].y;
+ if (upperIndex === 0) return sortedPoints[0].y;
+
+ const lowerPoint = sortedPoints[upperIndex - 1];
+ const upperPoint = sortedPoints[upperIndex];
+ const xDelta = upperPoint.x - lowerPoint.x;
+ if (xDelta === 0) return lowerPoint.y;
+
+ const ratio = (x - lowerPoint.x) / xDelta;
+ return lowerPoint.y + ratio * (upperPoint.y - lowerPoint.y);
+};
+
+const resolveSplitPreviewExtent = (focus, target, splitX, shift, ignoreRef) => {
+ if (!focus || !target || !focus.scales || !focus.scales.y) return null;
+
+ const yt = focus.scales.y;
+ const [xL, xU] = getIntegrationBounds(target, shift);
+ if (!Number.isFinite(splitX) || splitX <= xL || splitX >= xU) return null;
+
+ if (!ignoreRef) {
+ return NMR_SPLIT_PREVIEW_EXTENT;
+ }
+
+ const [contextXL, contextXU] = resolveBaselineContextBounds(focus, target, shift);
+ const points = getIntegrationPoints(contextXL, contextXU, focus.data);
+ if (points.length < 2) return null;
+
+ const baselineY = getLinearBaseline(points);
+ const curveY = interpolateY(points, splitX);
+ const baseY = baselineY({ x: splitX });
+ if (!Number.isFinite(curveY) || !Number.isFinite(baseY)) return null;
+
+ return {
+ y1: yt(baseY),
+ y2: yt(curveY),
+ };
+};
+
+const drawIntegrationSplitPreview = (focus, target, splitX, shift, ignoreRef) => {
+ const extent = resolveSplitPreviewExtent(focus, target, splitX, shift, ignoreRef);
+ if (!extent) {
+ clearIntegrationSplitPreview(focus);
+ return;
+ }
+
+ const xt = focus.scales.x;
+ const x = xt(splitX);
+ const preview = focus.root.select('.integration-preview');
+ preview.raise();
+ const line = preview.selectAll(`.${SPLIT_PREVIEW_CLASS}`).data([extent]);
+
+ line.enter()
+ .append('line')
+ .attr('class', SPLIT_PREVIEW_CLASS)
+ .attr('stroke', 'red')
+ .attr('stroke-width', 2)
+ .attr('stroke-dasharray', '4,3')
+ .style('pointer-events', 'none')
+ .merge(line)
+ .attr('x1', x)
+ .attr('x2', x)
+ .attr('y1', (d) => d.y1)
+ .attr('y2', (d) => d.y2);
+};
+
+const drawIntegrationVisualSplitLines = (
+ focus,
+ stack = [],
+ shift = 0,
+ ignoreRef = false,
+ isInteractive = false,
+ onClickLine = null,
+) => {
+ if (!focus || !focus.tags || !focus.tags.visualSplitPath) return;
+
+ const groups = getVisualSplitGroups(stack).filter((group) => group.isMerged);
+ const splitLines = groups.reduce((acc, group) => {
+ const groupTarget = { xL: group.xL, xU: group.xU };
+ getVisualSplitGroupBoundaries(group).forEach((boundary) => {
+ const splitX = boundary - shift;
+ const extent = resolveSplitPreviewExtent(focus, groupTarget, splitX, shift, ignoreRef);
+ if (extent) {
+ acc.push({
+ splitX,
+ key: `${group.groupId || `${group.xL}-${group.xU}`}-${splitX}`,
+ ...extent,
+ });
+ }
+ });
+ return acc;
+ }, []);
+
+ const xt = focus.scales.x;
+ const lines = focus.tags.visualSplitPath
+ .selectAll(`line.${VISUAL_SPLIT_CLASS}`)
+ .data(splitLines, (d) => d.key);
+
+ lines.exit()
+ .attr('class', 'exit')
+ .remove();
+
+ lines.enter()
+ .append('line')
+ .attr('class', VISUAL_SPLIT_CLASS)
+ .attr('stroke', 'red')
+ .attr('stroke-width', 2)
+ .merge(lines)
+ .attr('x1', (d) => xt(d.splitX))
+ .attr('x2', (d) => xt(d.splitX))
+ .attr('y1', (d) => d.y1)
+ .attr('y2', (d) => d.y2)
+ .style('pointer-events', isInteractive ? 'stroke' : 'none')
+ .on('click', isInteractive && onClickLine
+ ? (event, d) => onClickLine(event, d.splitX)
+ : null);
+};
+
+export {
+ NMR_SPLIT_PREVIEW_EXTENT,
+ clearIntegrationSplitPreview,
+ drawIntegrationSplitPreview,
+ drawIntegrationVisualSplitLines,
+ getIntegrationBounds,
+ getIntegrationSplitTarget,
+ getIntegrationSplitTargetFromEvent,
+ getSplitXFromEvent,
+ getVisualSplitLineAtX,
+ getVisualSplitLines,
+ interpolateY,
+ isAlreadyVisuallySplit,
+ isMergedVisualSplitGroup,
+ resolveSplitPreviewExtent,
+};
diff --git a/src/helpers/mount.js b/src/helpers/mount.js
index d91d7a5f..2c4cf9a1 100644
--- a/src/helpers/mount.js
+++ b/src/helpers/mount.js
@@ -34,11 +34,14 @@ const MountTags = (target) => {
const aucPath = target.root.append('g')
.attr('class', 'aucPath-clip')
.attr('clip-path', 'url(#clip)');
+ const visualSplitPath = target.root.append('g')
+ .attr('class', 'integration-visual-splits')
+ .attr('clip-path', 'url(#clip)');
const peckerPath = target.root.append('g')
.attr('class', 'peckerPath-clip')
.attr('clip-path', 'url(#clip)');
return {
- pPath, bpPath, bpTxt, igbPath, igcPath, igtPath, mpybPath, mpyt1Path, mpyt2Path, mpypPath, aucPath, peckerPath, // eslint-disable-line
+ pPath, bpPath, bpTxt, igbPath, igcPath, igtPath, mpybPath, mpyt1Path, mpyt2Path, mpypPath, aucPath, visualSplitPath, peckerPath, // eslint-disable-line
};
};
diff --git a/src/helpers/sweep.js b/src/helpers/sweep.js
new file mode 100644
index 00000000..6a30b8bc
--- /dev/null
+++ b/src/helpers/sweep.js
@@ -0,0 +1,23 @@
+const resolveVisibleYExtent = (focus) => {
+ const { currentExtent, h, scales } = focus;
+ if (currentExtent && currentExtent.yExtent) {
+ return currentExtent.yExtent;
+ }
+
+ const yes = [h, 0].map(scales.y.invert).sort((a, b) => a - b);
+ return { yL: yes[0], yU: yes[1] };
+};
+
+const buildSweepPayloadFromXBounds = (focus, xA, xB) => {
+ const { data, dataPks } = focus;
+ const xes = [xA, xB].map((x) => Number(x)).sort((a, b) => a - b);
+
+ return {
+ xExtent: { xL: xes[0], xU: xes[1] },
+ yExtent: resolveVisibleYExtent(focus),
+ data,
+ dataPks,
+ };
+};
+
+export { buildSweepPayloadFromXBounds, resolveVisibleYExtent };
diff --git a/src/layer_prism.js b/src/layer_prism.js
index a81a4d26..0d13fc94 100644
--- a/src/layer_prism.js
+++ b/src/layer_prism.js
@@ -21,14 +21,21 @@ const styles = () => ({
const LayerPrism = ({
entity, cLabel, xLabel, yLabel, forecast, operations,
descriptions, molSvg, editorOnly, exactMass,
- thresSt, scanSt, uiSt,
+ thresSt, scanSt, uiSt, curveSt, integrationSt,
canChangeDescription, onDescriptionChanged,
}) => {
const {
- topic, feature, hasEdit, integration,
+ topic, feature, hasEdit, integration: initialIntegration,
} = extractParams(entity, thresSt, scanSt);
if (!topic) return null;
+ const curveIdx = (curveSt && Number.isFinite(curveSt.curveIdx)) ? curveSt.curveIdx : 0;
+ const liveIntegrations = (integrationSt && Array.isArray(integrationSt.integrations))
+ ? integrationSt.integrations
+ : null;
+ const liveIntegration = liveIntegrations ? liveIntegrations[curveIdx] : null;
+ const integration = liveIntegration || initialIntegration;
+
const { viewer } = uiSt;
if (viewer === LIST_UI_VIEWER_TYPE.ANALYSIS) {
return (
@@ -104,6 +111,8 @@ const mapStateToProps = (state, props) => ( // eslint-disable-line
scanSt: state.scan,
thresSt: state.threshold.list[state.curve.curveIdx],
uiSt: state.ui,
+ curveSt: state.curve,
+ integrationSt: state.integration.present,
}
);
@@ -126,6 +135,8 @@ LayerPrism.propTypes = {
thresSt: PropTypes.object.isRequired,
scanSt: PropTypes.object.isRequired,
uiSt: PropTypes.object.isRequired,
+ curveSt: PropTypes.object.isRequired,
+ integrationSt: PropTypes.object.isRequired,
canChangeDescription: PropTypes.bool.isRequired,
onDescriptionChanged: PropTypes.func,
};
diff --git a/src/reducers/reducer_integration.js b/src/reducers/reducer_integration.js
index 01352986..869a12d4 100644
--- a/src/reducers/reducer_integration.js
+++ b/src/reducers/reducer_integration.js
@@ -3,7 +3,12 @@ import undoable from 'redux-undo';
import {
UI, INTEGRATION, EDITPEAK, MANAGER,
} from '../constants/action_type';
-import { getArea, getAbsoluteArea } from '../helpers/integration';
+import {
+ generateVisualSplitGroupId,
+ getAbsoluteArea,
+ getArea,
+ splitAreaProportionally,
+} from '../helpers/integration';
import { undoRedoConfig, undoRedoActions } from './undo_redo_config';
const initialState = {
@@ -39,7 +44,7 @@ const addToStack = (state, action) => {
const { stack, refArea, shift } = selectedIntegration;
const { xExtent, data } = newData;
const { xL, xU } = xExtent;
- if (!xL || !xU || (xU - xL) === 0) { return state; }
+ if (!Number.isFinite(xL) || !Number.isFinite(xU) || (xU - xL) === 0) { return state; }
const area = getArea(xL, xU, data);
const defaultRefArea = stack.length === 0 ? area : refArea;
@@ -61,6 +66,20 @@ const addToStack = (state, action) => {
return Object.assign({}, state, { integrations: newArrIntegration, selectedIdx: curveIdx });
};
+const dropOrphanVisualSplitGroupIds = (stack) => {
+ const groupCounts = stack.reduce((acc, item) => {
+ const groupId = item && item.visualSplitGroupId;
+ if (groupId) acc[groupId] = (acc[groupId] || 0) + 1;
+ return acc;
+ }, {});
+ return stack.map((item) => {
+ const groupId = item && item.visualSplitGroupId;
+ if (!groupId || groupCounts[groupId] > 1) return item;
+ const { visualSplitGroupId, ...rest } = item;
+ return rest;
+ });
+};
+
const rmFromStack = (state, action) => {
const { dataToRemove, curveIdx } = action.payload;
const { xL, xU, xExtent } = dataToRemove;
@@ -71,14 +90,325 @@ const rmFromStack = (state, action) => {
const { stack } = selectedIntegration;
let [txL, txU] = [0, 0];
- if (xL && xU) { // rm click integration
+ if (Number.isFinite(xL) && Number.isFinite(xU)) {
[txL, txU] = [xL, xU];
- } else if (xExtent) { // rm click multiplicity
+ } else if (xExtent) {
[txL, txU] = [xExtent.xL, xExtent.xU];
} else {
return state;
}
- const newStack = stack.filter((k) => k.xL !== txL && k.xU !== txU);
+ const filteredStack = stack.filter((k) => k.xL !== txL && k.xU !== txU);
+ const newStack = dropOrphanVisualSplitGroupIds(filteredStack);
+
+ const newIntegration = Object.assign({}, selectedIntegration, { stack: newStack });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+
+ return Object.assign({}, state, { integrations: newArrIntegration, selectedIdx: curveIdx });
+};
+
+const hasEnoughDataResolution = (xL, xU, data) => {
+ const [lower, upper] = [xL, xU].sort((a, b) => a - b);
+ const points = data.filter((pt) => (
+ pt
+ && Number.isFinite(pt.x)
+ && pt.x >= lower
+ && pt.x <= upper
+ ));
+ if (points.length < 2) return false;
+
+ return points.some((pt) => pt.x !== points[0].x);
+};
+
+const computeProportionalSplitAreas = (xL, splitX, xU, data, original) => {
+ const areaParts = splitAreaProportionally(
+ original.area,
+ getArea(xL, splitX, data),
+ getArea(splitX, xU, data),
+ );
+ const absParts = splitAreaProportionally(
+ original.absoluteArea,
+ getAbsoluteArea(xL, splitX, data),
+ getAbsoluteArea(splitX, xU, data),
+ );
+ return {
+ leftArea: areaParts.left,
+ rightArea: areaParts.right,
+ leftAbs: absParts.left,
+ rightAbs: absParts.right,
+ };
+};
+
+const buildSplitStackItem = (xL, xU, shift, area, absoluteArea) => {
+ const [lower, upper] = [xL, xU].sort((a, b) => a - b);
+ return {
+ xL: lower + shift,
+ xU: upper + shift,
+ area,
+ absoluteArea,
+ };
+};
+
+const getVisualSplitTolerance = (xL, xU) => Math.max(Math.abs(xU - xL) * 1e-6, Number.EPSILON);
+
+const findTargetIntegrationIndex = (stack, target) => stack.findIndex((item) => (
+ item.xL === target.xL && item.xU === target.xU
+));
+
+const buildVisualSplitItem = (xL, xU, shift, area, absoluteArea, groupId) => {
+ const [lower, upper] = [xL, xU].sort((a, b) => a - b);
+ const item = {
+ xL: lower + shift,
+ xU: upper + shift,
+ area,
+ absoluteArea,
+ };
+ if (groupId) item.visualSplitGroupId = groupId;
+ return item;
+};
+
+const isVisuallySplit = (stack, item) => {
+ if (!item || !item.visualSplitGroupId) return false;
+ return stack.some((other) => (
+ other !== item && other.visualSplitGroupId === item.visualSplitGroupId
+ ));
+};
+
+const buildRawSplitPart = (xL, xU, shift, data) => buildSplitStackItem(
+ xL,
+ xU,
+ shift,
+ getArea(xL, xU, data),
+ getAbsoluteArea(xL, xU, data),
+);
+
+const findVisualSplitNeighborhood = (stack, original, shift, xL, xU) => {
+ const groupId = original && original.visualSplitGroupId;
+ if (!groupId) return { hasLeft: false, hasRight: false };
+
+ const tolerance = getVisualSplitTolerance(xL, xU);
+ const isGroupSibling = (item) => (
+ item !== original && item.visualSplitGroupId === groupId
+ );
+
+ return {
+ hasLeft: stack.some((item) => (
+ isGroupSibling(item) && Math.abs((item.xU - shift) - xL) <= tolerance
+ )),
+ hasRight: stack.some((item) => (
+ isGroupSibling(item) && Math.abs((item.xL - shift) - xU) <= tolerance
+ )),
+ };
+};
+
+const buildSplitParts = (original, xL, splitX, xU, shift, data, stack) => {
+ if (!original.visualSplitGroupId) {
+ return [
+ buildRawSplitPart(xL, splitX, shift, data),
+ buildRawSplitPart(splitX, xU, shift, data),
+ ];
+ }
+
+ const { hasLeft, hasRight } = findVisualSplitNeighborhood(stack, original, shift, xL, xU);
+ if (!hasLeft && !hasRight) {
+ return [
+ buildRawSplitPart(xL, splitX, shift, data),
+ buildRawSplitPart(splitX, xU, shift, data),
+ ];
+ }
+
+ const groupId = original.visualSplitGroupId;
+ const {
+ leftArea, rightArea, leftAbs, rightAbs,
+ } = computeProportionalSplitAreas(xL, splitX, xU, data, original);
+
+ const leftStaysInGroup = hasLeft;
+ const rightStaysInGroup = hasRight;
+
+ const leftPart = leftStaysInGroup
+ ? buildVisualSplitItem(xL, splitX, shift, leftArea, leftAbs, groupId)
+ : buildSplitStackItem(xL, splitX, shift, leftArea, leftAbs);
+ const rightPart = rightStaysInGroup
+ ? buildVisualSplitItem(splitX, xU, shift, rightArea, rightAbs, groupId)
+ : buildSplitStackItem(splitX, xU, shift, rightArea, rightAbs);
+
+ return [leftPart, rightPart];
+};
+
+const splitStack = (state, action) => {
+ const {
+ curveIdx, target, splitX, data,
+ } = action.payload;
+
+ if (!Number.isFinite(curveIdx) || !target || !Array.isArray(data)) {
+ return state;
+ }
+
+ const { integrations } = state;
+ const selectedIntegration = integrations[curveIdx];
+ if (!selectedIntegration || selectedIntegration === false) {
+ return state;
+ }
+
+ const { stack, shift } = selectedIntegration;
+ const targetIndex = findTargetIntegrationIndex(stack, target);
+ if (targetIndex < 0 || !Number.isFinite(splitX)) {
+ return state;
+ }
+
+ const original = stack[targetIndex];
+ const [xL, xU] = [original.xL - shift, original.xU - shift].sort((a, b) => a - b);
+ if (!Number.isFinite(xL) || !Number.isFinite(xU) || splitX <= xL || splitX >= xU) {
+ return state;
+ }
+
+ if (!hasEnoughDataResolution(xL, splitX, data) || !hasEnoughDataResolution(splitX, xU, data)) {
+ return state;
+ }
+
+ const [leftIntegration, rightIntegration] = buildSplitParts(
+ original, xL, splitX, xU, shift, data, stack,
+ );
+
+ const newStack = dropOrphanVisualSplitGroupIds([
+ ...stack.slice(0, targetIndex),
+ leftIntegration,
+ rightIntegration,
+ ...stack.slice(targetIndex + 1),
+ ]);
+
+ const newIntegration = Object.assign({}, selectedIntegration, { stack: newStack });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+
+ return Object.assign({}, state, { integrations: newArrIntegration, selectedIdx: curveIdx });
+};
+
+const addVisualSplitLine = (state, action) => {
+ const {
+ curveIdx, target, splitX, data,
+ } = action.payload;
+
+ if (!Number.isFinite(curveIdx) || !target || !Number.isFinite(splitX) || !Array.isArray(data)) {
+ return state;
+ }
+
+ const { integrations } = state;
+ const selectedIntegration = integrations[curveIdx];
+ if (!selectedIntegration || selectedIntegration === false) {
+ return state;
+ }
+
+ const { stack, shift } = selectedIntegration;
+ const targetIndex = findTargetIntegrationIndex(stack, target);
+ if (targetIndex < 0) return state;
+
+ const original = stack[targetIndex];
+
+ if (original.visualSplitGroupId || isVisuallySplit(stack, original)) {
+ return state;
+ }
+
+ const [xL, xU] = [original.xL - shift, original.xU - shift].sort((a, b) => a - b);
+ const tolerance = getVisualSplitTolerance(xL, xU);
+ if (splitX <= xL + tolerance || splitX >= xU - tolerance) {
+ return state;
+ }
+ if (!hasEnoughDataResolution(xL, splitX, data) || !hasEnoughDataResolution(splitX, xU, data)) {
+ return state;
+ }
+
+ const groupId = generateVisualSplitGroupId();
+ const {
+ leftArea, rightArea, leftAbs, rightAbs,
+ } = computeProportionalSplitAreas(xL, splitX, xU, data, original);
+ const leftItem = buildVisualSplitItem(xL, splitX, shift, leftArea, leftAbs, groupId);
+ const rightItem = buildVisualSplitItem(splitX, xU, shift, rightArea, rightAbs, groupId);
+
+ if (leftItem.xL >= leftItem.xU
+ || rightItem.xL >= rightItem.xU
+ || leftItem.xU !== rightItem.xL) {
+ return state;
+ }
+
+ const newStack = [
+ ...stack.slice(0, targetIndex),
+ leftItem,
+ rightItem,
+ ...stack.slice(targetIndex + 1),
+ ];
+
+ const newIntegration = Object.assign({}, selectedIntegration, { stack: newStack });
+ const newArrIntegration = [...integrations];
+ newArrIntegration[curveIdx] = newIntegration;
+
+ return Object.assign({}, state, { integrations: newArrIntegration, selectedIdx: curveIdx });
+};
+
+const removeVisualSplitLine = (state, action) => {
+ const {
+ curveIdx, splitX, data,
+ } = action.payload;
+
+ if (!Number.isFinite(curveIdx) || !Number.isFinite(splitX) || !Array.isArray(data)) {
+ return state;
+ }
+
+ const { integrations } = state;
+ const selectedIntegration = integrations[curveIdx];
+ if (!selectedIntegration || selectedIntegration === false) {
+ return state;
+ }
+
+ const { stack, shift } = selectedIntegration;
+ if (!Array.isArray(stack) || stack.length < 2) return state;
+
+ const tolerance = getVisualSplitTolerance(
+ Math.min(...stack.map((s) => s.xL - shift)),
+ Math.max(...stack.map((s) => s.xU - shift)),
+ );
+
+ let mergeStartIdx = -1;
+ for (let i = 0; i < stack.length - 1; i += 1) {
+ const left = stack[i];
+ const right = stack[i + 1];
+ const gapTolerance = Math.max(tolerance, Math.abs(left.xU - right.xL));
+ if (
+ left.visualSplitGroupId
+ && left.visualSplitGroupId === right.visualSplitGroupId
+ && Math.abs((left.xU - shift) - splitX) <= gapTolerance
+ && Math.abs((right.xL - shift) - splitX) <= gapTolerance
+ ) {
+ mergeStartIdx = i;
+ break;
+ }
+ }
+ if (mergeStartIdx < 0) return state;
+
+ const leftItem = stack[mergeStartIdx];
+ const rightItem = stack[mergeStartIdx + 1];
+ const groupId = leftItem.visualSplitGroupId;
+ const mergedXL = Math.min(leftItem.xL, rightItem.xL) - shift;
+ const mergedXU = Math.max(leftItem.xU, rightItem.xU) - shift;
+
+ const remainingInGroup = stack.filter((item, idx) => (
+ idx !== mergeStartIdx && idx !== mergeStartIdx + 1 && item.visualSplitGroupId === groupId
+ ));
+ const keepGroupId = remainingInGroup.length > 0;
+ const mergedItem = buildVisualSplitItem(
+ mergedXL,
+ mergedXU,
+ shift,
+ (leftItem.area || 0) + (rightItem.area || 0),
+ (leftItem.absoluteArea || 0) + (rightItem.absoluteArea || 0),
+ keepGroupId ? groupId : null,
+ );
+
+ const newStack = [
+ ...stack.slice(0, mergeStartIdx),
+ mergedItem,
+ ...stack.slice(mergeStartIdx + 2),
+ ];
const newIntegration = Object.assign({}, selectedIntegration, { stack: newStack });
const newArrIntegration = [...integrations];
@@ -159,6 +489,12 @@ const integrationReducer = (state = initialState, action) => {
return addToStack(state, action);
case INTEGRATION.RM_ONE:
return rmFromStack(state, action);
+ case INTEGRATION.SPLIT:
+ return splitStack(state, action);
+ case INTEGRATION.ADD_VISUAL_SPLIT:
+ return addVisualSplitLine(state, action);
+ case INTEGRATION.RM_VISUAL_SPLIT:
+ return removeVisualSplitLine(state, action);
case INTEGRATION.SET_REF:
return setRef(state, action);
case INTEGRATION.SET_FKR:
@@ -183,4 +519,6 @@ const undoableIntegrationReducer = undoable(
undoRedoConfig,
);
+export { integrationReducer };
+
export default undoableIntegrationReducer;
diff --git a/src/reducers/undo_redo_config.js b/src/reducers/undo_redo_config.js
index 2c52e048..b24db61e 100644
--- a/src/reducers/undo_redo_config.js
+++ b/src/reducers/undo_redo_config.js
@@ -11,7 +11,8 @@ const undoRedoActions = [
MANAGER.RESET_INIT_MS, MANAGER.RESET_INIT_COMMON_WITH_INTERGATION,
UI.SWEEP.SELECT_INTEGRATION,
UI.SWEEP.SELECT_MULTIPLICITY_RDC,
- INTEGRATION.RM_ONE, INTEGRATION.SET_REF, INTEGRATION.SET_FKR,
+ INTEGRATION.RM_ONE, INTEGRATION.SET_REF, INTEGRATION.SET_FKR, INTEGRATION.SPLIT,
+ INTEGRATION.ADD_VISUAL_SPLIT, INTEGRATION.RM_VISUAL_SPLIT,
INTEGRATION.RESET_ALL, INTEGRATION.CLEAR_ALL,
MULTIPLICITY.PEAK_RM_BY_PANEL_RDC, MULTIPLICITY.PEAK_RM_BY_UI_RDC,
MULTIPLICITY.PEAK_ADD_BY_UI_RDC, MULTIPLICITY.RESET_ONE_RDC,
@@ -23,7 +24,7 @@ const undoRedoActions = [
const undoRedoConfig = {
debug: false,
limit: 10,
- ignoreInitialState: true,
+ ignoreInitialState: false,
filter: includeAction(undoRedoActions),
clearHistoryType: [
EDITPEAK.SHIFT, EDITPEAK.CLEAR_ALL,