From 3d2e328fa2cbff076567fe18fc78ecfe69f1c29f Mon Sep 17 00:00:00 2001 From: Nicolass67 Date: Wed, 29 Apr 2026 13:49:50 +0200 Subject: [PATCH 1/7] threshold + NMR/HPLC Fix --- dist/actions/curve.js | 7 +- dist/actions/integration.js | 19 +- dist/actions/threshold.js | 4 +- dist/actions/ui.js | 50 +- dist/app.js | 29 +- dist/components/cmd_bar/01_viewer.js | 26 +- dist/components/cmd_bar/03_peak.js | 41 +- dist/components/cmd_bar/04_integration.js | 133 +---- dist/components/cmd_bar/common.js | 7 +- dist/components/cmd_bar/index.js | 94 +--- dist/components/cmd_bar/r01_layout.js | 6 - dist/components/cmd_bar/r02_scan.js | 26 +- dist/components/cmd_bar/r03_threshold.js | 36 +- dist/components/cmd_bar/r04_submit.js | 67 +-- dist/components/cmd_bar/r05_submit_btn.js | 66 +-- dist/components/cmd_bar/r06_predict_btn.js | 8 +- dist/components/cmd_bar/r07_wavelength_btn.js | 19 +- dist/components/cmd_bar/r09_detector.js | 4 +- dist/components/cmd_bar/tri_btn.js | 5 +- dist/components/common/draw.js | 13 +- dist/components/d3_line/index.js | 85 +-- dist/components/d3_line/line_focus.js | 203 ++++--- dist/components/d3_multi/index.js | 328 +++++------ dist/components/d3_multi/multi_focus.js | 248 ++++----- dist/components/d3_rect/index.js | 6 - dist/components/d3_rect/rect_focus.js | 22 +- dist/components/multi_jcamps_viewer.js | 24 +- dist/components/panel/compare.js | 146 +++-- .../components/panel/cyclic_voltamery_data.js | 24 +- dist/components/panel/graph_selection.js | 62 +-- dist/components/panel/index.js | 50 +- dist/components/panel/info.js | 121 ++-- dist/constants/action_type.js | 25 +- dist/constants/list_layout.js | 3 +- dist/constants/list_ui.js | 7 +- dist/fn.js | 5 +- dist/helpers/brush.js | 93 +--- dist/helpers/calc.js | 6 +- dist/helpers/cfg.js | 9 +- dist/helpers/chem.js | 520 +++--------------- dist/helpers/compass.js | 198 +------ dist/helpers/extractParams.js | 151 ++--- dist/helpers/extractPeaksEdit.js | 38 +- dist/helpers/format.js | 193 +------ dist/helpers/init.js | 30 +- dist/helpers/integration.js | 147 +---- dist/helpers/mount.js | 9 +- dist/index.js | 310 +---------- dist/layer_content.js | 20 +- dist/layer_init.js | 138 +---- dist/layer_prism.js | 36 +- dist/reducers/index.js | 4 +- dist/reducers/reducer_curve.js | 90 ++- dist/reducers/reducer_integration.js | 272 +-------- dist/reducers/reducer_layout.js | 2 +- dist/reducers/reducer_submit.js | 3 +- dist/reducers/reducer_threshold.js | 44 +- dist/reducers/reducer_ui.js | 162 +----- dist/reducers/undo_redo_config.js | 4 +- dist/sagas/saga_ui.js | 235 +++----- dist/setupTests.js | 10 +- src/actions/threshold.js | 4 +- src/components/cmd_bar/r03_threshold.js | 7 +- src/components/common/draw.js | 2 +- src/components/d3_line/line_focus.js | 46 +- src/components/d3_multi/index.js | 12 +- src/components/d3_multi/multi_focus.js | 74 ++- src/reducers/reducer_threshold.js | 37 +- yarn.lock | 17 - 69 files changed, 1243 insertions(+), 3699 deletions(-) diff --git a/dist/actions/curve.js b/dist/actions/curve.js index 07877ece..85bd0062 100644 --- a/dist/actions/curve.js +++ b/dist/actions/curve.js @@ -10,12 +10,9 @@ const selectCurve = payload => ({ payload }); exports.selectCurve = selectCurve; -const setAllCurves = (payload, meta) => ({ +const setAllCurves = payload => ({ type: _action_type.CURVE.SET_ALL_CURVES, - payload, - ...(meta && typeof meta === 'object' ? { - meta - } : {}) + payload }); exports.setAllCurves = setAllCurves; const toggleShowAllCurves = payload => ({ diff --git a/dist/actions/integration.js b/dist/actions/integration.js index be96499c..f81706c4 100644 --- a/dist/actions/integration.js +++ b/dist/actions/integration.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.sweepIntegration = exports.splitIntegration = exports.setIntegrationFkr = exports.removeVisualSplitLine = exports.clearIntegrationAll = exports.addVisualSplitLine = void 0; +exports.sweepIntegration = exports.setIntegrationFkr = exports.clearIntegrationAll = void 0; var _action_type = require("../constants/action_type"); const sweepIntegration = payload => ({ type: _action_type.INTEGRATION.SWEEP, @@ -19,21 +19,6 @@ const clearIntegrationAll = payload => ({ type: _action_type.INTEGRATION.CLEAR_ALL, payload }); -exports.clearIntegrationAll = clearIntegrationAll; -const splitIntegration = payload => ({ - type: _action_type.INTEGRATION.SPLIT, - payload -}); -exports.splitIntegration = splitIntegration; -const addVisualSplitLine = payload => ({ - type: _action_type.INTEGRATION.ADD_VISUAL_SPLIT, - payload -}); -exports.addVisualSplitLine = addVisualSplitLine; -const removeVisualSplitLine = payload => ({ - type: _action_type.INTEGRATION.RM_VISUAL_SPLIT, - payload -}); // eslint-disable-line -exports.removeVisualSplitLine = removeVisualSplitLine; \ No newline at end of file +exports.clearIntegrationAll = clearIntegrationAll; \ No newline at end of file diff --git a/dist/actions/threshold.js b/dist/actions/threshold.js index 3feeeee2..5359753b 100644 --- a/dist/actions/threshold.js +++ b/dist/actions/threshold.js @@ -10,9 +10,9 @@ const updateThresholdValue = payload => ({ payload }); exports.updateThresholdValue = updateThresholdValue; -const resetThresholdValue = () => ({ +const resetThresholdValue = (payload = false) => ({ type: _action_type.THRESHOLD.RESET_VALUE, - payload: false + payload }); exports.resetThresholdValue = resetThresholdValue; const toggleThresholdIsEdit = payload => ({ diff --git a/dist/actions/ui.js b/dist/actions/ui.js index 590f7b16..aaa15a98 100644 --- a/dist/actions/ui.js +++ b/dist/actions/ui.js @@ -3,37 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.setUiViewerType = exports.setUiSweepType = exports.selectUiSweep = exports.scrollUiWheel = exports.displaySubViewerAt = exports.clickUiTarget = void 0; +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) => ({ +const setUiViewerType = payload => ({ + type: _action_type.UI.VIEWER.SET_TYPE, + payload +}); +exports.setUiViewerType = setUiViewerType; +const setUiSweepType = (payload, jcampIdx = 0) => ({ type: _action_type.UI.SWEEP.SET_TYPE, - payload: _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD, + payload, 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, @@ -45,21 +26,12 @@ const scrollUiWheel = payload => ({ payload }); exports.scrollUiWheel = scrollUiWheel; -const clickUiTarget = (payload, onPeak, voltammetryPeakIdx = 0, jcampIdx = 0, onPecker = false, sourceHint = null) => ({ +const clickUiTarget = (payload, onPeak, voltammetryPeakIdx = 0, jcampIdx = 0, onPecker = false) => ({ type: _action_type.UI.CLICK_TARGET, payload, onPeak, voltammetryPeakIdx, jcampIdx, - onPecker, - sourceHint -}); -exports.clickUiTarget = clickUiTarget; -const displaySubViewerAt = payload => ({ - type: _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT, - payload: payload == null ? { - x: null, - y: null - } : payload + onPecker }); -exports.displaySubViewerAt = displaySubViewerAt; \ No newline at end of file +exports.clickUiTarget = clickUiTarget; \ No newline at end of file diff --git a/dist/app.js b/dist/app.js index d66e1117..a6bd495c 100644 --- a/dist/app.js +++ b/dist/app.js @@ -10,7 +10,7 @@ Object.defineProperty(exports, "FN", { return _fn.default; } }); -exports.store = exports.SpectraEditor = void 0; +exports.SpectraEditor = void 0; var _react = _interopRequireDefault(require("react")); var _reactRedux = require("react-redux"); var _redux = require("redux"); @@ -33,13 +33,8 @@ var _jsxRuntime = require("react/jsx-runtime"); const sagaMiddleware = (0, _reduxSaga.default)(); const middlewares = [sagaMiddleware]; // logger -const store = exports.store = (0, _redux.compose)((0, _redux.applyMiddleware)(...middlewares))(_redux.createStore)(_index.default); -try { - sagaMiddleware.run(_index2.default); -} catch (error) { - // Keep startup failure visible without crashing silently. - console.error('[SpectraEditor] Failed to start sagas', error); // eslint-disable-line no-console -} +const store = (0, _redux.compose)((0, _redux.applyMiddleware)(...middlewares))(_redux.createStore)(_index.default); +sagaMiddleware.run(_index2.default); // - - - helper - - - const ensureQuillDelta = descs => { @@ -50,10 +45,6 @@ const ensureQuillDelta = descs => { }; // - - - React - - - -// LC/MS: when `onLcmsPageRequest` is set, the host (e.g. ELN) must reload `multiEntities` -// with MS data for the requested RT/polarity. Triggers include `user_click`, `initial`, -// and `tic_polarity` (TIC polarity dropdown). The standalone demo in `src/index.js` -// implements a local mock via `buildLcmsStandaloneMultiEntities`. const SpectraEditor = ({ entity, others, @@ -71,8 +62,7 @@ const SpectraEditor = ({ multiEntities, multiMolSvgs, entityFileNames, - userManualLink, - onLcmsPageRequest + userManualLink }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactRedux.Provider, { store: store, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.StyledEngineProvider, { @@ -94,8 +84,7 @@ const SpectraEditor = ({ editorOnly: editorOnly, exactMass: exactMass, canChangeDescription: canChangeDescription, - onDescriptionChanged: onDescriptionChanged, - onLcmsPageRequest: onLcmsPageRequest + onDescriptionChanged: onDescriptionChanged }) }) }); @@ -116,7 +105,6 @@ SpectraEditor.propTypes = { editorOnly: _propTypes.default.bool, canChangeDescription: _propTypes.default.bool, onDescriptionChanged: _propTypes.default.func, - onLcmsPageRequest: _propTypes.default.func, userManualLink: _propTypes.default.object, exactMass: _propTypes.default.string }; @@ -125,8 +113,8 @@ SpectraEditor.defaultProps = { others: [], addOthersCb: false }, - multiEntities: [], - entityFileNames: [], + multiEntities: false, + entityFileNames: false, cLabel: '', xLabel: '', yLabel: '', @@ -138,6 +126,5 @@ SpectraEditor.defaultProps = { multiMolSvgs: [], editorOnly: false, canChangeDescription: false, - userManualLink: {}, - onLcmsPageRequest: null + 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 index 87093240..637df919 100644 --- a/dist/components/cmd_bar/01_viewer.js +++ b/dist/components/cmd_bar/01_viewer.js @@ -40,13 +40,11 @@ const Viewer = ({ className: "txt-sv-tp", children: "Spectrum Viewer" }), - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - 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 - }) + 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, { @@ -54,14 +52,12 @@ const Viewer = ({ className: "txt-sv-tp", children: "Analysis Viewer" }), - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - 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 - }) + 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 }) }) })] diff --git a/dist/components/cmd_bar/03_peak.js b/dist/components/cmd_bar/03_peak.js index 4aeadb6c..ea2777d2 100644 --- a/dist/components/cmd_bar/03_peak.js +++ b/dist/components/cmd_bar/03_peak.js @@ -20,8 +20,6 @@ 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 _hplc_ms = require("../../actions/hplc_ms"); -var _list_layout = require("../../constants/list_layout"); 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, @@ -38,37 +36,32 @@ const Peak = ({ isFocusSetRefSt, disableSetRefSt, isHandleMaxAndMinPeaksSt, - cyclicVoltaState, + cyclicVotaSt, curveSt, clearAllPeaksAct, feature, editPeakSt, thresSt, shiftSt, - layoutSt, - clearAllPeaksHplcMsAct + layoutSt }) => { let onSweepPeakAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD); - let onSweepPeakDelete = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.PEAK_DELETE); + 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 = () => { - if (layoutSt === _list_layout.LIST_LAYOUT.LC_MS) { - clearAllPeaksHplcMsAct(); - } else { - const dataPeaks = (0, _extractPeaksEdit.extractAutoPeaks)(feature, thresSt, shiftSt, layoutSt); - clearAllPeaksAct({ - curveIdx, - dataPeaks - }); - } + const dataPeaks = (0, _extractPeaksEdit.extractAutoPeaks)(feature, thresSt, shiftSt, layoutSt); + clearAllPeaksAct({ + curveIdx, + dataPeaks + }); }; if (isHandleMaxAndMinPeaksSt) { const { spectraList - } = cyclicVoltaState; + } = cyclicVotaSt; const spectra = spectraList[curveIdx]; if (spectra) { const { @@ -76,10 +69,10 @@ const Peak = ({ } = 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); + 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); + 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); } @@ -112,7 +105,7 @@ const Peak = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, { className: (0, _classnames.default)((0, _common.focusStyle)(isFocusRmPeakSt, classes), 'btn-sv-bar-rmpeak'), disabled: disableRmPeakSt, - onClick: onSweepPeakDelete, + onClick: onSweepPeakDELETE, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmpeak'), children: "P-" @@ -160,7 +153,7 @@ const mapStateToProps = (state, props) => ( 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), - cyclicVoltaState: state.cyclicvolta, + cyclicVotaSt: state.cyclicvolta, curveSt: state.curve, editPeakSt: state.editPeak.present, thresSt: state.threshold.list[state.curve.curveIdx], @@ -169,8 +162,7 @@ const mapStateToProps = (state, props) => ( }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ setUiSweepTypeAct: _ui.setUiSweepType, - clearAllPeaksAct: _edit_peak.clearAllPeaks, - clearAllPeaksHplcMsAct: _hplc_ms.clearAllPeaksHplcMs + clearAllPeaksAct: _edit_peak.clearAllPeaks }, dispatch); Peak.propTypes = { classes: _propTypes.default.object.isRequired, @@ -182,14 +174,13 @@ Peak.propTypes = { disableSetRefSt: _propTypes.default.bool.isRequired, setUiSweepTypeAct: _propTypes.default.func.isRequired, isHandleMaxAndMinPeaksSt: _propTypes.default.bool.isRequired, - cyclicVoltaState: _propTypes.default.object.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, - clearAllPeaksHplcMsAct: _propTypes.default.func.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 index 7a61beb7..2152a917 100644 --- a/dist/components/cmd_bar/04_integration.js +++ b/dist/components/cmd_bar/04_integration.js @@ -16,34 +16,22 @@ var _TextField = _interopRequireDefault(require("@mui/material/TextField")); var _react2 = _interopRequireDefault(require("@mdi/react")); var _js = require("@mdi/js"); var _integration = require("../../actions/integration"); -var _hplc_ms = require("../../actions/hplc_ms"); 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 _list_layout = require("../../constants/list_layout"); 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' - } - } + txtIcon: {} }, _common.commonStyle); const iconSize = '16px'; const setFactor = (classes, isDisable, integrationSt, setIntegrationFkrAct, curveIdx) => { @@ -94,58 +82,25 @@ const iconColor = criteria => criteria ? '#fff' : '#000'; const Integration = ({ classes, ignoreRef, - showIntegSplitToolsSt, isDisableSt, isFocusAddIntgSt, isFocusRmIntgSt, isFocusSetRefSt, - isFocusSplitIntgSt, - isFocusVisualSplitIntgSt, setUiSweepTypeAct, setIntegrationFkrAct, clearIntegrationAllAct, curveSt, - integrationSt, - clearIntegrationAllHplcMsAct, - layoutSt + integrationSt }) => { + const onSweepIntegtAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD); + const onSweepIntegtRm = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_RM); + const onSweepIntegtSR = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF); 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 onClearAll = () => { - if (layoutSt === _list_layout.LIST_LAYOUT.LC_MS) { - clearIntegrationAllHplcMsAct(); - } else { - clearIntegrationAllAct({ - curveIdx - }); - } - }; - const onSweepIntegtSplit = () => { - if (isFocusSplitIntgSt) { - onCancelTool(); - return; - } - setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, curveIdx); - }; - const onSweepIntegtVisualSplit = () => { - if (isFocusVisualSplitIntgSt) { - onCancelTool(); - return; - } - setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, curveIdx); - }; + const onClearAll = () => clearIntegrationAllAct({ + curveIdx + }); return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { className: classes.group, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { @@ -155,15 +110,15 @@ const 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'), + className: (0, _classnames.default)((0, _common.focusStyle)(isFocusAddIntgSt, classes), 'btn-add-inter'), disabled: isDisableSt, onClick: onSweepIntegtAdd, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, { - path: isFocusAddIntgSt ? _js.mdiClose : _js.mdiMathIntegral, + path: _js.mdiMathIntegral, size: iconSize, - color: isFocusAddIntgSt ? '#d32f2f' : iconColor(isDisableSt), + color: iconColor(isFocusAddIntgSt || isDisableSt), className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-addint') - }), isFocusAddIntgSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-addint'), children: "+" })] @@ -190,7 +145,7 @@ const Integration = ({ })] }) }) - }), ignoreRef ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "txt-sv-tp", children: "Set Integration Reference" @@ -208,51 +163,7 @@ const Integration = ({ }) }) }) - }), showIntegSplitToolsSt ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { - children: [/*#__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: "/" - })] - }) - }) - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { - title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: "txt-sv-tp", - children: "Visual Split Integration" - }), - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_common.MuButton, { - className: (0, _classnames.default)(isFocusVisualSplitIntgSt ? classes.cancelBtn : (0, _common.focusStyle)(false, classes), 'btn-visual-split-inter'), - disabled: isDisableSt, - onClick: onSweepIntegtVisualSplit, - children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, { - path: isFocusVisualSplitIntgSt ? _js.mdiClose : _js.mdiMathIntegral, - size: iconSize, - color: isFocusVisualSplitIntgSt ? '#d32f2f' : iconColor(isDisableSt), - className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-visualsplitint') - }), isFocusVisualSplitIntgSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-visualsplitint'), - children: "|" - })] - }) - }) - })] - }) : null, !ignoreRef ? setFactor(classes, isDisableSt, integrationSt, setIntegrationFkrAct, curveIdx) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { + }), !ignoreRef ? setFactor(classes, isDisableSt, integrationSt, setIntegrationFkrAct, curveIdx) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { content: { tp: 'Clear All Integration' }, @@ -276,19 +187,14 @@ const mapStateToProps = (state, props) => ( 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, - isFocusVisualSplitIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, ignoreRef: _format.default.isHplcUvVisLayout(state.layout), - showIntegSplitToolsSt: _cfg.default.showIntegSplitTools(state.layout), curveSt: state.curve, - integrationSt: state.integration.present, - layoutSt: state.layout + integrationSt: state.integration.present }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ setUiSweepTypeAct: _ui.setUiSweepType, setIntegrationFkrAct: _integration.setIntegrationFkr, - clearIntegrationAllAct: _integration.clearIntegrationAll, - clearIntegrationAllHplcMsAct: _hplc_ms.clearIntegrationAllHplcMs + clearIntegrationAllAct: _integration.clearIntegrationAll }, dispatch); Integration.propTypes = { classes: _propTypes.default.object.isRequired, @@ -296,16 +202,11 @@ Integration.propTypes = { isFocusAddIntgSt: _propTypes.default.bool.isRequired, isFocusRmIntgSt: _propTypes.default.bool.isRequired, isFocusSetRefSt: _propTypes.default.bool.isRequired, - isFocusSplitIntgSt: _propTypes.default.bool.isRequired, - isFocusVisualSplitIntgSt: _propTypes.default.bool.isRequired, ignoreRef: _propTypes.default.bool.isRequired, - showIntegSplitToolsSt: _propTypes.default.bool.isRequired, setUiSweepTypeAct: _propTypes.default.func.isRequired, setIntegrationFkrAct: _propTypes.default.func.isRequired, clearIntegrationAllAct: _propTypes.default.func.isRequired, - clearIntegrationAllHplcMsAct: _propTypes.default.func.isRequired, curveSt: _propTypes.default.object.isRequired, - integrationSt: _propTypes.default.object.isRequired, - layoutSt: _propTypes.default.string.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/common.js b/dist/components/cmd_bar/common.js index b851c116..f99639f0 100644 --- a/dist/components/cmd_bar/common.js +++ b/dist/components/cmd_bar/common.js @@ -26,19 +26,18 @@ const useStyles = (0, _styles.makeStyles)(theme => ({ color: 'black' } })); -const MuButton = exports.MuButton = /*#__PURE__*/_react.default.forwardRef((props, ref) => { +const MuButton = props => { const classes = useStyles(); const { className, ...other } = props; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, { - ref: ref, className: (0, _classnames.default)(classes.muiBtn, className), ...other }); -}); -MuButton.displayName = 'MuButton'; +}; +exports.MuButton = MuButton; const commonStyle = exports.commonStyle = { card: { margin: '0 0 5px 52px', diff --git a/dist/components/cmd_bar/index.js b/dist/components/cmd_bar/index.js index e82cf604..5b000116 100644 --- a/dist/components/cmd_bar/index.js +++ b/dist/components/cmd_bar/index.js @@ -30,39 +30,7 @@ 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({}, { - cardFlex: { - display: 'flex', - flexWrap: 'wrap', - alignItems: 'center', - justifyContent: 'space-between', - columnGap: 8, - rowGap: 4 - }, - lcMsToolbarLeft: { - display: 'flex', - flexWrap: 'wrap', - alignItems: 'center', - columnGap: 4, - rowGap: 4, - flex: '1 1 auto', - minWidth: 0 - }, - lcMsToolbarRight: { - display: 'flex', - alignItems: 'center', - justifyContent: 'flex-end', - flex: '0 1 auto', - minWidth: 0 - }, - lcMsToolbarRightCluster: { - display: 'flex', - flexWrap: 'wrap', - alignItems: 'center', - columnGap: 8, - rowGap: 4 - } -}, _common.commonStyle); +const styles = () => Object.assign({}, {}, _common.commonStyle); const CmdBar = ({ classes, feature, @@ -72,16 +40,19 @@ const CmdBar = ({ editorOnly, jcampIdx, hideThreshold, - hideMainEditTools, - layoutSt, - prependLcMsToolbar + layoutSt }) => { const isCvLayout = _format.default.isCyclicVoltaLayout(layoutSt); - const rightCluster = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { - children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_r01_layout.default, { - feature: feature, - hasEdit: hasEdit - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r04_submit.default, { + 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, @@ -91,42 +62,18 @@ const CmdBar = ({ }), 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, {})] }); - if (prependLcMsToolbar) { - return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { - className: `${classes.card} ${classes.cardFlex}`, - children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: classes.lcMsToolbarLeft, - children: prependLcMsToolbar - }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: classes.lcMsToolbarRight, - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: classes.lcMsToolbarRightCluster, - children: rightCluster - }) - })] - }); - } - return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { - className: classes.card, - children: [hideMainEditTools ? null : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { - 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, {})] - }), rightCluster] - }); }; 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, @@ -136,11 +83,6 @@ CmdBar.propTypes = { editorOnly: _propTypes.default.bool.isRequired, layoutSt: _propTypes.default.string.isRequired, jcampIdx: _propTypes.default.any, - hideThreshold: _propTypes.default.bool, - hideMainEditTools: _propTypes.default.bool, - prependLcMsToolbar: _propTypes.default.node -}; -CmdBar.defaultProps = { - prependLcMsToolbar: null + hideThreshold: _propTypes.default.bool }; -var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, null), (0, _withStyles.default)(styles))(CmdBar); \ No newline at end of file +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 index 148f45e1..9c52d9b7 100644 --- a/dist/components/cmd_bar/r01_layout.js +++ b/dist/components/cmd_bar/r01_layout.js @@ -226,12 +226,6 @@ const layoutSelect = (classes, layoutSt, updateLayoutAct) => { className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'), children: "MS" }) - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { - value: _list_layout.LIST_LAYOUT.LC_MS, - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'), - children: "LC/MS" - }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { value: _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { diff --git a/dist/components/cmd_bar/r02_scan.js b/dist/components/cmd_bar/r02_scan.js index e684e9c0..89c5b7a3 100644 --- a/dist/components/cmd_bar/r02_scan.js +++ b/dist/components/cmd_bar/r02_scan.js @@ -37,13 +37,11 @@ const btnRestore = (classes, hasEdit, isEdit, toggleEditAct) => /*#__PURE__*/(0, className: "txt-sv-tp", children: restoreTp(hasEdit, isEdit) }), - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, { - className: (0, _classnames.default)('btn-sv-bar-scanrst'), - disabled: !hasEdit, - onClick: toggleEditAct, - children: restoreIcon(classes, 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, { @@ -51,14 +49,12 @@ const btnRrfresh = (classes, disabled, refreshAct) => /*#__PURE__*/(0, _jsxRunti className: "txt-sv-tp", children: "Refresh Scan" }), - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - 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 - }) + 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 }) }) }); diff --git a/dist/components/cmd_bar/r03_threshold.js b/dist/components/cmd_bar/r03_threshold.js index 0ca008d9..1bbbd04e 100644 --- a/dist/components/cmd_bar/r03_threshold.js +++ b/dist/components/cmd_bar/r03_threshold.js @@ -16,7 +16,6 @@ var _CloudDoneOutlined = _interopRequireDefault(require("@mui/icons-material/Clo var _HowToRegOutlined = _interopRequireDefault(require("@mui/icons-material/HowToRegOutlined")); var _RefreshOutlined = _interopRequireDefault(require("@mui/icons-material/RefreshOutlined")); var _cfg = _interopRequireDefault(require("../../helpers/cfg")); -var _format = _interopRequireDefault(require("../../helpers/format")); var _threshold = require("../../actions/threshold"); var _common = require("./common"); var _jsxRuntime = require("react/jsx-runtime"); @@ -96,19 +95,21 @@ const Threshold = ({ thresValSt, isEditSt, curveSt, - hplcMsSt, - layoutSt, updateThresholdValueAct, resetThresholdValueAct, toggleThresholdIsEditAct }) => { - const isLcMs = _format.default.isLCMsLayout(layoutSt); - let thresVal; - if (isLcMs) { - thresVal = hplcMsSt?.threshold?.value != null ? hplcMsSt.threshold.value : feature?.thresRef ?? thresValSt ?? 5; - } else { - thresVal = thresValSt || (feature ? feature.thresRef : hplcMsSt?.threshold?.value); - } + const thresVal = thresValSt || feature.thresRef; + const { + curveIdx + } = curveSt; + const onResetThreshold = () => resetThresholdValueAct({ + value: false, + curveIdx + }); + const onToggleThreshold = () => toggleThresholdIsEditAct({ + curveIdx + }); return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { className: classes.groupRight, children: [setThreshold(classes, thresVal, updateThresholdValueAct, curveSt), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, { @@ -120,7 +121,7 @@ const Threshold = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, { className: (0, _classnames.default)('btn-sv-bar-thresref'), disabled: _cfg.default.btnCmdThres(thresVal), - onClick: resetThresholdValueAct, + onClick: onResetThreshold, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RefreshOutlined.default, { className: classes.icon }) @@ -135,7 +136,7 @@ const Threshold = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, { className: (0, _classnames.default)('btn-sv-bar-thresrst'), disabled: _cfg.default.btnCmdThres(thresVal), - onClick: toggleThresholdIsEditAct, + onClick: onToggleThreshold, children: restoreIcon(classes, hasEdit, isEditSt) }) }) @@ -148,9 +149,7 @@ const mapStateToProps = (state, props) => ( 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, - hplcMsSt: state.hplcMs, - layoutSt: state.layout + curveSt: state.curve }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ updateThresholdValueAct: _threshold.updateThresholdValue, @@ -167,11 +166,6 @@ Threshold.propTypes = { curveSt: _propTypes.default.object.isRequired, updateThresholdValueAct: _propTypes.default.func.isRequired, resetThresholdValueAct: _propTypes.default.func.isRequired, - toggleThresholdIsEditAct: _propTypes.default.func.isRequired, - hplcMsSt: _propTypes.default.object.isRequired, - layoutSt: _propTypes.default.string -}; -Threshold.defaultProps = { - layoutSt: undefined + 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 index 5b1303ac..3a9431f9 100644 --- a/dist/components/cmd_bar/r04_submit.js +++ b/dist/components/cmd_bar/r04_submit.js @@ -13,12 +13,10 @@ var _redux = require("redux"); var _material = require("@mui/material"); var _styles = require("@mui/styles"); var _submit = require("../../actions/submit"); -var _hplc_ms = require("../../actions/hplc_ms"); 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 _list_layout = require("../../constants/list_layout"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, function-paren-newline, react/function-component-definition */ @@ -33,10 +31,6 @@ const styles = () => Object.assign({ fieldDecimal: { width: 80 }, - fieldLcmsIntegrationsExport: { - width: 148, - minWidth: 148 - }, fieldOpertaion: { width: 120 } @@ -148,44 +142,6 @@ const decimalSelect = (classes, hideSwitch, decimalSt, updateDecimalAct) => { })] }); }; -const lcmsIntegrationsExportSelect = (classes, layoutSt, value, onChange) => { - if (layoutSt !== _list_layout.LIST_LAYOUT.LC_MS) return null; - const v = ['percent', 'area', 'both'].includes(value) ? value : 'percent'; - return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, { - className: (0, _classnames.default)(classes.fieldLcmsIntegrationsExport), - variant: "outlined", - children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, { - id: "select-lcms-intg-export-label", - className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'), - children: "Integrations text" - }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, { - labelId: "select-lcms-intg-export-label", - label: "Integrations text", - value: v, - onChange: onChange, - className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-lcms-intg-export'), - children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { - value: "percent", - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: (0, _classnames.default)(classes.txtOpt), - children: "Percent only" - }) - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { - value: "area", - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: (0, _classnames.default)(classes.txtOpt), - children: "Area (AUC) only" - }) - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { - value: "both", - children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: (0, _classnames.default)(classes.txtOpt), - children: "Percent and area" - }) - })] - })] - }); -}; const operationSelect = (classes, operations, operation, onChangeSelect) => { const options = operations.map(o => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { value: o.name, @@ -194,8 +150,7 @@ const operationSelect = (classes, operations, operation, onChangeSelect) => { children: o.name }) }, o.name)); - const operationNames = operations.map(o => o.name); - const selectedValue = operationNames.includes(operation?.name) ? operation.name : operations[0].name; + const selectedValue = operation.name || operations[0].name; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, { className: (0, _classnames.default)(classes.fieldOpertaion), variant: "outlined", @@ -244,20 +199,16 @@ const Submit = ({ operationSt, decimalSt, isEmWaveSt, - layoutSt, - lcmsIntegrationsExportSt, toggleIsAscendAct, toggleIsIntensityAct, updateOperationAct, - updateDecimalAct, - setLcmsIntegrationsExportAct + updateDecimalAct }) => { const onChangeSelect = e => selectOperation(e.target.value, operations, updateOperationAct); - const onLcmsIntegrationsExport = e => setLcmsIntegrationsExportAct(e.target.value); 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), lcmsIntegrationsExportSelect(classes, layoutSt, lcmsIntegrationsExportSt, onLcmsIntegrationsExport), editorOnly ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_r06_predict_btn.default, { + 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, { @@ -272,20 +223,17 @@ const Submit = ({ const mapStateToProps = (state, props) => ( // eslint-disable-line { - layoutSt: state.layout, isEmWaveSt: _format.default.isEmWaveLayout(state.layout), isAscendSt: state.submit.isAscend, isIntensitySt: state.submit.isIntensity, decimalSt: state.submit.decimal, - operationSt: state.submit.operation, - lcmsIntegrationsExportSt: state.hplcMs?.lcmsIntegrationsExport || 'percent' + operationSt: state.submit.operation }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ toggleIsAscendAct: _submit.toggleIsAscend, toggleIsIntensityAct: _submit.toggleIsIntensity, updateOperationAct: _submit.updateOperation, - updateDecimalAct: _submit.updateDecimal, - setLcmsIntegrationsExportAct: _hplc_ms.setLcmsIntegrationsExport + updateDecimalAct: _submit.updateDecimal }, dispatch); Submit.propTypes = { classes: _propTypes.default.object.isRequired, @@ -303,9 +251,6 @@ Submit.propTypes = { toggleIsAscendAct: _propTypes.default.func.isRequired, toggleIsIntensityAct: _propTypes.default.func.isRequired, updateOperationAct: _propTypes.default.func.isRequired, - updateDecimalAct: _propTypes.default.func.isRequired, - layoutSt: _propTypes.default.string.isRequired, - lcmsIntegrationsExportSt: _propTypes.default.string.isRequired, - setLcmsIntegrationsExportAct: _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 index 8bbdca97..78747a3d 100644 --- a/dist/components/cmd_bar/r05_submit_btn.js +++ b/dist/components/cmd_bar/r05_submit_btn.js @@ -76,20 +76,6 @@ const defaultThreshold = { upper: false, lower: false }; -const LCMS_INTEGRATIONS_EXPORT_MODES = ['percent', 'area', 'both']; -const isLcmsIntegrationsExportMode = v => LCMS_INTEGRATIONS_EXPORT_MODES.includes(v); -const resolveLcmsIntegrationsExportForSubmit = (analysis, hplcMsSt) => { - if (isLcmsIntegrationsExportMode(analysis?.lcmsIntegrationsExport)) { - return analysis.lcmsIntegrationsExport; - } - if (analysis?.lcmsIncludeIntegrationArea === true) { - return 'both'; - } - if (isLcmsIntegrationsExportMode(hplcMsSt?.lcmsIntegrationsExport)) { - return hplcMsSt.lcmsIntegrationsExport; - } - return 'percent'; -}; const pickFromList = (list, index, fallback = null) => Array.isArray(list) && list[index] !== undefined ? list[index] : fallback; const hasBoolean = value => typeof value === 'boolean'; const resolveOptionalBooleanFlags = analysis => { @@ -170,36 +156,17 @@ const buildSpectrumPayload = ({ ...optionalBooleanFlags }; }; -const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, analysis, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaSt, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature, hplcMsSt) => () => { +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 }] : []; - let curves = Array.isArray(curveList) && curveList.length > 0 ? curveList : defaultCurves; - if (layoutSt === 'LC/MS') { - curves = curves.filter(c => c.lcmsKind === 'uvvis'); - if (curves.length === 0) curves = defaultCurves; - } + 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]; - let lcmsGlobalFields = null; - if (layoutSt === 'LC/MS') { - const lcmsIntegrationsExport = resolveLcmsIntegrationsExportForSubmit(analysis, hplcMsSt); - lcmsGlobalFields = { - lcms_peaks: (0, _extractPeaksEdit.formatLcmsPeaksForBackend)(hplcMsSt), - lcms_integrals: (0, _extractPeaksEdit.formatLcmsIntegralsForBackend)(hplcMsSt), - lcms_integrations_export: lcmsIntegrationsExport, - lcms_peaks_text: _format.default.formatedLCMS(hplcMsSt, isAscend, decimalSt, { - lcmsIntegrationsExport - }), - lcms_uvvis_wavelength: hplcMsSt?.uvvis?.selectedWaveLength ?? null, - lcms_mz_page: hplcMsSt?.tic?.currentPageValue ?? null, - lcms_mz_page_data: (0, _extractPeaksEdit.getLcmsMzPageData)(hplcMsSt) - }; - } const spectraList = indicesToSend.map(curveIdx => { const curve = curves[curveIdx] || {}; const curveFeature = curve.feature || feature; - const spectrumPayload = buildSpectrumPayload({ + return buildSpectrumPayload({ feature: curveFeature, curveIdx, editPeakSt, @@ -219,20 +186,10 @@ const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, ana analysis, decimalSt }); - if (lcmsGlobalFields && curve.lcmsKind === 'uvvis') { - return { - ...spectrumPayload, - ...lcmsGlobalFields - }; - } - return spectrumPayload; }); const payload = { spectra_list: spectraList }; - if (lcmsGlobalFields) { - Object.assign(payload, lcmsGlobalFields); - } if (Number.isFinite(curveSt?.curveIdx)) { payload.curveSt = { curveIdx: curveSt.curveIdx @@ -261,8 +218,7 @@ const BtnSubmit = ({ curveList, axesUnitsSt, detectorSt, - metaSt, - hplcMsSt + metaSt }) => { // const disBtn = peaksEdit.length === 0 || statusSt.btnSubmit || disabled; const { @@ -296,7 +252,7 @@ const BtnSubmit = ({ 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, hplcMsSt), + 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 }) @@ -321,9 +277,9 @@ const mapStateToProps = (state, props) => ( curveList: state.curve.listCurves, axesUnitsSt: state.axesUnits, detectorSt: state.detector, - metaSt: state.meta, - hplcMsSt: state.hplcMs + metaSt: state.meta }); +const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch); BtnSubmit.propTypes = { classes: _propTypes.default.object.isRequired, feature: _propTypes.default.object.isRequired, @@ -345,10 +301,6 @@ BtnSubmit.propTypes = { curveList: _propTypes.default.array.isRequired, axesUnitsSt: _propTypes.default.object.isRequired, detectorSt: _propTypes.default.object.isRequired, - metaSt: _propTypes.default.object.isRequired, - hplcMsSt: _propTypes.default.object -}; -BtnSubmit.defaultProps = { - hplcMsSt: {} + metaSt: _propTypes.default.object.isRequired }; -var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, null), (0, _styles.withStyles)(styles))(BtnSubmit); \ No newline at end of file +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 index 3ee28c82..0a6b1163 100644 --- a/dist/components/cmd_bar/r06_predict_btn.js +++ b/dist/components/cmd_bar/r06_predict_btn.js @@ -82,7 +82,7 @@ const onClickReady = (forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analy }); }; }; -const onClickUnknown = (feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analysis, integrationSt, multiplicitySt, curveSt) => { +const onClicUnknown = (feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analysis, integrationSt, multiplicitySt, curveSt) => { const { refreshCb } = forecast; @@ -170,7 +170,7 @@ const BtnPredict = ({ if (!(is13Cor1H || isIr)) return null; const oriPeaksEdit = (0, _extractPeaksEdit.extractPeaksEdit)(feature, editPeakSt, thresSt, shiftSt, layoutSt); const peaksEdit = _format.default.rmShiftFromPeaks(oriPeaksEdit, shiftSt); - const scan = _format.default.isMsLayout(layoutSt) ? (0, _chem.Convert2Scan)(feature, scanSt) : 0; + 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; @@ -191,7 +191,7 @@ const BtnPredict = ({ realCount = stack.length; } if (is13Cor1H && simuCount === 0) { - const onClickUnknownCb = onClickUnknown(feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, forecast.predictions, integrationSt, multiplicitySt, curveSt); + 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; @@ -221,7 +221,7 @@ BtnPredict.propTypes = { feature: _propTypes.default.object.isRequired, forecast: _propTypes.default.object.isRequired, layoutSt: _propTypes.default.string.isRequired, - simulationSt: _propTypes.default.object.isRequired, + simulationSt: _propTypes.default.array.isRequired, editPeakSt: _propTypes.default.object.isRequired, scanSt: _propTypes.default.object.isRequired, shiftSt: _propTypes.default.object.isRequired, diff --git a/dist/components/cmd_bar/r07_wavelength_btn.js b/dist/components/cmd_bar/r07_wavelength_btn.js index 9b517427..326026e6 100644 --- a/dist/components/cmd_bar/r07_wavelength_btn.js +++ b/dist/components/cmd_bar/r07_wavelength_btn.js @@ -28,34 +28,33 @@ const styles = () => Object.assign({ width: 100 } }, _common.commonStyle); -const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWavelengthAct) => { +const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWaveLengthAct) => { if (!_format.default.isXRDLayout(layoutSt)) { return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {}); } - const onChange = e => updateWavelengthAct(e.target.value); + 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 (nm)" + 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, idx) => { + children: _list_wavelength.LIST_WAVE_LENGTH.map(item => { // eslint-disable-line - const itemKey = `${item.label}-${item.value}-${item.unit}-${idx}`; 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, ")"] }) - }, itemKey); + }); }) })] }); @@ -64,10 +63,10 @@ const Wavelength = ({ classes, waveLengthSt, layoutSt, - updateWavelengthAct + updateWaveLengthAct }) => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: classes.groupRight, - children: wavelengthSelect(classes, waveLengthSt, layoutSt, updateWavelengthAct) + children: wavelengthSelect(classes, waveLengthSt, layoutSt, updateWaveLengthAct) }); const mapStateToProps = (state, props) => ( // eslint-disable-line @@ -76,12 +75,12 @@ const mapStateToProps = (state, props) => ( layoutSt: state.layout }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ - updateWavelengthAct: _wavelength.updateWaveLength + 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 + 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/r09_detector.js b/dist/components/cmd_bar/r09_detector.js index 380e6240..3efdcf7c 100644 --- a/dist/components/cmd_bar/r09_detector.js +++ b/dist/components/cmd_bar/r09_detector.js @@ -64,13 +64,13 @@ const detectorSelect = (classes, detectorSt, curveSt, layoutSt, updateDetectorAc children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout') }) - }, "detector-empty"), _list_detectors.LIST_DETECTORS.map((item, idx) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { + }), _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 }) - }, item?.name || item?.id || `detector-${idx}`))] + }))] })] }); }; diff --git a/dist/components/cmd_bar/tri_btn.js b/dist/components/cmd_bar/tri_btn.js index 30641cdc..64800f48 100644 --- a/dist/components/cmd_bar/tri_btn.js +++ b/dist/components/cmd_bar/tri_btn.js @@ -126,9 +126,6 @@ TriBtn.propTypes = { content: _propTypes.default.object.isRequired, cb: _propTypes.default.func.isRequired, children: _propTypes.default.node.isRequired, - isClearAllDisabled: _propTypes.default.bool -}; -TriBtn.defaultProps = { - isClearAllDisabled: false + 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/draw.js b/dist/components/common/draw.js index ad86fad9..16d930f8 100644 --- a/dist/components/common/draw.js +++ b/dist/components/common/draw.js @@ -5,17 +5,16 @@ Object.defineProperty(exports, "__esModule", { }); exports.drawMain = exports.drawLabel = exports.drawDisplay = exports.drawDestroy = exports.drawArrowOnCurve = void 0; const d3 = require('d3'); -const { - LIST_BRUSH_SVG_GRAPH -} = require('../../constants/list_graph'); -const drawMain = (klass, w, h, d3svgClass = LIST_BRUSH_SVG_GRAPH.LINE) => { - d3.select(klass).append('svg').attr('class', d3svgClass).attr('preserveAspectRatio', 'xMinYMin meet').attr('viewBox', `0 0 ${w} ${h}`); +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); - d3.select(klass).selectAll('.mark-text').text(cLabel || ''); + if (cLabel) { + d3.select(klass).selectAll('.mark-text').text(cLabel); + } }; exports.drawLabel = drawLabel; const drawDisplay = (klass, isHidden) => { @@ -26,7 +25,7 @@ const drawDisplay = (klass, isHidden) => { } }; exports.drawDisplay = drawDisplay; -const drawDestroy = klass => d3.select(`${klass} > *`).remove(); +const drawDestroy = klass => d3.select(klass).selectAll('*').remove(); exports.drawDestroy = drawDestroy; const drawArrowOnCurve = (klass, isHidden) => { if (isHidden) { diff --git a/dist/components/d3_line/index.js b/dist/components/d3_line/index.js index 9b0acfac..d9648444 100644 --- a/dist/components/d3_line/index.js +++ b/dist/components/d3_line/index.js @@ -12,12 +12,9 @@ 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 _list_graph = require("../../constants/list_graph"); -var _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable no-mixed-operators */ @@ -31,24 +28,17 @@ class ViewerLine extends _react.default.Component { const { clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct + scrollUiWheelAct } = props; - this.rootKlass = `.${_list_graph.LIST_ROOT_SVG_GRAPH.LINE}`; + this.rootKlass = '.d3Line'; this.focus = new _line_focus.default({ W, H, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct + scrollUiWheelAct }); this.normChange = this.normChange.bind(this); - this.syncFocusActions = this.syncFocusActions.bind(this); } componentDidMount() { const { @@ -64,20 +54,16 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integrationSt, + integationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, wavelength, axesUnitsSt, - resetAllAct, - uiSt + resetAllAct } = this.props; - this.syncFocusActions(); (0, _draw.drawDestroy)(this.rootKlass); resetAllAct(feature); let xxLabel = xLabel; @@ -105,15 +91,12 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integrationSt, + integationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, - wavelength, - uiSt + wavelength }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); @@ -131,19 +114,15 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integrationSt, + integationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, wavelength, - axesUnitsSt, - uiSt + axesUnitsSt } = this.props; - this.syncFocusActions(); this.normChange(prevProps); let xxLabel = xLabel; let yyLabel = yLabel; @@ -169,15 +148,12 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integrationSt, + integationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, - wavelength, - uiSt + wavelength }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); @@ -185,25 +161,6 @@ class ViewerLine extends _react.default.Component { componentWillUnmount() { (0, _draw.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, @@ -216,7 +173,7 @@ class ViewerLine extends _react.default.Component { } render() { return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: _list_graph.LIST_ROOT_SVG_GRAPH.LINE + className: "d3Line" }); } } @@ -229,25 +186,19 @@ const mapStateToProps = (state, props) => ({ tSfPeaks: (0, _chem.ToShiftPeaks)(state, props), editPeakSt: state.editPeak.present, layoutSt: state.layout, - integrationSt: state.integration.present, + 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: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, - isUiVisualSplitIntgSt: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0, wavelength: state.wavelength, - axesUnitsSt: state.axesUnits, - uiSt: state.ui + axesUnitsSt: state.axesUnits }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ resetAllAct: _manager.resetAll, clickUiTargetAct: _ui.clickUiTarget, selectUiSweepAct: _ui.selectUiSweep, scrollUiWheelAct: _ui.scrollUiWheel, - splitIntegrationAct: _integration.splitIntegration, - addVisualSplitLineAct: _integration.addVisualSplitLine, - removeVisualSplitLineAct: _integration.removeVisualSplitLine, addNewCylicVoltaPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak, addCylicVoltaMaxPeakAct: _cyclic_voltammetry.addCylicVoltaMaxPeak, addCylicVoltaMinPeakAct: _cyclic_voltammetry.addCylicVoltaMinPeak @@ -257,7 +208,6 @@ ViewerLine.propTypes = { peak: _propTypes.default.array.isRequired, freq: _propTypes.default.oneOfType([_propTypes.default.bool, _propTypes.default.number]).isRequired, comparisons: _propTypes.default.array.isRequired, - uiSt: _propTypes.default.object.isRequired, cLabel: _propTypes.default.string.isRequired, xLabel: _propTypes.default.string.isRequired, yLabel: _propTypes.default.string.isRequired, @@ -266,20 +216,15 @@ ViewerLine.propTypes = { tSfPeaks: _propTypes.default.array.isRequired, editPeakSt: _propTypes.default.object.isRequired, layoutSt: _propTypes.default.string.isRequired, - integrationSt: _propTypes.default.object.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, - isUiVisualSplitIntgSt: _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, - addVisualSplitLineAct: _propTypes.default.func.isRequired, - removeVisualSplitLineAct: _propTypes.default.func.isRequired, isHidden: _propTypes.default.bool.isRequired, wavelength: _propTypes.default.object.isRequired, axesUnitsSt: _propTypes.default.object.isRequired diff --git a/dist/components/d3_line/line_focus.js b/dist/components/d3_line/line_focus.js index 113c3abe..30004133 100644 --- a/dist/components/d3_line/line_focus.js +++ b/dist/components/d3_line/line_focus.js @@ -9,8 +9,6 @@ var _init = require("../../helpers/init"); var _mount = require("../../helpers/mount"); var _brush = _interopRequireDefault(require("../../helpers/brush")); var _compass = require("../../helpers/compass"); -var _integration_focus = require("../../helpers/integration_focus"); -var _integration_split = require("../../helpers/integration_split"); var _converter = require("../../helpers/converter"); var _focus = require("../../helpers/focus"); var _integration = require("../../helpers/integration"); @@ -18,6 +16,7 @@ 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"); +var _calc = require("../../helpers/calc"); /* eslint-disable prefer-object-spread, no-mixed-operators */ const d3 = require('d3'); @@ -28,11 +27,7 @@ class LineFocus { H, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct, - uiSt, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct + scrollUiWheelAct } = props; this.jcampIdx = 0; this.rootKlass = '.d3Line'; @@ -42,16 +37,11 @@ class LineFocus { l: 60, r: 5 }; - this.uiSt = uiSt; - this.graphIndex = uiSt?.zoom?.graphIndex; 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.addVisualSplitLineAct = addVisualSplitLineAct; - this.removeVisualSplitLineAct = removeVisualSplitLineAct; this.brush = d3.brush(); this.brushX = d3.brushX(); this.axis = null; @@ -76,11 +66,6 @@ class LineFocus { this.shouldUpdate = {}; this.freq = false; this.layout = _list_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); this.setTip = this.setTip.bind(this); @@ -98,10 +83,6 @@ 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.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'; this.wavelength = null; @@ -130,7 +111,7 @@ class LineFocus { const sameMySt = prevMySt === nextMySt; const sameTePt = prevTePt === this.tTrEndPts.length; const sameDtPk = prevDtPk === this.dataPks.length; - const sameSfPk = prevSfPk === this.tSfPeaks || Array.isArray(prevSfPk) && Array.isArray(this.tSfPeaks) && prevSfPk.length === this.tSfPeaks.length && prevSfPk.every((peak, idx) => peak === this.tSfPeaks[idx]); + 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, { @@ -275,28 +256,49 @@ class LineFocus { const onPeak = true; this.clickUiTargetAct(data, onPeak); } - clearSplitPreview() { - (0, _integration_split.clearIntegrationSplitPreview)(this); - } - onIntegrationMouseMove(event, data, shift, ignoreRef) { - (0, _integration_focus.handleIntegrationMouseMove)(this, event, data, shift, ignoreRef); - } - onClickIntegrationTarget(event, data) { - (0, _integration_focus.handleIntegrationClick)(this, event, data, (clickEvent, clickData) => { - this.onClickTarget(clickEvent, clickData); - }); - } - drawVisualSplitLines(stack, shift, ignoreRef) { - (0, _integration_focus.drawVisualSplitLinesForFocus)(this, stack, shift, ignoreRef); - } - drawAUC(stack, shift = 0) { - (0, _integration_focus.drawIntegrationAUC)(this, stack, shift); - } mergedPeaks(editPeakSt) { if (!editPeakSt) return this.dataPks; this.dataPks = (0, _converter.PksEdit)(this.dataPks, editPeakSt); return this.dataPks; } + drawAUC(stack) { + 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 = this.data.filter(d => d.x > xL && d.x < xU); + if (!ps[0]) return null; + const point1 = ps[0]; + const point2 = ps[ps.length - 1]; + const slope = (0, _calc.calcSlope)(point1.x, point1.y, point2.x, point2.y); + let lastDY = point1.y; + 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); + }).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); + }).on('click', (event, d) => this.onClickTarget(event, d)); + } drawPeaks(editPeakSt) { const { sameXY, @@ -314,6 +316,10 @@ class LineFocus { const dPks = this.mergedPeaks(editPeakSt); const mpp = this.tags.pPath.selectAll('path').data(dPks); mpp.exit().attr('class', 'exit').remove(); + const clearPeakLabels = () => { + const bpTxt = this.tags.bpTxt.selectAll('text').data([]); + bpTxt.exit().attr('class', 'exit').remove(); + }; const linePath = [{ x: -0.5, y: 10 @@ -351,9 +357,11 @@ class LineFocus { 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)); + } else { + clearPeakLabels(); } } - drawInteg(integrationState) { + drawInteg(integationSt) { const { sameXY, sameLySt, @@ -361,11 +369,29 @@ class LineFocus { sameData } = this.shouldUpdate; if (sameXY && sameLySt && sameItSt && sameData) return; + const clearIntegralPaths = () => { + const empty = []; + const igbp = this.tags.igbPath.selectAll('path').data(empty); + igbp.exit().attr('class', 'exit').remove(); + const igcp = this.tags.igcPath.selectAll('path').data(empty); + igcp.exit().attr('class', 'exit').remove(); + const igtp = this.tags.igtPath.selectAll('text').data(empty); + igtp.exit().attr('class', 'exit').remove(); + }; + const clearAUC = () => { + const auc = this.tags.aucPath.selectAll('path').data([]); + auc.exit().attr('class', 'exit').remove(); + }; const { selectedIdx, integrations - } = integrationState; + } = integationSt; const selectedIntegration = integrations[selectedIdx]; + if (selectedIntegration === false || selectedIntegration === undefined) { + clearIntegralPaths(); + clearAUC(); + return; + } const { stack, refArea, @@ -375,34 +401,22 @@ class LineFocus { const isDisable = _cfg.default.btnCmdIntg(this.layout); const ignoreRef = _format.default.isHplcUvVisLayout(this.layout); const itgs = isDisable ? [] : stack; - const { - showIntegSplit, - igBarData - } = (0, _integration_focus.buildIntegrationBarData)(this.layout, itgs); - Object.assign(this, { - integrationSplitTargets: { - stack: itgs, - shift, - ignoreRef - } - }); - const igbp = this.tags.igbPath.selectAll('path').data(igBarData); + const igbp = this.tags.igbPath.selectAll('path').data(itgs); igbp.exit().attr('class', 'exit').remove(); - const igcp = this.tags.igcPath.selectAll('path').data(igBarData); + 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); - this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); + clearIntegralPaths(); + clearAUC(); return; } if (ignoreRef) { - this.drawAUC(stack, shift); + clearIntegralPaths(); + this.drawAUC(stack); } else { + clearAUC(); // rescale for zoom const { xt @@ -417,8 +431,7 @@ class LineFocus { 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'); - if (showIntegSplit) this.clearSplitPreview(); - }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); + }).on('click', (event, d) => this.onClickTarget(event, d)); const integCurve = border => { const { xL, @@ -442,8 +455,7 @@ class LineFocus { 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'); - if (showIntegSplit) this.clearSplitPreview(); - }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); + }).on('click', (event, d) => this.onClickTarget(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'); @@ -452,10 +464,8 @@ class LineFocus { 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'); - if (showIntegSplit) this.clearSplitPreview(); - }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); + }).on('click', (event, d) => this.onClickTarget(event, d)); } - this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); } drawMtply(mtplySt) { const { @@ -466,19 +476,17 @@ class LineFocus { if (sameXY && sameLySt && sameMySt) return; const { selectedIdx, - multiplicities = [] - } = mtplySt || {}; - const selectedMulti = multiplicities[selectedIdx] || {}; + multiplicities + } = mtplySt; + const selectedMulti = multiplicities[selectedIdx]; const { - stack = [], - smExtext = false, - shift = 0 + stack, + smExtext, + shift } = selectedMulti; - const hasValidExtent = extent => extent && Number.isFinite(extent.xL) && Number.isFinite(extent.xU); - const mpys = stack.filter(m => hasValidExtent(m?.xExtent)); + const mpys = stack; const isDisable = _cfg.default.btnCmdMpy(this.layout); - if (mpys.length === 0 || isDisable) return; - const activeExtent = hasValidExtent(smExtext) ? smExtext : mpys[0].xExtent; + if (mpys === 0 || isDisable) return; // rescale for zoom const { xt @@ -494,8 +502,7 @@ class LineFocus { peaks, xExtent } = m; - const safePeaks = Array.isArray(peaks) ? peaks : []; - return safePeaks.filter(p => Number.isFinite(p?.x) && Number.isFinite(p?.y)).map(p => Object.assign({}, p, { + return peaks.map(p => Object.assign({}, p, { xExtent })); }); @@ -510,7 +517,7 @@ class LineFocus { xL, xU } = d.xExtent; - return activeExtent.xL === xL && activeExtent.xU === xU ? 'purple' : '#DA70D6'; + 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'); @@ -624,18 +631,13 @@ class LineFocus { comparisons, editPeakSt, layoutSt, - integrationSt, + integationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, - wavelength, - uiSt + wavelength }) { - this.uiSt = uiSt; - this.graphIndex = uiSt?.zoom?.graphIndex; this.svg = d3.select('.d3Svg'); (0, _mount.MountMainFrame)(this, 'focus'); (0, _mount.MountClip)(this); @@ -643,11 +645,6 @@ class LineFocus { this.scales = (0, _init.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(); (0, _compass.MountCompass)(this); this.axis = (0, _mount.MountAxis)(this); this.path = (0, _mount.MountPath)(this, 'steelblue'); @@ -664,12 +661,12 @@ class LineFocus { this.drawGrid(); this.drawRef(); this.drawPeaks(editPeakSt); - this.drawInteg(integrationSt); + this.drawInteg(integationSt); this.drawMtply(mtplySt); this.drawComparisons(comparisons); } (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt); - this.resetShouldUpdate(editPeakSt, integrationSt, mtplySt); + this.resetShouldUpdate(editPeakSt, integationSt, mtplySt); } update({ filterSeed, @@ -680,40 +677,30 @@ class LineFocus { comparisons, editPeakSt, layoutSt, - integrationSt, + integationSt, mtplySt, - uiSt, sweepExtentSt, isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, wavelength }) { - this.uiSt = uiSt; - this.graphIndex = uiSt?.zoom?.graphIndex; 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, - isUiVisualSplitIntgSt - }); - if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview(); if (this.data && this.data.length > 0) { this.setConfig(sweepExtentSt); - this.getShouldUpdate(editPeakSt, integrationSt, mtplySt); + this.getShouldUpdate(editPeakSt, integationSt, mtplySt); this.drawLine(); this.drawThres(); this.drawGrid(); this.drawRef(); this.drawPeaks(editPeakSt); - this.drawInteg(integrationSt); + this.drawInteg(integationSt); this.drawMtply(mtplySt); this.drawComparisons(comparisons); } (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt); - this.resetShouldUpdate(editPeakSt, integrationSt, mtplySt); + 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 index 9096bb2c..a179f126 100644 --- a/dist/components/d3_multi/index.js +++ b/dist/components/d3_multi/index.js @@ -11,12 +11,9 @@ var _redux = require("redux"); var _propTypes = _interopRequireDefault(require("prop-types")); var _chem = require("../../helpers/chem"); var _format = _interopRequireDefault(require("../../helpers/format")); -var _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _manager = require("../../actions/manager"); var _ui = require("../../actions/ui"); -var _integration = require("../../actions/integration"); var _list_ui = require("../../constants/list_ui"); -var _list_graph = require("../../constants/list_graph"); var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry"); var _multi_focus = _interopRequireDefault(require("./multi_focus")); var _draw = require("../common/draw"); @@ -27,6 +24,10 @@ 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 +const buildResetPayload = (feature, curveSt) => ({ + ...feature, + curveIdx: curveSt.curveIdx +}); class ViewerMulti extends _react.default.Component { constructor(props) { super(props); @@ -34,12 +35,9 @@ class ViewerMulti extends _react.default.Component { entities, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct + scrollUiWheelAct } = this.props; - this.rootKlass = `.${_list_graph.LIST_ROOT_SVG_GRAPH.LINE}`; + this.rootKlass = '.d3Line'; this.containerRef = /*#__PURE__*/_react.default.createRef(); this.currentSize = null; this.resizeObserver = null; @@ -49,18 +47,85 @@ class ViewerMulti extends _react.default.Component { entities, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct + scrollUiWheelAct }); this.normChange = this.normChange.bind(this); this.handleResize = this.handleResize.bind(this); - this.syncFocusActions = this.syncFocusActions.bind(this); } componentDidMount() { + this.renderChart(this.props, true); this.setupResizeObserver(); - this.mountChart(this.props, true); + const { + curveSt, + seed, + peak, + cLabel, + xLabel, + yLabel, + feature, + tTrEndPts, + tSfPeaks, + editPeakSt, + layoutSt, + sweepExtentSt, + isUiNoBrushSt, + isHidden, + resetAllAct, + cyclicvoltaSt, + integationSt, + mtplySt, + axesUnitsSt + } = this.props; + (0, _draw.drawDestroy)(this.rootKlass); + resetAllAct(buildResetPayload(feature, curveSt)); + 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, + 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 { @@ -76,50 +141,65 @@ class ViewerMulti extends _react.default.Component { editPeakSt, layoutSt, sweepExtentSt, - isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, cyclicvoltaSt, - integrationSt, + integationSt, mtplySt, - axesUnitsSt, - uiSt + axesUnitsSt } = this.props; - this.syncFocusActions(); 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(); } - const hasRelevantChange = prevProps.entities !== entities || prevProps.curveSt !== curveSt || prevProps.seed !== seed || prevProps.peak !== peak || prevProps.tTrEndPts !== tTrEndPts || prevProps.tSfPeaks !== tSfPeaks || prevProps.editPeakSt !== editPeakSt || prevProps.layoutSt !== layoutSt || prevProps.sweepExtentSt !== sweepExtentSt || prevProps.isUiNoBrushSt !== isUiNoBrushSt || prevProps.isHidden !== isHidden || prevProps.cyclicvoltaSt !== cyclicvoltaSt || prevProps.integrationSt !== integrationSt || prevProps.mtplySt !== mtplySt || prevProps.axesUnitsSt !== axesUnitsSt || prevProps.uiSt !== uiSt || prevProps.cLabel !== cLabel || prevProps.xLabel !== xLabel || prevProps.yLabel !== yLabel; - if (!hasRelevantChange) return; - const { - xxLabel, - yyLabel - } = this.resolveAxisLabels(this.props); this.focus.update({ entities, curveSt, - filterSeed: seed, - filterPeak: peak, + filterSeed, + filterPeak, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, - isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, - integrationSt, - mtplySt, - uiSt + integationSt, + mtplySt }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); - (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden || !_format.default.isAIFLayout(layoutSt)); + (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden); } componentWillUnmount() { (0, _draw.drawDestroy)(this.rootKlass); @@ -133,7 +213,7 @@ class ViewerMulti extends _react.default.Component { const size = this.getContainerSize(); if (!size) return; if (!this.currentSize || size.width !== this.currentSize.width || size.height !== this.currentSize.height) { - this.mountChart(this.props, false); + this.renderChart(this.props, false); } } getContainerSize() { @@ -165,159 +245,107 @@ class ViewerMulti extends _react.default.Component { this.resizeObserver = new ResizeObserver(this.handleResize); 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(); this.resizeObserver = null; } } - resolveAxisLabels(props) { - const { - curveSt, - xLabel, - yLabel, - axesUnitsSt, - cyclicvoltaSt - } = props; - let xxLabel = xLabel; - let yyLabel = yLabel; - if (axesUnitsSt) { - const { - curveIdx - } = curveSt; - const { - axes - } = axesUnitsSt; - const selectedAxes = axes[curveIdx] || { - 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}`; - } - return { - xxLabel, - yyLabel - }; - } normChange(prevProps) { const { feature, resetAllAct, - entities + entities, + curveSt } = this.props; const oldEntities = prevProps.entities; if (oldEntities !== entities) { - resetAllAct(feature); + resetAllAct(buildResetPayload(feature, curveSt)); } } - createMultiFocus(size, props) { - const { - entities, - clickUiTargetAct, - selectUiSweepAct, - scrollUiWheelAct, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct - } = props; - return new _multi_focus.default({ - W: size.width, - H: size.height, - entities, - clickUiTargetAct, - selectUiSweepAct, - scrollUiWheelAct, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct - }); - } - mountChart(props, shouldReset = false) { + renderChart(props, shouldReset) { const { curveSt, seed, peak, cLabel, + xLabel, + yLabel, feature, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, - isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, resetAllAct, cyclicvoltaSt, - integrationSt, + integationSt, mtplySt, - uiSt + axesUnitsSt, + entities, + clickUiTargetAct, + selectUiSweepAct, + scrollUiWheelAct } = props; const size = this.getTargetSize(layoutSt); this.currentSize = size; (0, _draw.drawDestroy)(this.rootKlass); if (shouldReset) { - resetAllAct(feature); + resetAllAct(buildResetPayload(feature, curveSt)); } - const { - xxLabel, - yyLabel - } = this.resolveAxisLabels(props); - this.focus = this.createMultiFocus(size, props); - this.syncFocusActions(); + 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 + }); (0, _draw.drawMain)(this.rootKlass, size.width, size.height); this.focus.create({ curveSt, - filterSeed: seed, - filterPeak: peak, + filterSeed, + filterPeak, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, - isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, - integrationSt, - mtplySt, - uiSt + integationSt, + mtplySt }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); - (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden || !_format.default.isAIFLayout(layoutSt)); + (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden); } render() { const { @@ -325,7 +353,7 @@ class ViewerMulti extends _react.default.Component { } = this.props; const isCyclicVolta = _format.default.isCyclicVoltaLayout(layoutSt); return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: _list_graph.LIST_ROOT_SVG_GRAPH.LINE, + className: "d3Line", ref: this.containerRef, style: isCyclicVolta ? { height: '100%' @@ -335,7 +363,6 @@ class ViewerMulti extends _react.default.Component { } const mapStateToProps = (state, props) => ({ curveSt: state.curve, - uiSt: state.ui, seed: (0, _chem.Topic2Seed)(state, props), peak: (0, _chem.Feature2Peak)(state, props), tTrEndPts: (0, _chem.ToThresEndPts)(state, props), @@ -343,13 +370,10 @@ const mapStateToProps = (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: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, - isUiVisualSplitIntgSt: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0, cyclicvoltaSt: state.cyclicvolta, maxminPeakSt: (0, _chem.Feature2MaxMinPeak)(state, props), - integrationSt: state.integration.present, + integationSt: state.integration.present, mtplySt: state.multiplicity.present, axesUnitsSt: state.axesUnits }); @@ -358,16 +382,12 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ clickUiTargetAct: _ui.clickUiTarget, selectUiSweepAct: _ui.selectUiSweep, scrollUiWheelAct: _ui.scrollUiWheel, - splitIntegrationAct: _integration.splitIntegration, - addVisualSplitLineAct: _integration.addVisualSplitLine, - removeVisualSplitLineAct: _integration.removeVisualSplitLine, addNewCylicVoltaPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak, addCylicVoltaMaxPeakAct: _cyclic_voltammetry.addCylicVoltaMaxPeak, addCylicVoltaMinPeakAct: _cyclic_voltammetry.addCylicVoltaMinPeak }, dispatch); ViewerMulti.propTypes = { curveSt: _propTypes.default.object.isRequired, - uiSt: _propTypes.default.object.isRequired, entities: _propTypes.default.array.isRequired, seed: _propTypes.default.array.isRequired, peak: _propTypes.default.array.isRequired, @@ -378,20 +398,14 @@ ViewerMulti.propTypes = { tSfPeaks: _propTypes.default.array.isRequired, editPeakSt: _propTypes.default.object.isRequired, layoutSt: _propTypes.default.string.isRequired, - integrationSt: _propTypes.default.object.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, - isUiVisualSplitIntgSt: _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, - addVisualSplitLineAct: _propTypes.default.func.isRequired, - removeVisualSplitLineAct: _propTypes.default.func.isRequired, isHidden: _propTypes.default.bool, cyclicvoltaSt: _propTypes.default.object.isRequired, maxminPeakSt: _propTypes.default.object, diff --git a/dist/components/d3_multi/multi_focus.js b/dist/components/d3_multi/multi_focus.js index 93431eb5..e646b50c 100644 --- a/dist/components/d3_multi/multi_focus.js +++ b/dist/components/d3_multi/multi_focus.js @@ -10,8 +10,6 @@ var _mount = require("../../helpers/mount"); var _converter = require("../../helpers/converter"); var _brush = _interopRequireDefault(require("../../helpers/brush")); var _compass = require("../../helpers/compass"); -var _integration_focus = require("../../helpers/integration_focus"); -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"); @@ -19,6 +17,7 @@ var _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _focus = require("../../helpers/focus"); var _integration = require("../../helpers/integration"); var _multiplicity_calc = require("../../helpers/multiplicity_calc"); +var _calc = require("../../helpers/calc"); /* eslint-disable no-unused-vars, prefer-object-spread, no-mixed-operators, no-unneeded-ternary, arrow-body-style, max-len */ @@ -31,14 +30,8 @@ class MultiFocus { clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, - entities, - uiSt, - splitIntegrationAct, - addVisualSplitLineAct, - removeVisualSplitLineAct + entities } = props; - this.uiSt = uiSt; - this.graphIndex = uiSt?.zoom?.graphIndex; this.entities = entities; this.jcampIdx = 0; this.isShowAllCurves = false; @@ -54,9 +47,6 @@ 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(); this.axis = null; @@ -83,11 +73,6 @@ class MultiFocus { this.shouldUpdate = {}; // this.freq = false; this.layout = _list_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); this.setTip = this.setTip.bind(this); @@ -105,10 +90,6 @@ 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.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); @@ -127,7 +108,8 @@ class MultiFocus { prevDtPk, prevSfPk, prevData, - prevYFactor + prevYFactor, + prevJcampIdx } = this.shouldUpdate; const { xt, @@ -138,9 +120,10 @@ class MultiFocus { const sameLySt = prevLySt === this.layout; const sameTePt = prevTePt === this.tTrEndPts.length; const sameDtPk = prevDtPk === this.dataPks.length; - const sameSfPk = prevSfPk === this.tSfPeaks || Array.isArray(prevSfPk) && Array.isArray(this.tSfPeaks) && prevSfPk.length === this.tSfPeaks.length && prevSfPk.every((peak, idx) => peak === this.tSfPeaks[idx]); + const sameSfPk = JSON.stringify(prevSfPk) === JSON.stringify(this.tSfPeaks); const sameData = prevData === this.data.length; const sameYFactor = prevYFactor === this.yTransformFactor; + const sameJcampIdx = prevJcampIdx === this.jcampIdx; this.shouldUpdate = Object.assign({}, this.shouldUpdate, { sameXY, sameEpSt, @@ -150,7 +133,8 @@ class MultiFocus { sameDtPk, sameSfPk, sameData, - sameYFactor // eslint-disable-line + sameYFactor, + sameJcampIdx // eslint-disable-line }); } resetShouldUpdate(prevEpSt) { @@ -166,6 +150,7 @@ class MultiFocus { const prevData = this.data.length; const prevLySt = this.layout; const prevYFactor = this.yTransformFactor; + const prevJcampIdx = this.jcampIdx; this.shouldUpdate = Object.assign({}, this.shouldUpdate, { prevXt, prevYt, @@ -176,7 +161,8 @@ class MultiFocus { prevDtPk, prevSfPk, prevData, - prevYFactor // eslint-disable-line + prevYFactor, + prevJcampIdx // eslint-disable-line }); } setTip() { @@ -317,8 +303,6 @@ class MultiFocus { this.path.style('stroke', this.pathColor); if (this.layout === _list_layout.LIST_LAYOUT.AIF) { this.path.attr('marker-mid', 'url(#arrow-left)'); - } else { - this.path.attr('marker-mid', null); } } drawThres() { @@ -351,8 +335,6 @@ class MultiFocus { path.attr('d', this.pathCall(data)); if (this.layout === _list_layout.LIST_LAYOUT.AIF && this.isShowAllCurves === true) { path.attr('marker-mid', 'url(#arrow-left)'); - } else { - path.attr('marker-mid', null); } }); return null; @@ -381,23 +363,6 @@ class MultiFocus { this.clickUiTargetAct(data, onPeak, false, this.jcampIdx); } } - clearSplitPreview() { - (0, _integration_split.clearIntegrationSplitPreview)(this); - } - onIntegrationMouseMove(event, data, shift, ignoreRef) { - (0, _integration_focus.handleIntegrationMouseMove)(this, event, data, shift, ignoreRef); - } - onClickIntegrationTarget(event, data) { - (0, _integration_focus.handleIntegrationClick)(this, event, data, (clickEvent, clickData) => { - this.onClickTarget(clickEvent, clickData); - }); - } - drawVisualSplitLines(stack, shift, ignoreRef) { - (0, _integration_focus.drawVisualSplitLinesForFocus)(this, stack, shift, ignoreRef); - } - drawAUC(stack, shift = 0) { - (0, _integration_focus.drawIntegrationAUC)(this, stack, shift); - } onClickPecker(event, data) { event.stopPropagation(); event.preventDefault(); @@ -436,14 +401,53 @@ class MultiFocus { } return this.dataPeckers; } + drawAUC(stack) { + 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 = this.data.filter(d => d.x > xL && d.x < xU); + if (!ps[0]) return null; + const point1 = ps[0]; + const point2 = ps[ps.length - 1]; + const slope = (0, _calc.calcSlope)(point1.x, point1.y, point2.x, point2.y); + let lastDY = point1.y; + 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); + }).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); + }).on('click', (event, d) => this.onClickTarget(event, d)); + } drawPeaks(editPeakSt) { const { sameXY, sameEpSt, sameDtPk, - sameSfPk + sameSfPk, + sameJcampIdx } = this.shouldUpdate; - if (!_format.default.isCyclicVoltaLayout(this.layout) && sameXY && sameEpSt && sameDtPk && sameSfPk) return; + if (!_format.default.isCyclicVoltaLayout(this.layout) && sameXY && sameEpSt && sameDtPk && sameSfPk && sameJcampIdx) return; // rescale for zoom const { @@ -476,6 +480,10 @@ class MultiFocus { } const mpp = this.tags.pPath.selectAll('path').data(dPks); mpp.exit().attr('class', 'exit').remove(); + const clearPeakLabels = () => { + const bpTxt = this.tags.bpTxt.selectAll('text').data([]); + bpTxt.exit().attr('class', 'exit').remove(); + }; const linePath = [{ x: -0.5, y: 10 @@ -532,6 +540,8 @@ class MultiFocus { 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)); + } else { + clearPeakLabels(); } mpp.attr('fill', (_, index) => { return indexOfCVRefPeaks[index] === -1 ? 'blue' : 'red'; @@ -545,9 +555,10 @@ class MultiFocus { sameXY, sameEpSt, sameDtPk, - sameSfPk + sameSfPk, + sameJcampIdx } = this.shouldUpdate; - if (!_format.default.isCyclicVoltaLayout(this.layout) && sameXY && sameEpSt && sameDtPk && sameSfPk) return; + if (!_format.default.isCyclicVoltaLayout(this.layout) && sameXY && sameEpSt && sameDtPk && sameSfPk && sameJcampIdx) return; // rescale for zoom const { @@ -591,34 +602,35 @@ class MultiFocus { this.tip.hide(tipParams, event.target); }).on('click', (event, d) => this.onClickPecker(event, d)); } - drawInteg(integrationState) { + drawInteg(integationSt) { const { sameXY, sameLySt, sameItSt, - sameData + sameData, + sameJcampIdx } = this.shouldUpdate; - if (sameXY && sameLySt && sameItSt && sameData) return; + if (sameXY && sameLySt && sameItSt && sameData && sameJcampIdx) return; + const clearIntegralPaths = () => { + const empty = []; + const igbp = this.tags.igbPath.selectAll('path').data(empty); + igbp.exit().attr('class', 'exit').remove(); + const igcp = this.tags.igcPath.selectAll('path').data(empty); + igcp.exit().attr('class', 'exit').remove(); + const igtp = this.tags.igtPath.selectAll('text').data(empty); + igtp.exit().attr('class', 'exit').remove(); + }; + const clearAUC = () => { + const auc = this.tags.aucPath.selectAll('path').data([]); + auc.exit().attr('class', 'exit').remove(); + }; const { integrations - } = integrationState; + } = 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(); - this.drawVisualSplitLines([], 0, false); + clearIntegralPaths(); + clearAUC(); return; } const { @@ -630,34 +642,22 @@ class MultiFocus { const isDisable = _cfg.default.btnCmdIntg(this.layout); const ignoreRef = _format.default.isHplcUvVisLayout(this.layout); const itgs = isDisable ? [] : stack; - const { - showIntegSplit, - igBarData - } = (0, _integration_focus.buildIntegrationBarData)(this.layout, itgs); - Object.assign(this, { - integrationSplitTargets: { - stack: itgs, - shift, - ignoreRef - } - }); - const igbp = this.tags.igbPath.selectAll('path').data(igBarData); + const igbp = this.tags.igbPath.selectAll('path').data(itgs); igbp.exit().attr('class', 'exit').remove(); - const igcp = this.tags.igcPath.selectAll('path').data(igBarData); + 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); - this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); + clearIntegralPaths(); + clearAUC(); return; } if (ignoreRef) { - this.drawAUC(stack, shift); + clearIntegralPaths(); + this.drawAUC(stack); } else { + clearAUC(); // rescale for zoom const { xt @@ -672,8 +672,7 @@ class MultiFocus { 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'); - if (showIntegSplit) this.clearSplitPreview(); - }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); + }).on('click', (event, d) => this.onClickTarget(event, d)); const integCurve = border => { const { xL, @@ -697,8 +696,7 @@ class MultiFocus { 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'); - if (showIntegSplit) this.clearSplitPreview(); - }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); + }).on('click', (event, d) => this.onClickTarget(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'); @@ -707,18 +705,17 @@ class MultiFocus { 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'); - if (showIntegSplit) this.clearSplitPreview(); - }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); + }).on('click', (event, d) => this.onClickTarget(event, d)); } - this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); } drawMtply(mtplySt) { const { sameXY, sameLySt, - sameMySt + sameMySt, + sameJcampIdx } = this.shouldUpdate; - if (sameXY && sameLySt && sameMySt) return; + if (sameXY && sameLySt && sameMySt && sameJcampIdx) return; const { multiplicities } = mtplySt; @@ -746,15 +743,13 @@ class MultiFocus { return; } const { - stack = [], - smExtext = false, - shift = 0 - } = selectedMulti || {}; - const hasValidExtent = extent => extent && Number.isFinite(extent.xL) && Number.isFinite(extent.xU); - const mpys = stack.filter(m => hasValidExtent(m?.xExtent)); + stack, + smExtext, + shift + } = selectedMulti; + const mpys = stack; const isDisable = _cfg.default.btnCmdMpy(this.layout); - if (mpys.length === 0 || isDisable) return; - const activeExtent = hasValidExtent(smExtext) ? smExtext : mpys[0].xExtent; + if (mpys === 0 || isDisable) return; // rescale for zoom const { xt @@ -770,8 +765,7 @@ class MultiFocus { peaks, xExtent } = m; - const safePeaks = Array.isArray(peaks) ? peaks : []; - return safePeaks.filter(p => Number.isFinite(p?.x) && Number.isFinite(p?.y)).map(p => Object.assign({}, p, { + return peaks.map(p => Object.assign({}, p, { xExtent })); }); @@ -786,7 +780,7 @@ class MultiFocus { xL, xU } = d.xExtent; - return activeExtent.xL === xL && activeExtent.xU === xU ? 'purple' : '#DA70D6'; + 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'); @@ -890,17 +884,11 @@ class MultiFocus { editPeakSt, layoutSt, sweepExtentSt, - isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, - integrationSt, - mtplySt, - uiSt + integationSt, + mtplySt }) { - this.uiSt = uiSt; - this.graphIndex = uiSt?.zoom?.graphIndex; this.svg = d3.select(this.rootKlass).select('.d3Svg'); (0, _mount.MountMainFrame)(this, 'focus'); (0, _mount.MountClip)(this); @@ -914,11 +902,6 @@ class MultiFocus { this.scales = (0, _init.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(); (0, _compass.MountCompass)(this); this.axis = (0, _mount.MountAxis)(this); this.path = (0, _mount.MountPath)(this, this.pathColor); @@ -937,10 +920,10 @@ class MultiFocus { this.drawPeaks(editPeakSt); this.drawRef(); this.drawPeckers(); - this.drawInteg(integrationSt); + this.drawInteg(integationSt); this.drawMtply(mtplySt); } - (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt); + (0, _brush.default)(this, false, isUiNoBrushSt); this.resetShouldUpdate(editPeakSt); } update({ @@ -953,19 +936,13 @@ class MultiFocus { editPeakSt, layoutSt, sweepExtentSt, - isUiAddIntgSt, - isUiSplitIntgSt, - isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, - integrationSt, - mtplySt, - uiSt + integationSt, + mtplySt }) { - this.uiSt = uiSt; this.root = d3.select(this.rootKlass).selectAll('.focus-main'); this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt)); - this.graphIndex = uiSt?.zoom?.graphIndex; const { curveIdx, isShowAllCurve @@ -974,11 +951,6 @@ class MultiFocus { this.isShowAllCurves = isShowAllCurve; 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); this.getShouldUpdate(editPeakSt); @@ -989,10 +961,10 @@ class MultiFocus { this.drawPeaks(editPeakSt); this.drawRef(); this.drawPeckers(); - this.drawInteg(integrationSt); + this.drawInteg(integationSt); this.drawMtply(mtplySt); } - (0, _brush.default)(this, false, isUiNoBrushSt, this.uiSt, this.graphIndex); + (0, _brush.default)(this, false, isUiNoBrushSt); this.resetShouldUpdate(editPeakSt); } } diff --git a/dist/components/d3_rect/index.js b/dist/components/d3_rect/index.js index d20f50a0..8c537de3 100644 --- a/dist/components/d3_rect/index.js +++ b/dist/components/d3_rect/index.js @@ -50,7 +50,6 @@ class ViewerRect extends _react.default.Component { tTrEndPts, tSfPeaks, isHidden, - decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, @@ -66,7 +65,6 @@ class ViewerRect extends _react.default.Component { filterPeak, tTrEndPts, tSfPeaks, - decimal: decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -81,7 +79,6 @@ class ViewerRect extends _react.default.Component { tTrEndPts, tSfPeaks, isHidden, - decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -94,7 +91,6 @@ class ViewerRect extends _react.default.Component { filterPeak, tTrEndPts, tSfPeaks, - decimal: decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -123,7 +119,6 @@ class ViewerRect extends _react.default.Component { const mapStateToProps = (state, props) => ({ seed: (0, _chem.Topic2Seed)(state, props), peak: (0, _chem.Feature2Peak)(state, props), - decimalSt: state.submit.decimal, tTrEndPts: (0, _chem.ToThresEndPts)(state, props), tSfPeaks: (0, _chem.ToShiftPeaks)(state, props), sweepExtentSt: state.ui.sweepExtent, @@ -139,7 +134,6 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ ViewerRect.propTypes = { seed: _propTypes.default.array.isRequired, peak: _propTypes.default.array.isRequired, - decimalSt: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired, cLabel: _propTypes.default.string.isRequired, xLabel: _propTypes.default.string.isRequired, yLabel: _propTypes.default.string.isRequired, diff --git a/dist/components/d3_rect/rect_focus.js b/dist/components/d3_rect/rect_focus.js index 2a42ac1b..bc58f31e 100644 --- a/dist/components/d3_rect/rect_focus.js +++ b/dist/components/d3_rect/rect_focus.js @@ -11,7 +11,6 @@ var _mount = require("../../helpers/mount"); var _compass = require("../../helpers/compass"); var _converter = require("../../helpers/converter"); var _list_layout = require("../../constants/list_layout"); -var _format = _interopRequireDefault(require("../../helpers/format")); const d3 = require('d3'); class RectFocus { constructor(props) { @@ -54,7 +53,6 @@ class RectFocus { this.factor = 0.125; this.currentExtent = null; this.layout = _list_layout.LIST_LAYOUT.MS; - this.decimal = 3; this.setTip = this.setTip.bind(this); this.setDataParams = this.setDataParams.bind(this); this.create = this.create.bind(this); @@ -70,14 +68,11 @@ class RectFocus { this.tip = (0, _init.InitTip)(); this.root.call(this.tip); } - setDataParams(data, peaks, tTrEndPts, tSfPeaks, decimal) { + setDataParams(data, peaks, tTrEndPts, tSfPeaks) { this.data = [...data]; this.dataPks = [...peaks]; this.tTrEndPts = tTrEndPts; this.tSfPeaks = tSfPeaks; - if (decimal !== undefined) { - this.decimal = _format.default.clampDecimalPlaces(decimal); - } } updatePathCall(xt, yt) { this.pathCall = d3.line().x(d => xt(d.x)).y(d => yt(d.y)); @@ -136,7 +131,6 @@ class RectFocus { } = (0, _compass.TfRescale)(this); this.updatePathCall(xt, yt); const yRef = this.tTrEndPts[0].y; - const msMaxY = d3.max(this.data, row => row.y) || 0; const bars = this.bars.selectAll('rect').data(this.data); bars.exit().attr('class', 'exit').remove(); const gnd = yt(0); @@ -145,9 +139,7 @@ class RectFocus { d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'blue'); const tipParams = { d, - layout: this.layout, - msMaxY, - xDigits: this.decimal + layout: this.layout }; this.tip.show(tipParams, event.target); }).on('mouseout', (event, d) => { @@ -155,9 +147,7 @@ class RectFocus { d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'red'); const tipParams = { d, - layout: this.layout, - msMaxY, - xDigits: this.decimal + layout: this.layout }; this.tip.hide(tipParams, event.target); }); @@ -184,7 +174,6 @@ class RectFocus { filterPeak, tTrEndPts, tSfPeaks, - decimal, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -194,7 +183,7 @@ class RectFocus { (0, _mount.MountClip)(this); this.root = d3.select(this.rootKlass).selectAll('.focus-main'); this.setTip(); - this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, decimal); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks); (0, _compass.MountCompass)(this); this.axis = (0, _mount.MountAxis)(this); [this.thresLine] = (0, _mount.MountThresLine)(this, 'green'); @@ -216,13 +205,12 @@ class RectFocus { filterPeak, tTrEndPts, tSfPeaks, - decimal, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt }) { this.root = d3.select(this.rootKlass).selectAll('.focus-main'); - this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, decimal); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks); if (this.data && this.data.length > 0) { this.setConfig(sweepExtentSt); this.drawBar(); diff --git a/dist/components/multi_jcamps_viewer.js b/dist/components/multi_jcamps_viewer.js index 0cd897f7..68e39783 100644 --- a/dist/components/multi_jcamps_viewer.js +++ b/dist/components/multi_jcamps_viewer.js @@ -97,9 +97,7 @@ class MultiJcampsViewer extends _react.default.Component { integrationSt, descriptions, canChangeDescription, - onDescriptionChanged, - forecast, - editorOnly + onDescriptionChanged } = this.props; if (!entities || entities.length === 0) return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {}); const separateCondition = _format.default.isGCLayout(layoutSt) ? 'yUnit' : 'xUnit'; @@ -116,19 +114,14 @@ class MultiJcampsViewer extends _react.default.Component { integrations } = integrationSt; const currentIntegration = integrations[curveIdx]; - const hasEdit = !!feature?.data?.[0]?.x?.length; - const xLabel = feature?.xUnit || ''; - const yLabel = feature?.yUnit || ''; const isCyclicVolta = _format.default.isCyclicVoltaLayout(layoutSt); return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: classes.root, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.default, { feature: feature, - hasEdit: hasEdit, - forecast: forecast || {}, + hasEdit: entity.hasEdit, operations: operations, - editorOnly: editorOnly, - hideThreshold: !_format.default.isNmrLayout(layoutSt) + editorOnly: true }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: (0, _classnames.default)('react-spectrum-editor', isCyclicVolta && classes.cvEditor), children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Grid.default, { @@ -143,8 +136,8 @@ class MultiJcampsViewer extends _react.default.Component { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.default, { entities: entities, topic: topic, - xLabel: xLabel, - yLabel: yLabel, + xLabel: feature.xUnit, + yLabel: feature.yUnit, feature: feature }) }), isCyclicVolta ? /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { @@ -169,7 +162,6 @@ class MultiJcampsViewer extends _react.default.Component { subLayoutsInfo: seperatedSubLayouts, integration: currentIntegration, descriptions: descriptions, - editorOnly: editorOnly, canChangeDescription: canChangeDescription, onDescriptionChanged: onDescriptionChanged, hideCyclicVolta: isCyclicVolta @@ -207,9 +199,7 @@ MultiJcampsViewer.propTypes = { addNewCylicVoltaPairPeakAct: _propTypes.default.func.isRequired, addCylicVoltaMaxPeakAct: _propTypes.default.func.isRequired, addCylicVoltaMinPeakAct: _propTypes.default.func.isRequired, - operations: _propTypes.default.array.isRequired, - forecast: _propTypes.default.object, - editorOnly: _propTypes.default.bool, + operations: _propTypes.default.func.isRequired, userManualLink: _propTypes.default.object, entities: _propTypes.default.array, layoutSt: _propTypes.default.string.isRequired, @@ -227,8 +217,6 @@ MultiJcampsViewer.defaultProps = { xLabel: '', yLabel: '', entities: [], - forecast: {}, - editorOnly: false, descriptions: [], canChangeDescription: false }; diff --git a/dist/components/panel/compare.js b/dist/components/panel/compare.js index 82949ccc..391903d6 100644 --- a/dist/components/panel/compare.js +++ b/dist/components/panel/compare.js @@ -10,6 +10,7 @@ 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")); @@ -129,35 +130,38 @@ const content = (classes, desc) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.T children: desc }) }); -const inputOthers = (classes, desc, onDropFiles, onFileChange, inputRef) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { - className: (0, _classnames.default)(classes.baseDD), - role: "button", - tabIndex: 0, - onClick: () => inputRef.current?.click(), - onKeyDown: event => { - if (event.key === 'Enter' || event.key === ' ') { - event.preventDefault(); - inputRef.current?.click(); - } - }, - onDragOver: event => { - event.preventDefault(); - }, - onDrop: event => { - event.preventDefault(); - onDropFiles(event.dataTransfer?.files); - }, - children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("input", { - ref: inputRef, - type: "file", - multiple: true, - accept: ".dx,.jdx,.jcamp,.JCAMP", - style: { - display: 'none' - }, - onChange: onFileChange - }), content(classes, 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, @@ -217,63 +221,37 @@ const ComparePanel = ({ jcampSt, rmOthersOneAct, toggleShowAct -}) => { - const inputRef = _react.default.useRef(null); - const { - selectedIdx, - jcamps - } = jcampSt; - const selectedJcamp = jcamps[selectedIdx]; - const { - addOthersCb - } = selectedJcamp; - const desc = msgDefault; - const onDropFiles = filesLike => { - if (!addOthersCb) return; - const droppedFiles = Array.from(filesLike || []); - if (droppedFiles.length === 0) return; - addOthersCb({ - jcamps: droppedFiles - }); - }; - const onFileChange = event => { - onDropFiles(event.target.files); - if (inputRef.current) { - inputRef.current.value = ''; - } - }; - return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, { - expanded: expand, - onChange: onExapnd, - disableGutters: true, - sx: { - '&.MuiAccordion-root.Mui-expanded': { - margin: 0 - }, - '&:before': { - display: 'none' - } +}) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, { + expanded: expand, + onChange: onExapnd, + disableGutters: true, + sx: { + '&.MuiAccordion-root.Mui-expanded': { + margin: 0 }, - 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" - }) + '&: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, desc, onDropFiles, onFileChange, inputRef), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: (0, _classnames.default)(classes.panelDetail), - children: compareList(classes, jcampSt, rmOthersOneAct, toggleShowAct) - })] - }); -}; + }) + }), /*#__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 { diff --git a/dist/components/panel/cyclic_voltamery_data.js b/dist/components/panel/cyclic_voltamery_data.js index 96718fd8..9024bda0 100644 --- a/dist/components/panel/cyclic_voltamery_data.js +++ b/dist/components/panel/cyclic_voltamery_data.js @@ -146,7 +146,7 @@ const styles = () => ({ }); const CyclicVoltammetryPanel = ({ classes, - cyclicVoltaState, + cyclicVotaSt, feature, addNewPairPeakAct, setWorkWithMaxPeakAct, @@ -161,18 +161,18 @@ const CyclicVoltammetryPanel = ({ const [isExpanded, setIsExpanded] = (0, _react.useState)(false); const { spectraList - } = cyclicVoltaState; + } = cyclicVotaSt; const spectra = spectraList[jcampIdx]; let list = []; if (spectra !== undefined) { list = spectra.list; } - const formatCurrent = (y, feature, cyclicVoltaState) => { + const formatCurrent = (y, feature, cyclicVotaSt) => { const baseY = feature && feature.yUnit ? String(feature.yUnit) : 'A'; const isMilli = /mA/i.test(baseY); - const useDensity = cyclicVoltaState && cyclicVoltaState.useCurrentDensity; - const rawArea = (cyclicVoltaState && cyclicVoltaState.areaValue === '' ? 1.0 : cyclicVoltaState?.areaValue) || 1.0; - const areaUnit = cyclicVoltaState && cyclicVoltaState.areaUnit ? cyclicVoltaState.areaUnit : 'cm²'; + 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'; @@ -226,9 +226,9 @@ const CyclicVoltammetryPanel = ({ }; 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, cyclicVoltaState)}` : 'nd', - min: o.min ? `E: ${_format.default.strNumberFixedLength(parseFloat(o.min.x), 3)} V,\nI: ${formatCurrent(o.min.y, feature, cyclicVoltaState)}` : 'nd', - pecker: o.pecker ? `${formatCurrent(o.pecker.y, feature, cyclicVoltaState)}` : 'nd', + 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', @@ -262,7 +262,7 @@ const CyclicVoltammetryPanel = ({ className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'), children: "Voltammetry data" }), ' - ', /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { - children: ["Mode: ", cyclicVoltaState.useCurrentDensity ? 'Current Density' : 'Current'] + 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." @@ -436,7 +436,7 @@ const CyclicVoltammetryPanel = ({ const mapStateToProps = (state, props) => ( // eslint-disable-line { - cyclicVoltaState: state.cyclicvolta, + cyclicVotaSt: state.cyclicvolta, sweepTypeSt: state.ui.sweepType }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ @@ -450,7 +450,7 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ CyclicVoltammetryPanel.propTypes = { classes: _propTypes.default.object.isRequired, feature: _propTypes.default.object.isRequired, - cyclicVoltaState: _propTypes.default.object.isRequired, + cyclicVotaSt: _propTypes.default.object.isRequired, addNewPairPeakAct: _propTypes.default.func.isRequired, setWorkWithMaxPeakAct: _propTypes.default.func.isRequired, selectPairPeakAct: _propTypes.default.func.isRequired, diff --git a/dist/components/panel/graph_selection.js b/dist/components/panel/graph_selection.js index ad38202d..5ab8adf3 100644 --- a/dist/components/panel/graph_selection.js +++ b/dist/components/panel/graph_selection.js @@ -63,12 +63,10 @@ const GraphSelectionPanel = ({ if (subLayoutsInfo) { subLayoutValues = Object.keys(subLayoutsInfo); } - const subLayoutKey = subLayoutValues.join('|'); const [selectedSubLayout, setSelectedSublayout] = (0, _react.useState)(subLayoutValues[0]); - const resolvedSelectedSubLayout = subLayoutValues.includes(selectedSubLayout) ? selectedSubLayout : subLayoutValues[0] || false; (0, _react.useEffect)(() => { setSelectedSublayout(subLayoutValues[0]); - }, [subLayoutKey]); + }, subLayoutValues); if (!curveSt) { return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {}); } @@ -91,23 +89,27 @@ const GraphSelectionPanel = ({ }; let itemsSubLayout = []; if (selectedSubLayout && subLayoutValues.length > 1) { - const subLayout = subLayoutsInfo?.[resolvedSelectedSubLayout]; - itemsSubLayout = Array.isArray(subLayout) ? 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 - }; - }) : []; + 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 { @@ -142,7 +144,7 @@ const GraphSelectionPanel = ({ className: "txt-panel-header", children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'), - children: "Graph selections" + children: "Graph selection" }) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), layoutSt === _list_layout.LIST_LAYOUT.AIF ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControlLabel, { @@ -153,9 +155,9 @@ const GraphSelectionPanel = ({ label: "Show all curves" }) : null, subLayoutValues && subLayoutValues.length > 1 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tabs, { - value: resolvedSelectedSubLayout, + value: selectedSubLayout, onChange: onChangeTabSubLayout, - children: subLayoutValues.map(subLayout => { + children: subLayoutValues.map((subLayout, i) => { let subLayoutName = ''; switch (subLayout.toUpperCase()) { case 'G/MOL': @@ -176,7 +178,7 @@ const GraphSelectionPanel = ({ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tab, { value: subLayout, label: subLayoutName - }, subLayout); + }, i); }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.List, { children: itemsSubLayout.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.ListItem, { @@ -246,17 +248,13 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ }, dispatch); GraphSelectionPanel.propTypes = { classes: _propTypes.default.object.isRequired, - expand: _propTypes.default.bool, + expand: _propTypes.default.bool.isRequired, layoutSt: _propTypes.default.string.isRequired, - onExapnd: _propTypes.default.func, - onExpand: _propTypes.default.func, + onExapnd: _propTypes.default.func.isRequired, curveSt: _propTypes.default.object.isRequired, selectCurveAct: _propTypes.default.func.isRequired, - entityFileNames: _propTypes.default.array, - subLayoutsInfo: _propTypes.default.object, + entityFileNames: _propTypes.default.array.isRequired, + subLayoutsInfo: _propTypes.default.array, toggleShowAllCurveAct: _propTypes.default.func.isRequired }; -GraphSelectionPanel.defaultProps = { - entityFileNames: [] -}; 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 index 80bc732a..66cbcca9 100644 --- a/dist/components/panel/index.js +++ b/dist/components/panel/index.js @@ -9,6 +9,7 @@ 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")); @@ -18,9 +19,8 @@ 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 _format = _interopRequireDefault(require("../../helpers/format")); var _jsxRuntime = require("react/jsx-runtime"); -/* eslint-disable react/prop-types, react/require-default-props, max-len */ +/* eslint-disable react/prop-types, react/require-default-props */ const theme = (0, _styles.createTheme)({ typography: { @@ -50,7 +50,7 @@ class PanelViewer extends _react.default.Component { this.state = { expand: 'info' }; - this.onToggleExpand = this.onToggleExpand.bind(this); + this.onExapnd = this.onExapnd.bind(this); this.handleDescriptionChanged = this.handleDescriptionChanged.bind(this); } handleDescriptionChanged(content, delta, source, editor) { @@ -59,7 +59,7 @@ class PanelViewer extends _react.default.Component { this.props.onDescriptionChanged(contentChanged); // eslint-disable-line } } - onToggleExpand(input) { + onExapnd(input) { const { expand } = this.state; @@ -87,20 +87,18 @@ class PanelViewer extends _react.default.Component { userManualLink, subLayoutsInfo, exactMass, - entities, hideCyclicVolta } = this.props; - const onExpandInfo = () => this.onToggleExpand('info'); - const onExpandPeak = () => this.onToggleExpand('peak'); - const onExpandMpy = () => this.onToggleExpand('mpy'); - const onExpandCompare = () => this.onToggleExpand('compare'); - const onExpandCyclicVolta = () => this.onToggleExpand('cyclicvolta'); - const onExpandGraphSelection = () => this.onToggleExpand('graph'); + 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 curveCount = Array.isArray(listCurves) ? listCurves.length : 0; - const hideGraphSelection = curveCount <= 1 || _format.default.isLCMsLayout(layoutSt); + 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, { @@ -111,34 +109,33 @@ class PanelViewer extends _react.default.Component { jcampIdx: jcampIdx, entityFileNames: entityFileNames, expand: expand === 'graph', - onExpand: onExpandGraphSelection, + onExapnd: onExapndGraphSelection, subLayoutsInfo: subLayoutsInfo }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_info.default, { - entities: entities, feature: feature, integration: integration, editorOnly: editorOnly, expand: expand === 'info', molSvg: molSvg, exactMass: exactMass, - onExpand: onExpandInfo, + onExapnd: onExapndInfo, descriptions: descriptions, canChangeDescription: canChangeDescription, onDescriptionChanged: this.handleDescriptionChanged }), _cfg.default.hidePanelPeak(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_peaks.default, { expand: expand === 'peak', - onExapnd: onExpandPeak + onExapnd: onExapndPeak }), _cfg.default.hidePanelMpy(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, { expand: expand === 'mpy', - onExapnd: onExpandMpy - }), _cfg.default.hidePanelCompare(layoutSt) || curveCount > 1 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_compare.default, { + onExapnd: onExapndMpy + }), _cfg.default.hidePanelCompare(layoutSt) || listCurves.length > 1 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_compare.default, { expand: expand === 'compare', - onExapnd: onExpandCompare + onExapnd: onExapndCompare }), _cfg.default.hidePanelCyclicVolta(layoutSt) || hideCyclicVolta ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_cyclic_voltamery_data.default, { jcampIdx: jcampIdx, feature: feature, expand: expand === 'cyclicvolta', - onExapnd: onExpandCyclicVolta, + onExapnd: onExapndCyclicVolta, userManualLink: userManualLink ? userManualLink.cv : undefined })] }) @@ -152,10 +149,11 @@ const mapStateToProps = (state, _) => ( 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, + integration: _propTypes.default.object.isRequired, editorOnly: _propTypes.default.bool.isRequired, molSvg: _propTypes.default.string.isRequired, descriptions: _propTypes.default.array.isRequired, @@ -167,12 +165,8 @@ PanelViewer.propTypes = { curveSt: _propTypes.default.object.isRequired, subLayoutsInfo: _propTypes.default.object, exactMass: _propTypes.default.string, - hideCyclicVolta: _propTypes.default.bool, - entities: _propTypes.default.array -}; -PanelViewer.defaultProps = { - integration: {} + hideCyclicVolta: _propTypes.default.bool }; var _default = exports.default = (0, _reactRedux.connect)( // eslint-disable-line -mapStateToProps, null)((0, _withStyles.default)(styles)(PanelViewer)); // eslint-disable-line \ No newline at end of file +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 index 7e3e96bf..72928355 100644 --- a/dist/components/panel/info.js +++ b/dist/components/panel/info.js @@ -21,7 +21,6 @@ var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable no-mixed-operators, react/function-component-definition, react/require-default-props, max-len */ -const ELECTRON_MASS = 0.000548579909065; const styles = () => ({ chip: { margin: '1px 0 1px 0' @@ -75,16 +74,11 @@ const styles = () => ({ }, rowOddSim: { backgroundColor: '#fff', - height: 'auto', - minHeight: 36, + height: 108, lineHeight: '24px', - overflow: 'visible', + overflowY: 'hidden', overflowWrap: 'word-break' }, - simPlaceholder: { - color: 'rgba(0, 0, 0, 0.54)', - fontStyle: 'italic' - }, tHead: { fontWeight: 'bold', float: 'left', @@ -117,21 +111,12 @@ const styles = () => ({ } }); const simTitle = () => 'Simulated signals from NMRshiftDB'; -const simContent = nmrSimPeaks => { - if (!Array.isArray(nmrSimPeaks) || nmrSimPeaks.length === 0) return ''; - return [...nmrSimPeaks].sort((a, b) => a - b).join(', '); -}; -const simPlaceholder = () => 'No simulated signals available.'; +const simContent = nmrSimPeaks => nmrSimPeaks && nmrSimPeaks.sort((a, b) => a - b).join(', '); const normalizeQuillValue = val => { if (!val) return ''; if (val === '


' || val === '

') return ''; return val; }; -const formatMsExactMass = exactMass => { - const neutralMass = parseFloat(exactMass); - if (Number.isNaN(neutralMass)) return null; - return (neutralMass - ELECTRON_MASS).toFixed(6); -}; const chemSubStyle = { fontSize: '0.85em', position: 'relative', @@ -165,9 +150,12 @@ const handleDescriptionChanged = (content, delta, source, editor, onDescriptionC if (!onDescriptionChanged) return; onDescriptionChanged(normalizeQuillValue(content), delta, source, editor); }; -const aucValue = (integration, hplcMsSt) => { +const aucValue = integration => { + if (!integration) { + return ''; + } const values = []; - const stackIntegration = integration?.stack; + const stackIntegration = integration.stack; if (Array.isArray(stackIntegration)) { let sumVal = 0.0; stackIntegration.forEach(inte => { @@ -185,23 +173,7 @@ const aucValue = (integration, hplcMsSt) => { } }); } - const spectraList = hplcMsSt?.uvvis?.spectraList || []; - const listWaveLength = hplcMsSt?.uvvis?.listWaveLength || []; - spectraList.forEach((spectrum, idx) => { - const wavelength = listWaveLength[idx]; - const integrations = spectrum?.integrations || []; - if (integrations.length > 0) { - const sumArea = integrations.reduce((sum, integ) => sum + (integ.absoluteArea ?? integ.area ?? 0), 0); - const integrationStrings = integrations.map(integ => { - const rawArea = integ.absoluteArea ?? integ.area ?? 0; - const areaVal = rawArea.toFixed(2); - const percent = sumArea > 0 ? (rawArea * 100 / sumArea).toFixed(2) : '0.00'; - return `${areaVal} (${percent}%)`; - }); - values.push(`[${wavelength} nm]: ${integrationStrings.join(', ')}`); - } - }); - return values.join('\n'); + return values.join(', '); }; const SECData = ({ classes, @@ -270,11 +242,8 @@ const SECData = ({ SECData.propTypes = { classes: _propTypes.default.object.isRequired, layout: _propTypes.default.string.isRequired, - detector: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]), - secData: _propTypes.default.object -}; -SECData.defaultProps = { - detector: '' + detector: _propTypes.default.object.isRequired, + secData: _propTypes.default.object.isRequired }; const DSCData = ({ classes, @@ -332,7 +301,7 @@ const DSCData = ({ DSCData.propTypes = { classes: _propTypes.default.object.isRequired, layout: _propTypes.default.string.isRequired, - dscMetaData: _propTypes.default.object, + dscMetaData: _propTypes.default.object.isRequired, updateAction: _propTypes.default.func.isRequired }; const InfoPanel = ({ @@ -348,17 +317,14 @@ const InfoPanel = ({ shiftSt, curveSt, exactMass, - onExpand, + onExapnd, canChangeDescription, onDescriptionChanged, detectorSt, metaSt, - updateDSCMetaDataAct, - hplcMsSt, - entities + updateDSCMetaDataAct }) => { if (!feature) return null; - const msExactMass = _format.default.isMsLayout(layoutSt) && exactMass ? formatMsExactMass(exactMass) : null; const { title, observeFrequency, @@ -372,14 +338,11 @@ const InfoPanel = ({ curveIdx } = curveSt; const { - curves = [] - } = detectorSt || {}; - const currentEntity = Array.isArray(entities) ? entities[curveIdx] : null; - const entityTitle = currentEntity?.entity?.title || currentEntity?.title || currentEntity?.spectra?.[0]?.title || currentEntity?.entity?.spectra?.[0]?.title || ''; - const displayTitle = title || entityTitle; + curves + } = detectorSt; const getSelectedDetectorForCurve = (_detectorSt, targetCurveIdx) => { const targetCurve = curves.find(curve => curve.curveIdx === targetCurveIdx); - return targetCurve?.selectedDetector?.name || ''; + return targetCurve ? targetCurve.selectedDetector.name : ''; }; let selectedDetector = getSelectedDetectorForCurve(detectorSt, curveIdx); @@ -400,11 +363,10 @@ const InfoPanel = ({ if (integration) { originStack = integration.originStack; // eslint-disable-line } - const simulatedSignals = simContent(simulationSt.nmrSimPeaks); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, { "data-testid": "PanelInfo", expanded: expand, - onChange: onExpand, + onChange: onExapnd, disableGutters: true, sx: { '&.MuiAccordion-root.Mui-expanded': { @@ -437,7 +399,7 @@ const InfoPanel = ({ children: "Title : " }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'), - children: displayTitle + children: title })] }), _format.default.isNmrLayout(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: (0, _classnames.default)(classes.rowRoot, classes.rowEven), @@ -457,14 +419,14 @@ const InfoPanel = ({ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'), children: renderReadableSubscript(showSolvName) })] - }) : null, msExactMass ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { + }) : 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 (M+): " + children: "Exact mass: " }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'), - children: `${msExactMass} g/mol` + children: `${parseFloat(exactMass).toFixed(6)} g/mol` })] }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(SECData, { classes: classes, @@ -513,30 +475,12 @@ const InfoPanel = ({ }), /*#__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, !simulatedSignals && classes.simPlaceholder, 'txt-sv-panel-txt'), - children: simulatedSignals || simPlaceholder() + className: (0, _classnames.default)(classes.tTxt, classes.tTxtSim, 'txt-sv-panel-txt'), + children: simContent(simulationSt.nmrSimPeaks) }) })] }) : null] - }), _format.default.isLCMsLayout(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)("div", { - className: (0, _classnames.default)(classes.tTxt, classes.tTxtSim, 'txt-sv-panel-txt'), - style: { - maxHeight: '80px', - overflowY: 'auto', - overflowX: 'hidden', - wordBreak: 'break-word', - marginBottom: '100px' - }, - children: aucValue(integration, hplcMsSt).split('\n').map((line, idx) => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - children: line - }, idx)) - })] - }) : null] + })] }); }; const mapStateToProps = (state, props) => ( @@ -547,8 +491,7 @@ const mapStateToProps = (state, props) => ( shiftSt: state.shift, curveSt: state.curve, detectorSt: state.detector, - metaSt: state.meta, - hplcMsSt: state.hplcMs + metaSt: state.meta }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ updateDSCMetaDataAct: _meta.updateDSCMetaData @@ -556,24 +499,22 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ InfoPanel.propTypes = { classes: _propTypes.default.object.isRequired, expand: _propTypes.default.bool.isRequired, - feature: _propTypes.default.object, - integration: _propTypes.default.object, + 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.object.isRequired, + simulationSt: _propTypes.default.array.isRequired, shiftSt: _propTypes.default.object.isRequired, curveSt: _propTypes.default.object.isRequired, - onExpand: _propTypes.default.func, + 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, - hplcMsSt: _propTypes.default.object.isRequired, - entities: _propTypes.default.array + updateDSCMetaDataAct: _propTypes.default.func.isRequired }; var _default = exports.default = (0, _reactRedux.connect)( // eslint-disable-line diff --git a/dist/constants/action_type.js b/dist/constants/action_type.js index ba7e4384..cee58bf1 100644 --- a/dist/constants/action_type.js +++ b/dist/constants/action_type.js @@ -3,7 +3,7 @@ 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.HPLC_MS = exports.FORECAST = exports.EDITPEAK = exports.CYCLIC_VOLTA_METRY = exports.CURVE = exports.AXES = void 0; +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', @@ -56,7 +56,6 @@ const UI = exports.UI = { SET_TYPE: 'UI_SWEEP_SET_TYPE', SELECT: 'UI_SWEEP_SELECT', SELECT_ZOOMIN: 'UI_SWEEP_SELECT_ZOOMIN', - SELECT_ZOOMIN_SUBVIEW: 'UI_SWEEP_SELECT_ZOOMIN', SELECT_ZOOMRESET: 'UI_SWEEP_SELECT_ZOOMRESET', SELECT_INTEGRATION: 'UI_SWEEP_SELECT_INTEGRATION', SELECT_MULTIPLICITY: 'UI_SWEEP_SELECT_MULTIPLICITY', @@ -64,9 +63,6 @@ const UI = exports.UI = { }, WHEEL: { SCROLL: 'UI_WHEEL_SCROLL' - }, - SUB_VIEWER: { - DISPLAY_VIEWER_AT: 'DISPLAY_VIEWER_AT' } }; const FORECAST = exports.FORECAST = { @@ -87,10 +83,7 @@ const INTEGRATION = exports.INTEGRATION = { SET_FKR: 'INTEGRATION_SET_FKR', 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' + SWEEP: 'INTEGRATION_SWEEP' }; const SIMULATION = exports.SIMULATION = { RESET_ALL_RDC: 'SIMULATION_RESET_ALL_RDC' @@ -157,18 +150,4 @@ const AXES = exports.AXES = { }; const SEC = exports.SEC = { UPDATE_DETECTOR: 'UPDATE_DETECTOR' -}; -const HPLC_MS = exports.HPLC_MS = { - SET_LCMS_INTEGRATIONS_EXPORT: 'HPLC_MS_SET_LCMS_INTEGRATIONS_EXPORT', - UPDATE_UVVIS_WAVE_LENGTH: 'UPDATE_UVVIS_WAVE_LENGTH', - SELECT_TIC_CURVE: 'SELECT_TIC_CURVE', - UPDATE_HPLCMS_INTEGRATIONS: 'UPDATE_HPLCMS_INTEGRATIONS', - UPDATE_CURRENT_PAGE_VALUE: 'UPDATE_CURRENT_PAGE_VALUE', - UVVIS_UNDO: 'HPLC_MS_UVVIS_UNDO', - UVVIS_REDO: 'HPLC_MS_UVVIS_REDO', - UPDATE_HPLCMS_PEAKS: 'UPDATE_HPLCMS_PEAKS', - REMOVE_HPLCMS_PEAK: 'REMOVE_HPLCMS_PEAK', - CLEAR_INTEGRATION_ALL_HPLCMS: 'CLEAR_INTEGRATION_ALL_HPLCMS', - CLEAR_ALL_PEAKS_HPLCMS: 'CLEAR_ALL_PEAKS_HPLCMS', - CLEAR_STATE: 'HPLC_MS_CLEAR_STATE' }; \ No newline at end of file diff --git a/dist/constants/list_layout.js b/dist/constants/list_layout.js index 829cb69f..cf5830ed 100644 --- a/dist/constants/list_layout.js +++ b/dist/constants/list_layout.js @@ -27,6 +27,5 @@ const LIST_LAYOUT = exports.LIST_LAYOUT = { DLS_ACF: 'DLS ACF', DLS_INTENSITY: 'DLS intensity', DSC: 'DIFFERENTIAL SCANNING CALORIMETRY', - GC: 'GAS CHROMATOGRAPHY', - LC_MS: 'LC/MS' + GC: 'GAS CHROMATOGRAPHY' }; \ No newline at end of file diff --git a/dist/constants/list_ui.js b/dist/constants/list_ui.js index 6348a679..ad219334 100644 --- a/dist/constants/list_ui.js +++ b/dist/constants/list_ui.js @@ -15,8 +15,6 @@ const LIST_UI_SWEEP_TYPE = exports.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', @@ -32,7 +30,6 @@ const LIST_UI_SWEEP_TYPE = exports.LIST_UI_SWEEP_TYPE = { 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', - PEAK_GROUP_SELECT: 'peak group select' + 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.INTEGRATION_VISUAL_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, LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT]; \ No newline at end of file +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.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/fn.js b/dist/fn.js index 3b4ece75..348a8fe8 100644 --- a/dist/fn.js +++ b/dist/fn.js @@ -10,17 +10,14 @@ var _chem = require("./helpers/chem"); var _converter = require("./helpers/converter"); var _multiplicity_calc = require("./helpers/multiplicity_calc"); var _carbonFeatures = require("./helpers/carbonFeatures"); -var _integration_jcamp = require("./helpers/integration_jcamp"); var _list_layout = require("./constants/list_layout"); /* eslint-disable prefer-object-spread */ const FN = Object.assign({}, _format.default, { ExtractJcamp: _chem.ExtractJcamp, - buildLcmsMsPageJcamp: _chem.buildLcmsMsPageJcamp, ToXY: _converter.ToXY, LIST_LAYOUT: _list_layout.LIST_LAYOUT, CalcMpyCenter: _multiplicity_calc.calcMpyCenter, - CarbonFeatures: _carbonFeatures.carbonFeatures, - serializeIntegrationRecords: _integration_jcamp.serializeIntegrationRecords + 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 index d23a6946..309f49d7 100644 --- a/dist/helpers/brush.js +++ b/dist/helpers/brush.js @@ -1,43 +1,31 @@ "use strict"; -var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); 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"); -var _list_ui = require("../constants/list_ui"); -var _cfg = _interopRequireDefault(require("./cfg")); /* eslint-disable prefer-object-spread */ -// eslint-disable-line import/extensions -// eslint-disable-line import/extensions - const d3 = require('d3'); const wheeled = (focus, event) => { const { currentExtent, - scrollUiWheelAct, - brushClass + 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, - brushClass + direction })); }; -const usesTwoClickIntegAdd = (focus, isUiAddIntgSt) => isUiAddIntgSt && _cfg.default.showIntegSplitTools(focus.layout); -const brushed = (focus, xOnly, event, brushedClass = '.d3Svg') => { +const brushed = (focus, isUiAddIntgSt, event) => { const { selectUiSweepAct, data, dataPks, brush, - brushX, w, h, scales @@ -54,15 +42,7 @@ const brushed = (focus, xOnly, event, brushedClass = '.d3Svg') => { yL: yes[0], yU: yes[1] }; - if (xOnly) { - if (focus.isUiAddIntgSt) { - const payload = (0, _sweep.buildSweepPayloadFromXBounds)(focus, scales.x.invert(selection[0]), scales.x.invert(selection[1])); - selectUiSweepAct(payload); - if (brushX) { - focus.svg.selectAll('.brushX').call(brushX.move, null); - } - return; - } + if (isUiAddIntgSt) { xes = selection.map(scales.x.invert).sort((a, b) => a - b); xExtent = { xL: xes[0], @@ -87,69 +67,34 @@ const brushed = (focus, xOnly, event, brushedClass = '.d3Svg') => { data, dataPks }); - let svgSel = null; - if (focus?.svg && typeof focus.svg.selectAll === 'function') { - svgSel = focus.svg; - } else if (typeof brushedClass === 'string') { - svgSel = d3.select(brushedClass); - } - if (svgSel && typeof svgSel.selectAll === 'function' && !svgSel.empty()) { - const brushSelection = xOnly ? svgSel.selectAll('.brushX') : svgSel.selectAll('.brush'); - if (!brushSelection.empty()) { - if (xOnly && brushX) { - brushSelection.call(brushX.move, null); - } else if (brush) { - brushSelection.call(brush.move, null); - } - } - } + d3.select('.d3Svg').selectAll('.brush').call(brush.move, null); }; -const MountBrush = (focus, isUiAddIntgSt, isUiNoBrushSt, brushedClass = '.d3Svg') => { +const MountBrush = (focus, isUiAddIntgSt, isUiNoBrushSt) => { const { root, svg, brush, brushX, w, - h, - uiSt, - graphIndex + h } = focus; - Object.assign(focus, { - isUiAddIntgSt - }); - const twoClickIntegAdd = usesTwoClickIntegAdd(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); - } - if (!root || !svg || typeof svg.selectAll !== 'function') return; - svg.selectAll('.brush, .brushX').remove(); - const isZoomInSubview = uiSt?.zoom?.sweepTypes?.[graphIndex] === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN; - const isZoomInGlobal = uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN; - const isIntegrationAdd = uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD; - const isMultiplicitySweepAdd = uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_SWEEP_ADD; - const isZoomIn = isZoomInSubview || isZoomInGlobal; - if (graphIndex !== undefined && !(graphIndex === 0 && isIntegrationAdd) && !isZoomIn && !isMultiplicitySweepAdd) return; - const isXAxisOnly = focus?.xOnlyBrush === true; - const xOnly = isUiAddIntgSt || isXAxisOnly && !isZoomIn; - const brushedCb = event => brushed(focus, xOnly, event, brushedClass); + svg.selectAll('.brush').remove(); + svg.selectAll('.brushX').remove(); + const brushedCb = event => brushed(focus, isUiAddIntgSt, event); const wheeledCb = event => wheeled(focus, event); - if (isUiNoBrushSt && !twoClickIntegAdd) { + if (isUiNoBrushSt) { const target = isUiAddIntgSt ? brushX : brush; target.handleSize(10).extent([[0, 0], [w, h]]).on('end', brushedCb); + + // append brush components const klass = isUiAddIntgSt ? 'brushX' : 'brush'; root.append('g').attr('class', klass).on('mousemove', event => (0, _compass.MouseMove)(event, focus)).call(target); } svg.on('wheel', wheeledCb); }; -var _default = exports.default = MountBrush; \ No newline at end of file +var _default = exports.default = MountBrush; // const resetedCb = () => reseted(main); +// main.svg.on('dblclick', resetedCb); +// const reseted = (main) => { +// const { selectUiSweepAct } = main; +// selectUiSweepAct({ xExtent: false, yExtent: false }); +// }; \ No newline at end of file diff --git a/dist/helpers/calc.js b/dist/helpers/calc.js index ed9fe07a..664ffdf8 100644 --- a/dist/helpers/calc.js +++ b/dist/helpers/calc.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.findClosest = exports.calcSlope = exports.almostEqual = void 0; +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) => { @@ -12,6 +12,4 @@ const calcSlope = (x1, y1, x2, y2) => { } return (y2 - y1) / (x2 - x1); }; -exports.calcSlope = calcSlope; -const findClosest = (arr, target) => arr.reduce((prev, curr) => Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev); // eslint-disable-line -exports.findClosest = findClosest; \ No newline at end of file +exports.calcSlope = calcSlope; \ No newline at end of file diff --git a/dist/helpers/cfg.js b/dist/helpers/cfg.js index b8754dcc..4cc3b51c 100644 --- a/dist/helpers/cfg.js +++ b/dist/helpers/cfg.js @@ -6,14 +6,14 @@ Object.defineProperty(exports, "__esModule", { }); exports.default = void 0; var _format = _interopRequireDefault(require("./format")); -const btnCmdAnaViewer = layoutSt => _format.default.isMsLayout(layoutSt) || _format.default.isLCMsLayout(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 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); -const btnCmdIntg = layoutSt => !(_format.default.isNmrLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt) || _format.default.isLCMsLayout(layoutSt)); // eslint-disable-line +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 showIntegSplitTools = layoutSt => _format.default.isHplcUvVisLayout(layoutSt); const btnCmdMpy = layoutSt => !_format.default.isNmrLayout(layoutSt); const btnCmdMpyPeak = (layoutSt, mpySt, curveIdx = 0) => { const { @@ -50,7 +50,6 @@ const Config = { btnCmdRmPeak, btnCmdSetRef, btnCmdIntg, - showIntegSplitTools, btnCmdMpy, btnCmdMpyPeak, hideCmdThres, diff --git a/dist/helpers/chem.js b/dist/helpers/chem.js index d0033614..65dd81ef 100644 --- a/dist/helpers/chem.js +++ b/dist/helpers/chem.js @@ -4,27 +4,19 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildIntegFeature = 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; -Object.defineProperty(exports, "buildLcmsMsPageJcamp", { - enumerable: true, - get: function get() { - return _parsing.buildLcmsMsPageJcamp; - } -}); -exports.convertTopic = exports.convertThresEndPts = void 0; +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"); -var _parsing = require("../features/lc-ms/parsing"); /* eslint-disable no-mixed-operators, react/function-component-definition, prefer-object-spread, camelcase, no-plusplus, prefer-destructuring, max-len */ -const canIntegrate = layoutSt => !(_format.default.isNmrLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt) || _format.default.isLCMsLayout(layoutSt)); const getTopic = (_, props) => props.topic; const getFeature = (_, props) => props.feature; const getLayout = (state, _) => state.layout; // eslint-disable-line @@ -112,13 +104,12 @@ const calcXY = (xs, ys, maxY, offset) => { return sp; }; const convertTopic = (topic, layout, feature, offset) => { - if (!feature || !topic) return []; const { maxY - } = feature || {}; - const xs = topic.x || []; - const ys = topic.y || []; - const isItgDisable = canIntegrate(layout); + } = 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); }; @@ -163,7 +154,7 @@ const convertComparisons = (layout, comparisons, feature) => { }; const GetComparisons = exports.GetComparisons = (0, _reselect.createSelector)(getLayout, getOthers, getFeature, convertComparisons); const convertFrequency = (layout, feature) => { - if (!_format.default.isNmrLayout(layout)) return false; + if (['1H', '13C', '19F', '31P', '15N', '29Si'].indexOf(layout) < 0) return false; const { observeFrequency } = feature; @@ -173,27 +164,6 @@ const convertFrequency = (layout, feature) => { 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) => { - if (feature?.operation?.layout === 'LC/MS') { - const data = feature.data[0]; - if (!data) return []; - const { - x, - y - } = data; - const peaks = []; - const maxIntensity = Math.max(...y); - const thresholdValue = threshold || 0; - for (let i = 1; i < y.length - 1; i++) { - const intensity = y[i] / maxIntensity * 100; - if (intensity >= thresholdValue && y[i] > y[i - 1] && y[i] > y[i + 1]) { - peaks.push({ - x: x[i], - y: y[i] - }); - } - } - return peaks; - } const peak = []; if (!feature || !feature.data) return peak; const data = feature.data[0]; @@ -209,12 +179,8 @@ const Convert2Peak = (feature, threshold, offset, upThreshold = false, lowThresh const { layout } = operation; - if (_format.default.isLCMsLayout(layout) && feature.peaks) { - return feature.peaks.map(p => ({ - x: p.x - (offset || 0), - y: p.y - })); - } + + // if (!Format.isSECLayout(layout) && (upperThres || lowerThres)) { if ((_format.default.isCyclicVoltaLayout(layout) || _format.default.isCDSLayout(layout)) && (upperThres || lowerThres)) { let upperThresVal = upThreshold || upperThres; if (!upperThresVal) { @@ -325,7 +291,6 @@ const convertThresEndPts = (feature, threshold) => { }]; return endPts; }; -exports.convertThresEndPts = convertThresEndPts; const ToThresEndPts = exports.ToThresEndPts = (0, _reselect.createSelector)(getFeature, getThreshold, convertThresEndPts); const getShiftPeak = state => { const { @@ -357,20 +322,14 @@ const ToShiftPeaks = exports.ToShiftPeaks = (0, _reselect.createSelector)(getShi // ExtractJcamp // - - - - - - - - - - - - - - - - - - - - - - const readLayout = jcamp => { - if (jcamp.dataType?.toUpperCase?.() === 'LC/MS') { - return _list_layout.LIST_LAYOUT.LC_MS; - } const { xType, spectra } = jcamp; if (xType && _format.default.isNmrLayout(xType)) return xType; - if (!spectra || !Array.isArray(spectra) || spectra.length === 0) { - return false; - } const { dataType - } = spectra[0] || {}; + } = spectra[0]; if (dataType) { if (dataType.includes('INFRARED SPECTRUM')) { return _list_layout.LIST_LAYOUT.IR; @@ -420,9 +379,6 @@ const readLayout = jcamp => { if (dataType.includes('DLS intensity')) { return _list_layout.LIST_LAYOUT.DLS_INTENSITY; } - if (dataType.includes('LC/MS')) { - return _list_layout.LIST_LAYOUT.LC_MS; - } } return false; }; @@ -430,217 +386,30 @@ const extrSpectraShare = (spectra, layout) => spectra.map(s => Object.assign({ layout }, s)).filter(r => r != null); const extrSpectraMs = (jcamp, layout) => { - const csCategories = [].concat(jcamp?.info?.$CSCATEGORY || []).map(c => String(c).toUpperCase()); - const hasUvvisCategory = csCategories.some(c => c.includes('UVVIS')); - const hasUvvisDataType = jcamp?.spectra?.some(s => { - const dt = String(s?.dataType || '').toUpperCase(); - return dt.includes('UV-VIS') || dt.includes('UVVIS') || dt.includes('HPLC UV'); - }); - const jcampDataType = String(jcamp?.dataType || '').toUpperCase(); - const hasUvvisJcampDataType = jcampDataType.includes('UV-VIS') || jcampDataType.includes('UVVIS') || jcampDataType.includes('HPLC UV'); - const isUvvisData = hasUvvisCategory || hasUvvisDataType || hasUvvisJcampDataType; - const hasTicCategory = csCategories.some(c => c.includes('TIC')); - const hasTicDataType = jcamp?.spectra?.some(s => { - const dt = String(s?.dataType || '').toUpperCase(); - return dt.includes('MASS TIC') || dt.includes('TIC'); - }); - const hasTicJcampDataType = jcampDataType.includes('MASS TIC') || jcampDataType.includes('TIC'); - const isTicData = hasTicCategory || hasTicDataType || hasTicJcampDataType; - const getCategory = idx => csCategories[idx] || ''; - const finalSpectra = []; - const parseIntegralsString = raw => { - if (raw == null) return []; - let text = raw; - if (Array.isArray(text)) text = text.join(' '); - text = String(text).trim(); - const groups = text.match(/\(([^)]+)\)/g) || []; - const out = []; - groups.forEach(g => { - const nums = g.replace(/[()]/g, '').split(/[,\s;]+/).map(s => Number(s)).filter(Number.isFinite); - if (nums.length >= 3) { - const [xL, xU, area, absMaybe] = nums; - out.push({ - xL, - xU, - area, - absoluteArea: Number.isFinite(absMaybe) ? absMaybe : Math.abs(area), - xExtent: { - xL, - xU - } - }); - } - }); - return out; - }; - const pickIntegralsForPair = (raw, idx) => { - if (raw == null) return ''; - if (Array.isArray(raw)) return raw[idx] ?? ''; - if (typeof raw === 'string') return idx === 0 ? raw : ''; - return ''; - }; - if (isUvvisData) { - const spectraList = jcamp.spectra || []; - const uvvisSpectra = []; - const peakTablesByPage = new Map(); - const hasPeakData = table => { - const data = table?.data?.[0]; - if (!data) return false; - if (Array.isArray(data)) return data.length >= 2; - if (data?.x && data?.y) return data.x.length > 0 && data.y.length > 0; - return false; - }; - const buildPeaks = source => { - if (!source) return []; - if (Array.isArray(source)) { - const peaks = []; - for (let i = 0; i < source.length - 1; i += 2) { - const x = Number(source[i]); - const y = Number(source[i + 1]); - if (Number.isFinite(x) && Number.isFinite(y)) peaks.push({ - x, - y - }); - } - return peaks; - } - if (source?.x && source?.y) { - const len = Math.min(source.x.length, source.y.length); - const peaks = new Array(len); - for (let j = 0; j < len; j++) peaks[j] = { - x: source.x[j], - y: source.y[j] - }; - return peaks; - } - return []; - }; - spectraList.forEach((s, idx) => { - if (!s) return; - const sDataType = String(s.dataType || '').toUpperCase(); - const isUvvisSpectrum = s.dataType === 'LC/MS' && getCategory(idx).includes('UVVIS') || sDataType.includes('UV-VIS') || sDataType.includes('UVVIS') || sDataType.includes('HPLC UV'); - if (isUvvisSpectrum) { - uvvisSpectra.push({ - spectrum: s, - idx - }); - } - if (s.dataType?.includes('PEAKTABLE')) { - const pageKey = s.pageValue ?? s.page; - if (pageKey == null) return; - const entry = peakTablesByPage.get(pageKey) || {}; - const cat = getCategory(idx); - if (cat.includes('AUTO_PEAK')) entry.auto = s;else if (cat.includes('EDIT_PEAK')) entry.edit = s;else entry.other = s; - peakTablesByPage.set(pageKey, entry); - } - }); - const container = jcamp?.info?.$OBSERVEDINTEGRALS ?? null; - const jcampUnitsField = String(jcamp?.info?.UNITS || '').toUpperCase(); - const jcampUnitsIndicatesMinutes = jcampUnitsField.includes('MINUTE'); - const jcampUnitsIndicatesSeconds = jcampUnitsField.includes('SECOND'); - const getMaxAbsX = data => { - const xs = data?.[0]?.x; - if (!Array.isArray(xs) || xs.length === 0) return 0; - return xs.reduce((max, value) => { - const abs = Math.abs(Number(value)); - return Number.isFinite(abs) && abs > max ? abs : max; - }, 0); - }; - uvvisSpectra.forEach(({ - spectrum - }, pairIdx) => { - const xUnitUpper = String(spectrum?.xUnit || '').toUpperCase(); - const isExplicitMinutes = xUnitUpper.includes('MINUTE') || jcampUnitsIndicatesMinutes; - const isExplicitSeconds = xUnitUpper.includes('SECOND') || jcampUnitsIndicatesSeconds; - const isTimeAxis = xUnitUpper.includes('TIME') || xUnitUpper.includes('SECOND'); - const dataLooksLikeSeconds = getMaxAbsX(spectrum?.data) > 60; - const needsSecToMin = isTimeAxis && !isExplicitMinutes && (isExplicitSeconds || dataLooksLikeSeconds); - const scaleX = value => needsSecToMin ? value / 60 : value; - const pageKey = spectrum.pageValue ?? spectrum.page; - const peakTable = peakTablesByPage.get(pageKey); - let selectedPeakTable = null; - if (hasPeakData(peakTable?.edit)) { - selectedPeakTable = peakTable.edit; - } else if (hasPeakData(peakTable?.auto)) { - selectedPeakTable = peakTable.auto; - } else if (hasPeakData(peakTable?.other)) { - selectedPeakTable = peakTable.other; - } else { - selectedPeakTable = peakTable?.edit || peakTable?.auto || peakTable?.other || null; - } - const originalData = spectrum?.data?.[0]; - let normalizedData = spectrum.data; - if (needsSecToMin && originalData?.x) { - normalizedData = [{ - ...originalData, - x: originalData.x.map(scaleX) - }]; - } - const mainSpectrum = { - ...spectrum, - data: normalizedData, - peaks: [], - integrations: [], - csCategory: 'UVVIS PEAK TABLE' - }; - const peakSource = selectedPeakTable?.data?.[0] || spectrum?.data?.[0]; - const peaks = buildPeaks(peakSource).map(p => ({ - ...p, - x: scaleX(p.x) - })); - if (peaks.length) mainSpectrum.peaks = peaks; - const rawText = pickIntegralsForPair(container, pairIdx); - const integrals = parseIntegralsString(rawText).map(integ => ({ - ...integ, - xL: scaleX(integ.xL), - xU: scaleX(integ.xU), - xExtent: { - xL: scaleX(integ.xL), - xU: scaleX(integ.xU) - } - })); - if (integrals.length) mainSpectrum.integrations = integrals; - finalSpectra.push(mainSpectrum); - }); - } else if (isTicData) { - (jcamp.spectra || []).forEach(s => { - const hasPoints = s?.data?.[0]?.x?.length > 0; - if (hasPoints) { - finalSpectra.push({ - ...s, - csCategory: (0, _parsing.inferLcMsCategory)(s, jcamp) - }); - } - }); - } else { - (jcamp.spectra || []).forEach(s => { - const hasPoints = s?.data?.[0]?.x?.length > 0; - if (hasPoints) { - finalSpectra.push({ - ...s, - csCategory: (0, _parsing.inferLcMsCategory)(s, jcamp) - }); - } - }); - } - let spectra = extrSpectraShare(finalSpectra, layout) || []; - const info = jcamp?.info || {}; - if (info.UNITS && info.SYMBOL) { - const unitsString = Array.isArray(info.UNITS) ? info.UNITS[0] : info.UNITS; - const symbolString = Array.isArray(info.SYMBOL) ? info.SYMBOL[0] : info.SYMBOL; - const units = String(unitsString).split(','); - const symbols = String(symbolString).split(','); + 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; - symbols.forEach((sym, idx) => { - const curr = String(sym).replace(' ', '').toLowerCase(); - if (curr === 'x') xUnit = units[idx]?.trim?.() || null; - if (curr === 'y') yUnit = units[idx]?.trim?.() || 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; + if (xUnit) { + spectrum.xUnit = xUnit; + } + if (yUnit) { + spectrum.yUnit = yUnit; + } return spectrum; }); } @@ -653,33 +422,21 @@ const extrSpectraNi = (jcamp, layout) => { return [spectrum] || [jcamp.spectra[0]]; }; const calcThresRef = (s, peakUp) => { - if (!s || !s.data || !Array.isArray(s.data) || !s.data[0] || !s.data[0].y) { - return null; - } - const ys = s.data[0].y; - if (!ys || !Array.isArray(ys) || ys.length === 0) return null; + 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); - if (!s.maxY || s.maxY === 0) return null; return peakUp ? Math.floor(ref * 100 * 100 / s.maxY) / 100 : Math.ceil(ref * 100 * 100 / s.maxY) / 100; }; const calcUpperThres = s => { - if (!s || !s.data || !Array.isArray(s.data) || !s.data[0] || !s.data[0].y) { - return null; - } - const ys = s.data[0].y; - if (!ys || !Array.isArray(ys) || ys.length === 0) return null; + const ys = s && s.data[0].y; + if (!ys) return null; const ref = Math.max(...ys); - if (!s.maxY || s.maxY === 0) return null; return Math.floor(ref * 100 * 100 / s.maxY) / 100; }; const calcLowerThres = s => { - if (!s || !s.data || !Array.isArray(s.data) || !s.data[0] || !s.data[0].y) { - return null; - } - const ys = s.data[0].y; - if (!ys || !Array.isArray(ys) || ys.length === 0) return null; + const ys = s && s.data[0].y; + if (!ys) return null; const ref = Math.min(...ys); - if (!s.minY || s.minY === 0) return null; return Math.ceil(ref * 100 * 100 / s.minY) / 100; }; const extractShift = (s, jcamp) => { @@ -735,12 +492,13 @@ const extractVoltammetryData = jcamp => { return peakStack; }; const buildPeakFeature = (jcamp, layout, peakUp, s, thresRef, upperThres = false, lowerThres = false) => { + // eslint-disable-line const { xType, info } = jcamp; const subTyp = xType ? ` - ${xType}` : ''; - const baseFeature = { + return Object.assign({ typ: s.dataType + subTyp, peakUp, thresRef, @@ -760,14 +518,8 @@ const buildPeakFeature = (jcamp, layout, peakUp, s, thresRef, upperThres = false scanRate: +info.$CSSCANRATE || 0.1, weAreaValue: info.$CSWEAREAVALUE || '', weAreaUnit: info.$CSWEAREAUNIT || '', - currentMode: info.$CSCURRENTMODE || '', - csCategory: info.$CSCATEGORY || s.csCategory - }; - if (layout === 'LC/MS') { - if (s.peaks) baseFeature.peaks = s.peaks; - if (s.integrations) baseFeature.integrations = s.integrations; - } - return Object.assign({}, baseFeature, s); + currentMode: info.$CSCURRENTMODE || '' + }, s); }; const maxArray = arr => { let len = arr.length; @@ -795,43 +547,23 @@ const calcIntgRefArea = (spectra, stack) => { 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, - $OBSERVEDINTEGRALSGROUPS + $OBSERVEDMULTIPLETS } = jcamp.info; const regx = /[^0-9.,-]/g; let stack = []; if ($OBSERVEDINTEGRALS) { const its = $OBSERVEDINTEGRALS.split('\n').slice(1); - const groupsByIdx = parseObservedIntegralGroups($OBSERVEDINTEGRALSGROUPS); - const itStack = its.map((t, idx) => { + const itStack = its.map(t => { const ts = t.replace(regx, '').split(','); - const item = { + return { 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]; } @@ -870,7 +602,7 @@ const range = (head, tail, length) => { ); }; */ -exports.buildIntegFeature = buildIntegFeature; + const buildSimFeature = jcamp => { const { $CSSIMULATIONPEAKS @@ -1048,15 +780,32 @@ const extrFeaturesCylicVolta = (jcamp, layout, peakUp) => { }).filter(r => r != null); return features; }; -const extrFeaturesMs = (jcamp, layout, peakUp, spectra) => { +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 features = spectra.map(s => { - if (!s.data || !s.data[0] || !s.data[0].x || !s.data[0].y) { - return null; - } + 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({}, cpo, bnd); + return Object.assign({}, base, cpo, bnd); }).filter(r => r != null); return features; }; @@ -1070,135 +819,17 @@ const extractTemperature = jcamp => { } return 'xxx'; }; -const normalizeXyData = raw => { - if (!raw) return null; - if (Array.isArray(raw)) { - if (raw.length === 0) return null; - const first = raw[0]; - if (first && typeof first === 'object' && !Array.isArray(first)) { - const x = Array.isArray(first.x) ? first.x : []; - const y = Array.isArray(first.y) ? first.y : []; - if (x.length || y.length) return { - x, - y - }; - } - if (Array.isArray(first)) { - if (raw.length === 2 && Array.isArray(raw[0]) && Array.isArray(raw[1])) { - return { - x: raw[0], - y: raw[1] - }; - } - const x = []; - const y = []; - raw.forEach(pair => { - if (!Array.isArray(pair) || pair.length < 2) return; - const xVal = Number(pair[0]); - const yVal = Number(pair[1]); - if (Number.isFinite(xVal) && Number.isFinite(yVal)) { - x.push(xVal); - y.push(yVal); - } - }); - if (x.length || y.length) return { - x, - y - }; - } - } else if (typeof raw === 'object') { - const x = Array.isArray(raw.x) ? raw.x : []; - const y = Array.isArray(raw.y) ? raw.y : []; - if (x.length || y.length) return { - x, - y - }; - } - return null; -}; -const ensureSpectrumData = (spectrum, source) => { - if (!spectrum) return spectrum; - const result = { - ...spectrum - }; - let normalized = normalizeXyData(result.data); - if (!normalized && source) { - normalized = normalizeXyData({ - x: source.x, - y: source.y - }) || normalizeXyData(source.data); - } - if (normalized) { - result.data = [{ - x: normalized.x || [], - y: normalized.y || [] - }]; - } - return result; -}; const ExtractJcamp = source => { const jcamp = _jcampconverter.default.convert(source, { xy: true, - 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|\$CSLCMSMZPAGE|SCAN_MODE|SCANMODE|TYPE|SOFTWARE|DATATYPE)/ // eslint-disable-line + 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 isChemstation = (0, _parsing.isChemstationLcms)(source, jcamp); - const parsedPages = (0, _parsing.parseChemstationPages)(source, jcamp); - const spectraCount = Array.isArray(jcamp.spectra) ? jcamp.spectra.length : 0; - if (parsedPages.length > 1 && spectraCount < parsedPages.length) { - jcamp.spectra = parsedPages; - } - const hasNtuples = jcamp.ntuples && Array.isArray(jcamp.ntuples) && jcamp.ntuples.length > 0; - const hasSpectra = jcamp.spectra && Array.isArray(jcamp.spectra) && jcamp.spectra.length > 0; - const hasNtupleData = hasNtuples && jcamp.ntuples.some(ntuple => !!normalizeXyData(ntuple?.data) || !!normalizeXyData({ - x: ntuple?.x, - y: ntuple?.y - })); - const hasSpectraData = hasSpectra && jcamp.spectra.some(spectrum => !!normalizeXyData(spectrum?.data) || !!normalizeXyData({ - x: spectrum?.x, - y: spectrum?.y - })); - if (hasNtuples && hasNtupleData) { - if (hasSpectra && jcamp.spectra.length === 1 && jcamp.ntuples.length > 1) { - const singleSpectrum = jcamp.spectra[0]; - jcamp.spectra = jcamp.ntuples.map(ntuple => { - const spectrum = { - ...singleSpectrum, - ...ntuple, - dataType: singleSpectrum.dataType || jcamp.dataType || ntuple.dataType, - xUnit: ntuple.xUnit || singleSpectrum.xUnit || jcamp.info?.XUNITS, - yUnit: ntuple.yUnit || singleSpectrum.yUnit || jcamp.info?.YUNITS, - pageValue: ntuple.pageValue || ntuple.page, - page: ntuple.page || ntuple.pageValue, - pageSymbol: ntuple.pageSymbol || ntuple.pageValue || ntuple.page - }; - ensureSpectrumData(spectrum, ntuple); - return spectrum; - }); - } else if (!hasSpectra || !hasSpectraData || jcamp.spectra.length < jcamp.ntuples.length) { - jcamp.spectra = jcamp.ntuples.map(ntuple => { - const spectrum = { - ...ntuple, - dataType: jcamp.dataType || ntuple.dataType, - xUnit: ntuple.xUnit || jcamp.info?.XUNITS, - yUnit: ntuple.yUnit || jcamp.info?.YUNITS, - pageValue: ntuple.pageValue || ntuple.page, - page: ntuple.page || ntuple.pageValue, - pageSymbol: ntuple.pageSymbol || ntuple.pageValue || ntuple.page - }; - ensureSpectrumData(spectrum, ntuple); - return spectrum; - }); - } - } - let layout = readLayout(jcamp); - if (isChemstation) { - layout = _list_layout.LIST_LAYOUT.LC_MS; - } + const layout = readLayout(jcamp); const peakUp = !_format.default.isIrLayout(layout); - const spectra = _format.default.isMsLayout(layout) || _format.default.isLCMsLayout(layout) ? extrSpectraMs(jcamp, layout) : extrSpectraNi(jcamp, layout); + const spectra = _format.default.isMsLayout(layout) ? extrSpectraMs(jcamp, layout) : extrSpectraNi(jcamp, layout); let features = {}; - if (_format.default.isMsLayout(layout) || _format.default.isLCMsLayout(layout)) { - features = extrFeaturesMs(jcamp, layout, peakUp, spectra); + 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); @@ -1234,15 +865,6 @@ const ExtractJcamp = source => { // : ((Format.isXRDLayout(layout) || Format.isCyclicVoltaLayout(layout)) // ? extrFeaturesXrd(jcamp, layout, peakUp) : extrFeaturesNi(jcamp, layout, peakUp, spectra)); - const lcmsMzPageFromInfo = _format.default.isLCMsLayout(layout) ? (0, _parsing.readLcmsMzPageFromJcampInfo)(jcamp.info) : null; - if (lcmsMzPageFromInfo != null) { - return { - spectra, - features, - layout, - lcms_mz_page: lcmsMzPageFromInfo - }; - } return { spectra, features, diff --git a/dist/helpers/compass.js b/dist/helpers/compass.js index 00e85277..c23573b0 100644 --- a/dist/helpers/compass.js +++ b/dist/helpers/compass.js @@ -4,18 +4,9 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau Object.defineProperty(exports, "__esModule", { value: true }); -exports.getCurvePointFromEvent = exports.clearIntegrationPreview = exports.TfRescale = exports.MouseMove = exports.MountCompass = exports.ClickCompass = void 0; +exports.TfRescale = exports.MouseMove = exports.MountCompass = exports.ClickCompass = void 0; var _format = _interopRequireDefault(require("./format")); var _chem = require("./chem"); -var _list_ui = require("../constants/list_ui"); -var _cfg = _interopRequireDefault(require("./cfg")); -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; @@ -27,16 +18,25 @@ const TfRescale = focus => { }; exports.TfRescale = TfRescale; 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[Math.min(idx, ls - 1)]; + return sortData[idx]; }; 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); @@ -58,69 +58,6 @@ const fetchFreePt = (event, focus, xt, yt) => { }); 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; - if (!_cfg.default.showIntegSplitTools(focus.layout)) 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 - } = (0, _integration_split.getIntegrationSplitTargetFromEvent)(event, focus); - if (!target) { - (0, _integration_split.clearIntegrationSplitPreview)(focus); - return; - } - if (focus.isUiVisualSplitIntgSt && (0, _integration_split.isAlreadyVisuallySplit)(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, @@ -162,13 +99,6 @@ const MouseMove = (event, focus) => { 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 if (_format.default.isMsLayout(layout)) { - const maxY = d3.max(focus.data, row => row.y) || 0; - const relPct = maxY > 0 ? 100 * pt.y / maxY : 0; - const rel = maxY > 0 ? parseInt(relPct, 10) : 0; - const xPrecision = _format.default.clampDecimalPlaces(focus.decimal); - focus.root.select('.cursor-txt').attr('transform', `translate(${tx},${10})`).text(`${pt.x.toFixed(xPrecision)} (${rel})`); - focus.root.select('.cursor-txt-hz').text(''); } else { focus.root.select('.cursor-txt').attr('transform', `translate(${tx},${10})`).text(pt.x.toFixed(3)); if (freq) { @@ -179,111 +109,21 @@ const MouseMove = (event, focus) => { } } } - 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 && _cfg.default.showIntegSplitTools(focus.layout)) { - 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; - } - if (focus.isUiVisualSplitIntgSt) { - const { - splitX, - target - } = (0, _integration_split.getIntegrationSplitTargetFromEvent)(event, focus); - if (!target) return; - const { - stack = [], - shift = 0 - } = focus.integrationSplitTargets || {}; - const existingSplitX = (0, _integration_split.getVisualSplitLineAtX)(focus, stack, splitX, shift); - (0, _integration_split.clearIntegrationSplitPreview)(focus); - if (Number.isFinite(existingSplitX)) { - if (typeof focus.removeVisualSplitLineAct !== 'function') return; - focus.removeVisualSplitLineAct({ - curveIdx: focus.jcampIdx, - splitX: existingSplitX, - data: focus.data - }); - return; - } - if ((0, _integration_split.isAlreadyVisuallySplit)(target)) return; - if (typeof focus.addVisualSplitLineAct !== 'function') return; - focus.addVisualSplitLineAct({ - curveIdx: focus.jcampIdx, - target, - splitX, - data: focus.data - }); - return; - } - const { - layout, - cyclicvoltaSt, - jcampIdx - } = focus; - const isPeakGroupSelect = focus.uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT; - const isMsGraph = focus.graphIndex === 2; - const isUvvisGraph = focus.graphIndex === 0; - const isLcmsTicGraph = _format.default.isLCMsLayout(layout) && focus.graphIndex === 1; - if (isPeakGroupSelect && isMsGraph) return; - if (isPeakGroupSelect && _format.default.isLCMsLayout(layout) && isUvvisGraph) 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; @@ -297,8 +137,6 @@ const ClickCompass = (event, focus) => { } else { focus.clickUiTargetAct(pt, onPeak); } - } else if (isLcmsTicGraph) { - focus.clickUiTargetAct(pt, false, false, jcampIdx, false, 'lcms_tic'); } else { focus.clickUiTargetAct(pt, false); } @@ -312,13 +150,11 @@ const MountCompass = focus => { } = 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/extractParams.js b/dist/helpers/extractParams.js index c7cbe90f..cbb4f86a 100644 --- a/dist/helpers/extractParams.js +++ b/dist/helpers/extractParams.js @@ -6,33 +6,35 @@ Object.defineProperty(exports, "__esModule", { }); exports.extractParams = void 0; var _format = _interopRequireDefault(require("./format")); -var _extractEntityLCMS = require("./extractEntityLCMS"); -const getScanIdx = (entity, scanState) => { +const getScanIdx = (entity, scanSt) => { const { target, isAuto - } = scanState || {}; + } = scanSt; const { - features = {}, - spectra = [] - } = entity || {}; - const defaultFeature = features.editPeak || features.autoPeak || features[0] || {}; - const hasEdit = !!defaultFeature?.scanEditTarget; - const defaultIdx = isAuto || !hasEdit ? defaultFeature?.scanAutoTarget : defaultFeature?.scanEditTarget; + 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 Math.max(idx - 1, 0); + if (idx > defaultCount) { + idx = defaultCount; + } + return idx - 1; }; -const extractSharedParams = (entity, thresholdState, scanIdx = 0) => { +const extrShare = (entity, thresSt, scanIdx = 0) => { const { - spectra = [], - features = {} - } = entity || {}; - const autoPeak = features.autoPeak || features[scanIdx] || features[0] || {}; - const editPeak = features.editPeak || features[scanIdx] || features[0] || {}; - const hasEdit = !!editPeak?.data?.[0]?.x?.length; - const feature = hasEdit && thresholdState?.isEdit ? editPeak : autoPeak; + 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 @@ -45,99 +47,21 @@ const extractSharedParams = (entity, thresholdState, scanIdx = 0) => { multiplicity }; }; -const extractLcmsParams = entity => { - const { - features, - layout - } = entity; - let topicX = []; - let topicY = []; - const entityInfo = (0, _extractEntityLCMS.getLcMsInfo)(entity); - let featuresArray = []; - if (Array.isArray(features)) { - featuresArray = features; - } else if (features && typeof features === 'object') { - featuresArray = Object.values(features); - } - if (entityInfo.kind === 'tic') { - const ticFeature = featuresArray.find(spectrum => spectrum?.data?.[0]?.x?.length > 0); - if (ticFeature?.data?.[0]) { - const { - x, - y - } = ticFeature.data[0]; - topicX = x; - topicY = y; - } - } else { - featuresArray.forEach(spectrum => { - if (!spectrum?.data?.[0]) return; - const { - y - } = spectrum.data[0]; - const { - pageValue - } = spectrum; - topicX.push(pageValue); - topicY.push(Math.max(...y)); - }); - } - return { - topic: { - x: topicX, - y: topicY - }, - feature: { - maxY: topicY.length ? Math.max(...topicY) : 0, - operation: { - layout - }, - data: [{ - x: topicX, - y: topicY - }], - isPeaktable: false - } - }; -}; -const extractMsParams = (entity, thresholdState, scanState, forceLcms = false) => { - const { - layout - } = entity; - if (_format.default.isMsLayout(layout) && !forceLcms) { - const scanIdx = getScanIdx(entity, scanState); - const { - spectra, - feature, - hasEdit - } = extractSharedParams(entity, thresholdState, scanIdx); - const topic = spectra?.[scanIdx]?.data?.[0] || { - x: [], - y: [] - }; - return { - topic, - feature, - hasEdit - }; - } +const extrMs = (entity, thresSt, scanSt) => { + const scanIdx = getScanIdx(entity, scanSt); const { spectra, - features - } = entity; - const { - topic, - feature - } = extractLcmsParams(entity); + feature, + hasEdit + } = extrShare(entity, thresSt, scanIdx); + const topic = spectra[scanIdx].data[0]; return { - entity, - spectra, - features, topic, - feature + feature, + hasEdit }; }; -const extractNonMsParams = (entity, thresholdState) => { +const extrNi = (entity, thresSt) => { const scanIdx = 0; const { spectra, @@ -145,11 +69,8 @@ const extractNonMsParams = (entity, thresholdState) => { hasEdit, integration, multiplicity - } = extractSharedParams(entity, thresholdState, scanIdx); - const topic = spectra?.[0]?.data?.[0] || { - x: [], - y: [] - }; + } = extrShare(entity, thresSt, scanIdx); + const topic = spectra[0].data[0]; return { topic, feature, @@ -158,13 +79,7 @@ const extractNonMsParams = (entity, thresholdState) => { multiplicity }; }; -const extractParams = (entity, thresholdState, scanState, options = {}) => { - const { - forceLcms = false - } = options; - const shouldUseLcmsPath = forceLcms || _format.default.isLCMsLayout(entity.layout); - return _format.default.isMsLayout(entity.layout) || shouldUseLcmsPath ? extractMsParams(entity, thresholdState, scanState, shouldUseLcmsPath) : extractNonMsParams(entity, thresholdState); -}; +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 index c0d0433b..92af43f4 100644 --- a/dist/helpers/extractPeaksEdit.js +++ b/dist/helpers/extractPeaksEdit.js @@ -5,32 +5,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.extractPeaksEdit = exports.extractAutoPeaks = exports.extractAreaUnderCurve = void 0; -Object.defineProperty(exports, "formatLcmsIntegralsForBackend", { - enumerable: true, - get: function get() { - return _submit.formatLcmsIntegralsForBackend; - } -}); -Object.defineProperty(exports, "formatLcmsPeaksForBackend", { - enumerable: true, - get: function get() { - return _submit.formatLcmsPeaksForBackend; - } -}); -Object.defineProperty(exports, "getLcmsMzPageData", { - enumerable: true, - get: function get() { - return _submit.getLcmsMzPageData; - } -}); -var _chem = require("./chem"); var _converter = require("./converter"); +var _chem = require("./chem"); var _shift = require("./shift"); var _format = _interopRequireDefault(require("./format")); var _integration = require("./integration"); -var _submit = require("../features/lc-ms/submit"); -/* eslint-disable max-len */ - const niOffset = (shiftSt, atIndex = 0) => { const { shifts @@ -47,18 +26,19 @@ const niOffset = (shiftSt, atIndex = 0) => { 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) || _format.default.isLCMsLayout(layoutSt) ? msOffset() : niOffset(shiftSt, atIndex); + 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 extractPeaksEdit = (feature, editPeakSt, thresSt, shiftSt, layoutSt, atIndex = 0) => { - if (_format.default.isLCMsLayout(layoutSt)) return []; - const peaks = extractAutoPeaks(feature, thresSt, shiftSt, layoutSt, atIndex); - return (0, _converter.PksEdit)(peaks, editPeakSt); -}; -exports.extractPeaksEdit = extractPeaksEdit; const getAUCValue = (integrationSt, layoutSt) => { const { refArea, diff --git a/dist/helpers/format.js b/dist/helpers/format.js index 24e07a64..b528beb8 100644 --- a/dist/helpers/format.js +++ b/dist/helpers/format.js @@ -1,9 +1,11 @@ "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"); @@ -23,7 +25,6 @@ const spectraDigit = layout => { case _list_layout.LIST_LAYOUT.CDS: case _list_layout.LIST_LAYOUT.SEC: case _list_layout.LIST_LAYOUT.GC: - case _list_layout.LIST_LAYOUT.LC_MS: case _list_layout.LIST_LAYOUT.MS: return 0; case _list_layout.LIST_LAYOUT.C13: @@ -43,16 +44,6 @@ const fixDigit = (input, precision) => { const output = input || 0.0; return output.toFixed(precision); }; - -/** - * Integer 0–20 for toFixed; invalid input uses fallback. - * Default 3 preserves legacy cursor precision. - */ -const clampDecimalPlaces = (value, fallback = 3) => { - const n = Number(value); - if (!Number.isFinite(n)) return fallback; - return Math.max(0, Math.min(20, Math.trunc(n))); -}; const buildData = entity => { if (!entity) return { isExist: false @@ -72,28 +63,6 @@ const toPeakStr = peaks => { const str = arr.join('#'); return str; }; -const extractUvvisLcmsPeaks = hplcMsSt => { - if (!hplcMsSt?.uvvis) { - return '{}'; - } - const { - listWaveLength = [], - spectraList = [] - } = hplcMsSt.uvvis; - const byWavelength = {}; - spectraList.forEach((spectrum, idx) => { - const wl = listWaveLength[idx]; - const wlKey = String(Math.round(wl)); - (spectrum.peaks || []).forEach((p, n) => { - if (!byWavelength[wlKey]) byWavelength[wlKey] = []; - byWavelength[wlKey].push({ - x: p.x, - y: p.y - }); - }); - }); - return JSON.stringify(byWavelength); -}; const spectraOps = { [_list_layout.LIST_LAYOUT.PLAIN]: { head: '', @@ -178,10 +147,6 @@ const spectraOps = { [_list_layout.LIST_LAYOUT.DLS_INTENSITY]: { head: 'DLS', tail: '.' - }, - [_list_layout.LIST_LAYOUT.LC_MS]: { - head: 'HPLC UV/VIS', - tail: '' } }; const rmRef = (peaks, shift, atIndex = 0) => { @@ -193,147 +158,6 @@ const rmRef = (peaks, shift, atIndex = 0) => { 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 isValidLcmsWavelengthLabel = wl => Number.isFinite(wl) && wl > 0; -const LCMS_INTEGRATION_EXPORT_MODES = ['percent', 'area', 'both']; -const isLcmsIntegrationExportMode = v => LCMS_INTEGRATION_EXPORT_MODES.includes(v); -const formatedLCMS = (hplcMsSt, isAscend, decimal, options = {}) => { - if (!hplcMsSt?.uvvis) { - return ''; - } - const { - lcmsIntegrationsExport: modeOpt, - includeIntegrationArea = false - } = options; - let lcmsIntegrationsExport = modeOpt; - if (!isLcmsIntegrationExportMode(lcmsIntegrationsExport)) { - lcmsIntegrationsExport = hplcMsSt?.lcmsIntegrationsExport; - } - if (!isLcmsIntegrationExportMode(lcmsIntegrationsExport)) { - lcmsIntegrationsExport = includeIntegrationArea ? 'both' : 'percent'; - } - let result = '\n'; - const sections = []; - const parsedDecimal = Number.isFinite(decimal) ? decimal : Number.parseInt(decimal, 10); - const resolvedDecimal = Number.isFinite(parsedDecimal) ? parsedDecimal : 3; - const { - listWaveLength = [], - spectraList = [] - } = hplcMsSt.uvvis || {}; - const ms = hplcMsSt.ms || {}; - const tic = hplcMsSt.tic; - const threshold = hplcMsSt.threshold; - listWaveLength.forEach((wavelength, idx) => { - const spectrum = spectraList[idx]; - if (!spectrum) { - return; - } - const peaks = spectrum.peaks || []; - const integrations = spectrum.integrations || []; - const stack = integrations?.[0]?.stack; - const hasStack = Array.isArray(stack) && stack.length > 0; - const hasList = !hasStack && Array.isArray(integrations) && integrations.length > 0; - const hasIntegrations = hasStack || hasList; - const hasPeaks = peaks.length > 0; - if (!hasPeaks && !hasIntegrations) { - return; - } - const lines = []; - if (isValidLcmsWavelengthLabel(wavelength)) { - lines.push(`Wavelength ${wavelength} nm:`); - } - if (hasPeaks) { - const sortedPeaks = [...peaks].sort((a, b) => b.y - a.y); - const maxIntensity = sortedPeaks[0].y || 1; - const peakLines = sortedPeaks.map(peak => { - const rt = peak.x.toFixed(resolvedDecimal); - const percent = (peak.y / maxIntensity * 100).toFixed(1); - return `${rt} min (${percent}%)`; - }); - lines.push(`Peaks: ${peakLines.join(', ')}`); - } - if (hasIntegrations) { - const entries = hasStack ? stack : integrations; - const refAreaCandidate = hasStack ? integrations?.[0]?.refArea : integrations?.[0]?.refArea ?? integrations?.[0]?.area; - const refArea = refAreaCandidate && refAreaCandidate > 0 ? refAreaCandidate : 1; - const sortedIntegrations = [...entries].sort((a, b) => a.xL - b.xL); - const integrationLines = sortedIntegrations.map(integ => { - const rt = integ.xL.toFixed(resolvedDecimal); - const area = integ.area || integ.absoluteArea || 0; - const percent = (area / refArea * 100).toFixed(1); - const areaStr = Number.isFinite(area) ? area.toExponential(3) : String(area); - if (lcmsIntegrationsExport === 'area') { - return `${rt} min (A=${areaStr})`; - } - if (lcmsIntegrationsExport === 'both') { - return `${rt} min (${percent}%, A=${areaStr})`; - } - return `${rt} min (${percent}%)`; - }); - lines.push(`Integrations: ${integrationLines.join(', ')}`); - } - sections.push(lines.join('\n')); - }); - if (sections.length > 0) { - result = `\n${sections.join('\n\n')}`; - } - const polarity = tic?.polarity || 'positive'; - let polarityKey = 'neutral'; - if (polarity === 'negative') { - polarityKey = 'negative'; - } else if (polarity === 'positive') { - polarityKey = 'positive'; - } - let polarityLabel = ''; - if (polarity === 'negative') { - polarityLabel = '−'; - } else if (polarity === 'positive') { - polarityLabel = '+'; - } - if (tic && ms[polarityKey]) { - const pageValues = Array.isArray(ms[polarityKey].pageValues) ? ms[polarityKey].pageValues : []; - const peaksByPage = Array.isArray(ms[polarityKey].peaks) ? ms[polarityKey].peaks : []; - let currentIndex = -1; - if (Number.isFinite(tic.currentPageValue) && pageValues.length > 0) { - currentIndex = pageValues.findIndex(value => Number.isFinite(value) && Math.abs(value - tic.currentPageValue) < 1e-6); - } - if (Array.isArray(tic[polarityKey]?.data?.x)) { - const fallbackIndex = tic[polarityKey].data.x.findIndex(x => Math.abs(x - tic.currentPageValue) < 1e-6); - if (currentIndex < 0) currentIndex = fallbackIndex; - } - if (currentIndex >= 0 && peaksByPage[currentIndex]) { - const peaks = peaksByPage[currentIndex]; - const maxIntensity = Math.max(...peaks.map(p => p.y)) || 1; - const thresholdValue = threshold?.value != null ? threshold.value : 5; - const filtered = peaks.filter(peak => peak.y / maxIntensity * 100 >= thresholdValue); - const sortedPeaks = [...filtered].sort((a, b) => { - if (isAscend) { - return parseFloat(a.x) - parseFloat(b.x); - } - return parseFloat(b.x) - parseFloat(a.x); - }); - const label = polarityLabel ? `${polarityLabel}ESI` : 'ESI'; - if (result) { - result += '\n\n'; - } - const rtPage = tic?.currentPageValue; - const rtDecimal = Math.max(resolvedDecimal, 3); - const rtPart = Number.isFinite(rtPage) ? `RT ${fixDigit(rtPage, rtDecimal)} min, ` : ''; - result += `MS (${label}), ${rtPart}m/z (≥${thresholdValue}%):\n`; - const lines = sortedPeaks.map(peak => { - const mass = fixDigit(peak.x, resolvedDecimal); - const percent = Math.round(peak.y / maxIntensity * 100); - return `${mass} (${percent}%)`; - }); - result += ` ${lines.join(', ')}`; - } else { - if (result) { - result += '\n\n'; - } - result += 'MS: No data for current retention time.\n'; - } - } - return result; -}; const formatedMS = (peaks, maxY, decimal = 2, isAscend = true) => { const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b); const descendFunc = (a, b) => parseFloat(b) - parseFloat(a); @@ -541,8 +365,7 @@ const peaksBody = ({ integration, atIndex = 0, waveLength, - temperature, - hplcMsSt = null + temperature }) => { const result = rmShiftFromPeaks(peaks, shift, atIndex); const ascendFunc = (a, b) => parseFloat(a.x) - parseFloat(b.x); @@ -550,9 +373,6 @@ const peaksBody = ({ 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.LC_MS) { - return formatedLCMS(hplcMsSt, isAscend, decimal); - } if (layout === _list_layout.LIST_LAYOUT.MS) { return formatedMS(ordered, maxY, decimal, isAscend); } @@ -625,7 +445,6 @@ const isCyclicVoltaLayout = layoutSt => _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMME 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 isLCMsLayout = layoutSt => _list_layout.LIST_LAYOUT.LC_MS === 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; @@ -790,7 +609,6 @@ const inlineNotation = (layout, data, sampleName = '') => { }; const Format = { toPeakStr, - extractUvvisLcmsPeaks, buildData, spectraDigit, spectraOps, @@ -820,9 +638,7 @@ const Format = { isDLSIntensityLayout, isEmWaveLayout, isGCLayout, - isLCMsLayout, fixDigit, - clampDecimalPlaces, formatPeaksByPrediction, formatedMS, formatedEm, @@ -835,7 +651,6 @@ const Format = { strNumberFixedDecimal, formatedXRD, strNumberFixedLength, - inlineNotation, - formatedLCMS + inlineNotation }; var _default = exports.default = Format; \ No newline at end of file diff --git a/dist/helpers/init.js b/dist/helpers/init.js index 436c87bf..494047e6 100644 --- a/dist/helpers/init.js +++ b/dist/helpers/init.js @@ -55,33 +55,13 @@ const tpDiv = (d, digits, yFactor = 1) => ` y: ${d3.format('.2~e')(d.y * (yFactor || 1))}
`; -const msPeakTpDiv = (d, relInt, digits) => ` -
- ${_format.default.fixDigit(d.x, digits)} (${relInt}) -
- `; -const resolveDigits = (layout, xDigits) => xDigits != null && xDigits !== '' ? _format.default.clampDecimalPlaces(xDigits, _format.default.spectraDigit(layout)) : _format.default.spectraDigit(layout); -const peakTipHtml = ({ - d, - layout, - yFactor, - xDigits, - msMaxY -}) => { - const digits = resolveDigits(layout, xDigits); - if (_format.default.isMsLayout(layout) && msMaxY > 0) { - const relPct = 100 * d.y / msMaxY; - const rel = parseInt(relPct, 10); - return msPeakTpDiv(d, rel, digits); - } - return tpDiv(d, digits, yFactor || 1); -}; const InitTip = () => { d3.select('.peak-tp').remove(); - const tip = (0, _d3Tip.default)().attr('class', 'd3-tip').html(peakTipHtml); + 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 index 8c1fac82..3be92276 100644 --- a/dist/helpers/integration.js +++ b/dist/helpers/integration.js @@ -3,12 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.splitAreaProportionally = exports.normalizeSplitLines = exports.getVisualSplitGroups = exports.getVisualSplitGroupBoundaries = exports.getSplitAreas = exports.getLinearBaseline = exports.getIntegrationPoints = exports.getArea = exports.getAbsoluteAreaWithBaseline = exports.getAbsoluteArea = exports.generateVisualSplitGroupId = exports.calcArea = exports.buildSplitIntervals = void 0; +exports.getArea = exports.getAbsoluteArea = exports.calcArea = void 0; var _calc = require("./calc"); /* eslint-disable no-mixed-operators */ const getArea = (xL, xU, data) => { - if (!Array.isArray(data) || data.length === 0) return NaN; let [iL, iU] = [data.length - 1, 0]; for (let i = 0; i < data.length; i += 1) { const pt = data[i]; @@ -24,68 +23,27 @@ const getArea = (xL, xU, data) => { return Math.abs(data[iU].k - data[iL].k); }; exports.getArea = getArea; -const getIntegrationPoints = (xL, xU, data) => { - if (!Array.isArray(data)) return []; - return 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 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); -}; -exports.normalizeSplitLines = normalizeSplitLines; -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 - })); -}; -exports.buildSplitIntervals = buildSplitIntervals; -const getAbsoluteAreaWithBaseline = (xL, xU, data, baselineY) => { - const ps = getIntegrationPoints(xL, xU, data); - if (ps.length < 2 || typeof baselineY !== 'function') return 0; +const getAbsoluteArea = (xL, xU, data) => { + const ps = data.filter(d => d.x > xL && d.x < xU); + if (!ps[0]) 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); + const point1 = ps[0]; + const point2 = ps[ps.length - 1]; + const slope = (0, _calc.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); + area += delta; } } return area; }; -exports.getAbsoluteAreaWithBaseline = getAbsoluteAreaWithBaseline; -const getAbsoluteArea = (xL, xU, data) => { - const points = getIntegrationPoints(xL, xU, data); - const baselineY = getLinearBaseline(points); - return getAbsoluteAreaWithBaseline(xL, xU, data, baselineY); -}; exports.getAbsoluteArea = getAbsoluteArea; -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) - })); -}; -exports.getSplitAreas = getSplitAreas; const calcArea = (d, refArea, refFactor, ignoreRef = false) => { if (ignoreRef) { const { @@ -95,77 +53,6 @@ const calcArea = (d, refArea, refFactor, ignoreRef = false) => { } return (d.area * refFactor / refArea).toFixed(2); }; -exports.calcArea = calcArea; -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 - }; -}; -exports.splitAreaProportionally = splitAreaProportionally; -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}`; -}; -exports.generateVisualSplitGroupId = generateVisualSplitGroupId; -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; -}; -exports.getVisualSplitGroups = getVisualSplitGroups; -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; -}; // eslint-disable-line -exports.getVisualSplitGroupBoundaries = getVisualSplitGroupBoundaries; \ No newline at end of file +exports.calcArea = calcArea; \ No newline at end of file diff --git a/dist/helpers/mount.js b/dist/helpers/mount.js index b1ca522b..5f1bb693 100644 --- a/dist/helpers/mount.js +++ b/dist/helpers/mount.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.MountThresLine = exports.MountTags = exports.MountRef = exports.MountPath = exports.MountMarker = exports.MountMainFrame = exports.MountGrid = exports.MountGraphLabel = exports.MountComparePath = exports.MountClip = exports.MountBars = exports.MountAxisLabelY = exports.MountAxisLabelX = exports.MountAxis = void 0; +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)'); @@ -17,7 +17,6 @@ const MountTags = target => { 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 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, @@ -31,7 +30,6 @@ const MountTags = target => { mpyt2Path, mpypPath, aucPath, - visualSplitPath, peckerPath // eslint-disable-line }; }; @@ -93,11 +91,6 @@ const MountAxisLabelY = target => { 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 MountGraphLabel = target => { - const xTrans = `translate(${target.w / 2}, ${20})`; - target.root.append('text').attr('text-anchor', 'middle').attr('transform', xTrans).attr('class', 'mark-text').attr('font-family', 'Helvetica').style('font-size', '12px'); -}; -exports.MountGraphLabel = MountGraphLabel; const MountMarker = (target, color) => { const tTrans = `translate(${target.w - 80}, -10)`; const lTrans = `translate(${target.w - 200}, -18)`; diff --git a/dist/index.js b/dist/index.js index ac438caa..88f8ad09 100644 --- a/dist/index.js +++ b/dist/index.js @@ -6,8 +6,6 @@ var _reactDom = _interopRequireDefault(require("react-dom")); var _material = require("@mui/material"); var _reactQuill = _interopRequireDefault(require("react-quill")); var _app = require("./app"); -var _extractEntityLCMS = require("./helpers/extractEntityLCMS"); -var _utils = require("./reducers/reducer_hplc_ms/utils"); 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")); @@ -21,14 +19,6 @@ var _compare_ir_1_jcamp = _interopRequireDefault(require("./__tests__/fixtures/c 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 _lc_ms_jcamp = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp")); -var _lc_ms_jcamp_ = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_2")); -var _lc_ms_jcamp_tic_pos = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_tic_pos")); -var _lc_ms_jcamp_tic_neg = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_tic_neg")); -var _lc_ms_jcamp_uvvis = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_uvvis")); -var _lc_ms_jcamp_tic_chemstation = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_tic_chemstation")); -var _lc_ms_jcamp_mz_chemstation = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_mz_chemstation")); -var _lc_ms_jcamp_uvvis_chemstation = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_uvvis_chemstation")); 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")); @@ -92,14 +82,6 @@ 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 lcmsEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp.default); -const lcmsEntity2 = _app.FN.ExtractJcamp(_lc_ms_jcamp_.default); -const hplcMsTicPosEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_tic_pos.default); -const hplcMsTicNegEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_tic_neg.default); -const hplcMsUvvisEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_uvvis.default); -const hplcMsTicChemstationEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_tic_chemstation.default); -const hplcMsMzChemstationEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_mz_chemstation.default); -const hplcMsUvvisChemstationEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_uvvis_chemstation.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); @@ -124,140 +106,6 @@ 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); -const cloneData = value => JSON.parse(JSON.stringify(value)); -const parseNumericPage = feature => { - const candidates = [feature?.pageValue, feature?.page, feature?.pageSymbol]; - for (let i = 0; i < candidates.length; i += 1) { - const raw = candidates[i]; - if (raw != null) { - if (typeof raw === 'number' && Number.isFinite(raw)) return raw; - const text = String(raw).split('\n')[0].trim(); - const match = text.match(/[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/); - if (match) { - const value = Number(match[0]); - if (Number.isFinite(value)) return value; - } - } - } - return null; -}; -const getCurveFeatures = curve => { - if (Array.isArray(curve?.features)) return curve.features; - if (curve?.features && typeof curve.features === 'object') { - return Object.values(curve.features); - } - return []; -}; -const selectClosestMsFeature = (retentionTime, polarity) => { - const featurePool = [...getCurveFeatures(lcmsEntity).map(feature => ({ - curve: lcmsEntity, - feature - })), ...getCurveFeatures(lcmsEntity2).map(feature => ({ - curve: lcmsEntity2, - feature - }))].filter(entry => Number.isFinite(parseNumericPage(entry.feature))); - if (featurePool.length === 0) return null; - const normalizedPolarity = polarity ? String(polarity).toLowerCase() : null; - const filteredPool = normalizedPolarity ? featurePool.filter(entry => (0, _extractEntityLCMS.getLcMsInfo)(entry.curve).polarity === normalizedPolarity) : featurePool; - const pool = filteredPool.length > 0 ? filteredPool : featurePool; - if (pool.length === 0) return null; - if (!Number.isFinite(retentionTime)) return pool[0]; - return pool.reduce((best, entry) => { - const bestRt = parseNumericPage(best.feature); - const currentRt = parseNumericPage(entry.feature); - if (!Number.isFinite(bestRt)) return entry; - if (!Number.isFinite(currentRt)) return best; - return Math.abs(currentRt - retentionTime) < Math.abs(bestRt - retentionTime) ? entry : best; - }, pool[0]); -}; -const buildLcmsStandaloneMultiEntities = (retentionTime, polarity) => { - const selected = selectClosestMsFeature(retentionTime, polarity); - const selectedMsCurve = selected?.curve || lcmsEntity; - const allFeatures = getCurveFeatures(selectedMsCurve); - const msCurve = cloneData(selectedMsCurve); - const spectrArr = Array.isArray(msCurve.spectra) ? msCurve.spectra : []; - const nFeat = allFeatures.length; - const nSpec = spectrArr.length; - const primaryIdx = selected?.feature != null && allFeatures.indexOf(selected.feature) >= 0 ? allFeatures.indexOf(selected.feature) : 0; - let rawLen = Math.min(nFeat, nSpec); - if (primaryIdx >= rawLen) { - rawLen = Math.min(primaryIdx + 1, nFeat, nSpec); - } - const safePrimary = Math.min(primaryIdx, Math.max(0, rawLen - 1)); - const allIndices = Array.from({ - length: rawLen - }, (_, i) => i); - const orderedIdx = [safePrimary, ...allIndices.filter(i => i !== safePrimary)]; - msCurve.features = orderedIdx.map(i => cloneData(allFeatures[i])); - msCurve.spectra = orderedIdx.map(i => cloneData(spectrArr[i])); - const multi = [cloneData(hplcMsTicPosEntity), cloneData(hplcMsTicNegEntity), cloneData(hplcMsUvvisEntity), msCurve]; - const pol = polarity ? String(polarity).toLowerCase() : 'positive'; - const ticEntityForPolarity = pol === 'negative' ? multi[1] : multi[0]; - const ticXs = ticEntityForPolarity?.features?.[0]?.data?.[0]?.x || []; - const rtNum = Number.isFinite(retentionTime) ? retentionTime : parseNumericPage({ - pageValue: retentionTime, - page: retentionTime, - pageSymbol: retentionTime - }); - const snapped = Array.isArray(ticXs) && ticXs.length > 0 && Number.isFinite(rtNum) ? (0, _utils.snapRtToAxis)(rtNum, ticXs) : null; - if (snapped != null && Number.isFinite(snapped)) { - if (msCurve.features[0]) { - msCurve.features[0].pageValue = snapped; - msCurve.features[0].page = String(snapped); - msCurve.features[0].pageSymbol = String(snapped); - } - if (msCurve.spectra?.[0]) { - msCurve.spectra[0].pageValue = snapped; - msCurve.spectra[0].page = String(snapped); - msCurve.spectra[0].pageSymbol = String(snapped); - } - } - return multi; -}; -const getInitialLcmsRetentionTime = () => { - const ticX = hplcMsTicPosEntity?.features?.[0]?.data?.[0]?.x; - return Array.isArray(ticX) && Number.isFinite(ticX[0]) ? ticX[0] : null; -}; -const selectClosestChemstationMzFeature = retentionTime => { - const allFeatures = getCurveFeatures(hplcMsMzChemstationEntity); - if (allFeatures.length === 0) return null; - if (!Number.isFinite(retentionTime)) return allFeatures[0]; - return allFeatures.reduce((best, feature) => { - const bestRt = parseNumericPage(best); - const currentRt = parseNumericPage(feature); - if (!Number.isFinite(bestRt)) return feature; - if (!Number.isFinite(currentRt)) return best; - return Math.abs(currentRt - retentionTime) < Math.abs(bestRt - retentionTime) ? feature : best; - }, allFeatures[0]); -}; -const buildChemstationStandaloneMultiEntities = retentionTime => { - const allFeatures = getCurveFeatures(hplcMsMzChemstationEntity); - const selectedFeature = selectClosestChemstationMzFeature(retentionTime); - const featureIdx = selectedFeature != null && allFeatures.indexOf(selectedFeature) >= 0 ? allFeatures.indexOf(selectedFeature) : 0; - const msCurve = cloneData(hplcMsMzChemstationEntity); - const spectrArr = Array.isArray(msCurve.spectra) ? msCurve.spectra : []; - const safeIdx = Math.min(featureIdx, Math.max(allFeatures.length - 1, 0)); - msCurve.features = [cloneData(allFeatures[safeIdx])]; - msCurve.spectra = spectrArr[safeIdx] ? [cloneData(spectrArr[safeIdx])] : [cloneData(allFeatures[safeIdx])]; - const ticXs = hplcMsTicChemstationEntity?.features?.[0]?.data?.[0]?.x || []; - const rtNum = Number.isFinite(retentionTime) ? retentionTime : parseNumericPage(msCurve.features[0]); - const snapped = Array.isArray(ticXs) && ticXs.length > 0 && Number.isFinite(rtNum) ? (0, _utils.snapRtToAxis)(rtNum, ticXs) : null; - if (snapped != null && Number.isFinite(snapped)) { - msCurve.features[0].pageValue = snapped; - msCurve.features[0].page = String(snapped); - msCurve.features[0].pageSymbol = String(snapped); - if (msCurve.spectra[0]) { - msCurve.spectra[0].pageValue = snapped; - msCurve.spectra[0].page = String(snapped); - msCurve.spectra[0].pageSymbol = String(snapped); - } - } - return [cloneData(hplcMsTicChemstationEntity), msCurve, cloneData(hplcMsUvvisChemstationEntity)]; -}; -const getInitialChemstationRetentionTime = () => { - const ticX = hplcMsTicChemstationEntity?.features?.[0]?.data?.[0]?.x; - return Array.isArray(ticX) && Number.isFinite(ticX[0]) ? ticX[0] : null; -}; class DemoWriteIr extends _react.default.Component { constructor(props) { super(props); @@ -267,9 +115,7 @@ class DemoWriteIr extends _react.default.Component { predictions: false, molecule: '', showOthers: false, - descChanged: '', - lcmsDynamicMultiEntities: null, - lcmsChemstationDynamicMultiEntities: null + descChanged: '' }; this.onClick = this.onClick.bind(this); this.writeMpy = this.writeMpy.bind(this); @@ -285,8 +131,16 @@ class DemoWriteIr extends _react.default.Component { this.loadOthers = this.loadOthers.bind(this); this.onDescriptionChanged = this.onDescriptionChanged.bind(this); this.loadMultiEntities = this.loadMultiEntities.bind(this); - this.handleLcmsPageRequest = this.handleLcmsPageRequest.bind(this); - this.lcmsRequestCounter = 0; + } + onClick(typ) { + return () => { + this.setState({ + typ, + desc: '', + predictions: false, + molecule: '' + }); + }; } onShowOthers(jcamp) { // eslint-disable-line @@ -300,82 +154,6 @@ class DemoWriteIr extends _react.default.Component { descChanged: content }); } - componentDidUpdate(_prevProps, prevState) { - const { - typ - } = this.state; - const { - typ: prevTyp - } = prevState; - if (typ === 'lcms' && prevTyp !== 'lcms') { - const initialRt = getInitialLcmsRetentionTime(); - this.handleLcmsPageRequest({ - retentionTime: initialRt, - polarity: 'positive', - trigger: 'initial_load' - }); - } - if (typ === 'lcms chemstation' && prevTyp !== 'lcms chemstation') { - const initialRt = getInitialChemstationRetentionTime(); - this.handleLcmsPageRequest({ - retentionTime: initialRt, - polarity: 'positive', - trigger: 'initial_load' - }); - } - } - handleLcmsPageRequest(request) { - const { - typ - } = this.state; - if (typ !== 'lcms' && typ !== 'lcms chemstation') return; - const retentionTime = request?.retentionTime; - const polarity = request?.polarity; - const trigger = request?.trigger || 'unknown'; - this.lcmsRequestCounter += 1; - const requestId = this.lcmsRequestCounter; - if (typeof window !== 'undefined') { - // eslint-disable-next-line no-underscore-dangle - const history = Array.isArray(window.__lcmsDemoRequests) ? window.__lcmsDemoRequests : []; - history.push({ - requestId, - retentionTime, - polarity, - trigger, - createdAt: Date.now() - }); - // eslint-disable-next-line no-underscore-dangle - window.__lcmsDemoRequests = history; - } - setTimeout(() => { - if (requestId !== this.lcmsRequestCounter) return; - if (typ === 'lcms chemstation') { - this.setState({ - lcmsChemstationDynamicMultiEntities: buildChemstationStandaloneMultiEntities(retentionTime) - }); - return; - } - this.setState({ - lcmsDynamicMultiEntities: buildLcmsStandaloneMultiEntities(retentionTime, polarity) - }); - }, 250); - } - onClick(typ) { - return () => { - const isLcms = typ === 'lcms'; - const isChemstation = typ === 'lcms chemstation'; - const initialRt = getInitialLcmsRetentionTime(); - const initialChemstationRt = getInitialChemstationRetentionTime(); - this.setState({ - typ, - desc: '', - predictions: false, - molecule: '', - lcmsDynamicMultiEntities: isLcms ? buildLcmsStandaloneMultiEntities(initialRt) : null, - lcmsChemstationDynamicMultiEntities: isChemstation ? buildChemstationStandaloneMultiEntities(initialChemstationRt) : null - }); - }; - } loadEntity() { const { typ @@ -426,22 +204,14 @@ class DemoWriteIr extends _react.default.Component { case 'gc': return gcEntity1; case 'ms': - return msEntity; - case 'lcms': - return lcmsEntity; - case 'lcms chemstation': - return hplcMsUvvisChemstationEntity; default: return msEntity; } } loadMultiEntities() { const { - typ, - lcmsDynamicMultiEntities, - lcmsChemstationDynamicMultiEntities + typ } = this.state; - const chemstationMultiEntities = lcmsChemstationDynamicMultiEntities || buildChemstationStandaloneMultiEntities(getInitialChemstationRetentionTime()); switch (typ) { case 'cyclic volta': return [cyclicVoltaEntity1, cyclicVoltaEntity2, cyclicVoltaEntity3]; @@ -459,12 +229,8 @@ class DemoWriteIr extends _react.default.Component { return [aifEntity1, aifEntity2]; case 'gc': return [gcEntity1, gcEntity2, gcEntity3]; - case 'lcms': - return lcmsDynamicMultiEntities || buildLcmsStandaloneMultiEntities(getInitialLcmsRetentionTime()); - case 'lcms chemstation': - return chemstationMultiEntities; default: - return []; + return false; } } loadQuill() { @@ -491,8 +257,6 @@ class DemoWriteIr extends _react.default.Component { case 'dsc': case 'xrd': case 'ms': - case 'lcms': - case 'lcms chemstation': case 'cyclic volta': case 'cds': case 'sec': @@ -560,8 +324,7 @@ class DemoWriteIr extends _react.default.Component { boundary, integration, waveLength, - temperature, - hplcMsSt: _app.store.getState().hplcMs + temperature }); const wrapper = _app.FN.peaksWrapper(safeLayout, shiftForFormatting); let desc = this.rmDollarSign(wrapper.head) + body + wrapper.tail; @@ -729,7 +492,10 @@ class DemoWriteIr extends _react.default.Component { shift, isAscend, decimal, + analysis, isIntensity, + integration, + multiplicity, waveLength } = pickSelectedSpectrumFromPayload(payload); const entity = this.loadEntity(); @@ -758,20 +524,18 @@ class DemoWriteIr extends _react.default.Component { isIntensity, boundary, waveLength, - temperature, - hplcMsSt: _app.store.getState().hplcMs + temperature }); /*eslint-disable */ - let message = `Peaks: ${body}\n`; + console.log(analysis); + console.log(integration); + console.log(multiplicity); if (shift?.ref?.label) { const label = this.rmDollarSign(shift.ref.label); - message += '- - - - - - - - - - -\n'; - message += `Shift solvent = ${label}, ${shift.ref.value}ppm\n`; + alert(`Peaks: ${body}` + '\n' + '- - - - - - - - - - -' + '\n' + `Shift solvent = ${label}, ${shift.ref.value}ppm` + '\n'); + } else { + alert(`Peaks: ${body}` + '\n'); } - console.info(message); // eslint-disable-line no-console - this.setState({ - desc: message - }); /*eslint-disable */ } predictOp({ @@ -844,9 +608,7 @@ class DemoWriteIr extends _react.default.Component { value: this.writeMpy }, ...operations]; } - const refreshCb = () => { - console.info('Refresh simulation requested.'); // eslint-disable-line no-console - }; + const refreshCb = () => alert('Refresch simulation!'); const forecast = { btnCb: this.predictOp, refreshCb, @@ -1034,20 +796,6 @@ class DemoWriteIr extends _react.default.Component { }, onClick: this.onClick('ms'), children: "MS" - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, { - variant: "contained", - style: { - margin: '0 10px 0 10px' - }, - onClick: this.onClick('lcms'), - children: "LC/MS OpenLab" - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, { - variant: "contained", - style: { - margin: '0 10px 0 10px' - }, - onClick: this.onClick('lcms chemstation'), - children: "LC/MS Chemstation" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, { variant: "contained", style: { @@ -1080,7 +828,6 @@ class DemoWriteIr extends _react.default.Component { }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_app.SpectraEditor, { entity: entity, multiEntities: multiEntities, - onLcmsPageRequest: this.handleLcmsPageRequest, others: others, editorOnly: false, descriptions: desc, @@ -1127,9 +874,4 @@ class DemoWriteIr extends _react.default.Component { } // - - - DOM - - - -_reactDom.default.render(/*#__PURE__*/(0, _jsxRuntime.jsx)(DemoWriteIr, {}), document.getElementById('root')); -if (typeof window !== 'undefined') { - window.__spectraStore = _app.store; - // eslint-disable-next-line no-underscore-dangle - window.__lcmsDemoRequests = []; -} \ No newline at end of file +_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 index 7192e375..56a2fb51 100644 --- a/dist/layer_content.js +++ b/dist/layer_content.js @@ -17,11 +17,9 @@ var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, default-param-last, react/function-component-definition */ const extractLayout = (forecast, layoutSt) => { - const safeForecast = forecast && typeof forecast === 'object' ? forecast : {}; - const isEmpty = Object.keys(safeForecast).length === 0 && safeForecast.constructor === Object; + const isEmpty = Object.keys(forecast).length === 0 && forecast.constructor === Object; const isNmr = _format.default.isNmrLayout(layoutSt); const isMs = _format.default.isMsLayout(layoutSt); - const isLCMs = _format.default.isLCMsLayout(layoutSt); const isIr = _format.default.isIrLayout(layoutSt); const isUvvis = _format.default.isUvVisLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt); const isXRD = _format.default.isXRDLayout(layoutSt); @@ -32,8 +30,7 @@ const extractLayout = (forecast, layoutSt) => { isIr, isMs, isUvvis, - isXRD, - isLCMs + isXRD }; }; const Content = ({ @@ -52,8 +49,7 @@ const Content = ({ isIr, isMs, isUvvis, - isXRD, - isLCMs + isXRD } = extractLayout(forecast, layoutSt); if (showForecast) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_forecast_viewer.default, { @@ -80,16 +76,6 @@ const Content = ({ isHidden: false }); } - if (isLCMs) { - 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, diff --git a/dist/layer_init.js b/dist/layer_init.js index 17fd8df5..3df80431 100644 --- a/dist/layer_init.js +++ b/dist/layer_init.js @@ -11,34 +11,18 @@ var _reactRedux = require("react-redux"); var _redux = require("redux"); var _styles = require("@mui/styles"); var _submit = require("./actions/submit"); -var _layout = require("./actions/layout"); 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 _extractEntityLCMS = require("./helpers/extractEntityLCMS"); var _multi_jcamps_viewer = _interopRequireDefault(require("./components/multi_jcamps_viewer")); -var _hplc_viewer = _interopRequireDefault(require("./components/hplc_viewer")); var _curve = require("./actions/curve"); -var _hplc_ms = require("./actions/hplc_ms"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, default-param-last */ const styles = () => ({}); class LayerInit extends _react.default.Component { - static entitySignature(e) { - if (!e) return 'none'; - const id = e.idDt ?? e.id ?? e.datasetId; - if (id != null && id !== '') return `id:${id}`; - const firstFeature = (Array.isArray(e.features) ? e.features[0] : null) || (Array.isArray(e.spectra) ? e.spectra[0] : null) || null; - const data0 = firstFeature?.data?.[0]; - const xs = data0?.x; - const xLen = Array.isArray(xs) ? xs.length : 0; - const xHead = Array.isArray(xs) && xs.length > 0 ? xs[0] : ''; - const xTail = Array.isArray(xs) && xs.length > 0 ? xs[xs.length - 1] : ''; - return `sig:${e.layout || ''}|${e.title || ''}|${xLen}|${xHead}|${xTail}`; - } constructor(props) { super(props); this.normChange = this.normChange.bind(this); @@ -54,40 +38,15 @@ class LayerInit extends _react.default.Component { this.updateMultiEntities(); } componentDidUpdate(prevProps) { - const { - others, - multiEntities, - entity, - operations - } = this.props; this.normChange(prevProps); - if (prevProps.operations !== operations || prevProps.entity !== entity) { - this.initReducer(); - } - if (prevProps.others !== others) { - this.updateOthers(); - } - if (prevProps.multiEntities !== multiEntities || prevProps.entity !== entity) { - this.updateMultiEntities(); - } + this.updateOthers(); + this.updateMultiEntities(); } normChange(prevProps) { const { - entity, - multiEntities, - clearHplcMsStateAct + entity } = this.props; if (prevProps.entity !== entity) { - const prevIsLcms = _format.default.isLCMsLayout(prevProps.entity?.layout); - const nextIsLcms = _format.default.isLCMsLayout(entity?.layout); - const lcmsSessionActive = prevIsLcms && nextIsLcms && Array.isArray(multiEntities) && (0, _extractEntityLCMS.isLcMsGroup)(multiEntities); - if ((prevIsLcms || nextIsLcms) && !lcmsSessionActive) { - const prevSig = LayerInit.entitySignature(prevProps.entity); - const nextSig = LayerInit.entitySignature(entity); - if (prevSig !== nextSig) { - clearHplcMsStateAct(); - } - } this.execReset(); } } @@ -101,17 +60,14 @@ class LayerInit extends _react.default.Component { resetInitCommonWithIntergationAct, resetDetectorAct, updateDSCMetaDataAct, - resetMultiplicityAct, - updateLayoutAct + resetMultiplicityAct } = this.props; - if (!entity || !entity.layout) return; resetInitCommonAct(); resetDetectorAct(); const { layout, - features = {} + features } = entity; - updateLayoutAct(layout); if (_format.default.isMsLayout(layout)) { // const { autoPeak, editPeak } = features; // TBD const autoPeak = features.autoPeak || features[0]; @@ -152,18 +108,14 @@ class LayerInit extends _react.default.Component { operations, updateOperationAct } = this.props; - if (Array.isArray(operations) && operations.length > 0) { - updateOperationAct(operations[0]); - } + updateOperationAct(operations[0]); } updateOthers() { const { others, addOthersAct } = this.props; - if (others) { - addOthersAct(others); - } + addOthersAct(others); } updateMultiEntities() { const { @@ -171,37 +123,9 @@ class LayerInit extends _react.default.Component { setAllCurvesAct, entity } = this.props; - if (!entity || !entity.layout) return; - const lcmsCurveMeta = () => { - const uvvisFromMulti = Array.isArray(multiEntities) ? multiEntities.find(e => (0, _extractEntityLCMS.getLcMsInfo)(e).kind === 'uvvis') : null; - const mzFromMulti = Array.isArray(multiEntities) ? multiEntities.find(e => (0, _extractEntityLCMS.getLcMsInfo)(e).kind === 'mz') : null; - const idDt = uvvisFromMulti?.idDt ?? uvvisFromMulti?.id ?? uvvisFromMulti?.datasetId ?? entity?.idDt ?? entity?.id ?? entity?.datasetId ?? null; - const lcmsUvvisWavelength = entity?.lcms_uvvis_wavelength ?? entity?.lcmsUvvisWavelength ?? uvvisFromMulti?.lcms_uvvis_wavelength ?? uvvisFromMulti?.lcmsUvvisWavelength; - const lcmsMzPage = entity?.lcms_mz_page ?? entity?.lcmsMzPage ?? mzFromMulti?.lcms_mz_page ?? mzFromMulti?.lcmsMzPage ?? uvvisFromMulti?.lcms_mz_page ?? uvvisFromMulti?.lcmsMzPage; - const mzInfo = mzFromMulti ? (0, _extractEntityLCMS.getLcMsInfo)(mzFromMulti) : null; - const lcmsPolarity = entity?.lcms_polarity ?? entity?.lcmsPolarity ?? entity?.ticPolarity ?? mzFromMulti?.lcms_polarity ?? mzFromMulti?.lcmsPolarity ?? (mzInfo?.kind === 'mz' ? mzInfo.polarity : null); - const out = {}; - if (idDt != null) out.idDt = idDt; - if (lcmsUvvisWavelength != null && lcmsUvvisWavelength !== '') { - out.lcmsUvvisWavelength = lcmsUvvisWavelength; - } - if (lcmsMzPage != null && lcmsMzPage !== '') { - out.lcmsMzPage = lcmsMzPage; - } - if (lcmsPolarity != null && lcmsPolarity !== '') { - out.lcmsPolarity = lcmsPolarity; - } - return Object.keys(out).length ? out : undefined; - }; const isMultiSpectra = Array.isArray(multiEntities) && multiEntities.length > 1; if (isMultiSpectra) { - const meta = _format.default.isLCMsLayout(entity.layout) ? lcmsCurveMeta() : undefined; - setAllCurvesAct(multiEntities, meta); - return; - } - if (_format.default.isLCMsLayout(entity.layout)) { - const payload = Array.isArray(multiEntities) && multiEntities.length > 0 ? multiEntities : [entity]; - setAllCurvesAct(payload, lcmsCurveMeta()); + setAllCurvesAct(multiEntities); return; } if (_format.default.isCyclicVoltaLayout(entity.layout)) { @@ -227,35 +151,15 @@ class LayerInit extends _react.default.Component { onDescriptionChanged, multiEntities, entityFileNames, - userManualLink, - onLcmsPageRequest + userManualLink } = this.props; + const target = entity.spectra[0]; const { layout } = entity; - const hasMultiEntities = Array.isArray(multiEntities) && multiEntities.length > 0; - const hasLcmsEntity = hasMultiEntities && multiEntities.some(multiEntity => _format.default.isLCMsLayout(multiEntity?.layout)); - const isDetectedLcmsGroup = hasLcmsEntity && (0, _extractEntityLCMS.isLcMsGroup)(multiEntities); - // For multi mode, trust multiEntities over single entity to avoid mixed-layout misrouting. - const isLcms = hasMultiEntities ? isDetectedLcmsGroup : _format.default.isLCMsLayout(layout); - const target = isLcms ? null : entity.spectra && Array.isArray(entity.spectra) && entity.spectra[0] || null; - const xxLabel = !xLabel && xLabel === '' && target && target.xUnit ? `X (${target.xUnit})` : xLabel; - const yyLabel = !yLabel && yLabel === '' && target && target.yUnit ? `Y (${target.yUnit})` : yLabel; + 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 (isLcms) { - return /*#__PURE__*/(0, _jsxRuntime.jsx)(_hplc_viewer.default, { - entityFileNames: entityFileNames, - userManualLink: userManualLink, - molSvg: molSvg, - forecast: forecast, - operations: operations, - descriptions: descriptions, - canChangeDescription: canChangeDescription, - onDescriptionChanged: onDescriptionChanged, - editorOnly: editorOnly, - onLcmsPageRequest: onLcmsPageRequest - }); - } if (isMultiSpectra) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_multi_jcamps_viewer.default, { multiEntities: multiEntities, @@ -263,8 +167,6 @@ class LayerInit extends _react.default.Component { userManualLink: userManualLink, molSvg: molSvg, exactMass: exactMass, - forecast: forecast, - editorOnly: editorOnly, operations: operations, descriptions: descriptions, canChangeDescription: canChangeDescription, @@ -278,8 +180,6 @@ class LayerInit extends _react.default.Component { userManualLink: userManualLink, molSvg: molSvg, exactMass: exactMass, - forecast: forecast, - editorOnly: editorOnly, operations: operations, descriptions: descriptions, canChangeDescription: canChangeDescription, @@ -297,8 +197,6 @@ class LayerInit extends _react.default.Component { molSvg: molSvg, editorOnly: editorOnly, exactMass: exactMass, - entityFileNames: entityFileNames, - userManualLink: userManualLink, canChangeDescription: canChangeDescription, onDescriptionChanged: onDescriptionChanged }); @@ -315,12 +213,10 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ resetDetectorAct: _manager.resetDetector, resetMultiplicityAct: _manager.resetMultiplicity, updateOperationAct: _submit.updateOperation, - updateLayoutAct: _layout.updateLayout, updateMetaPeaksAct: _meta.updateMetaPeaks, addOthersAct: _jcamp.addOthers, setAllCurvesAct: _curve.setAllCurves, - updateDSCMetaDataAct: _meta.updateDSCMetaData, - clearHplcMsStateAct: _hplc_ms.clearHplcMsState + updateDSCMetaDataAct: _meta.updateDSCMetaData }, dispatch); LayerInit.propTypes = { entity: _propTypes.default.object.isRequired, @@ -343,23 +239,17 @@ LayerInit.propTypes = { resetInitMsAct: _propTypes.default.func.isRequired, resetInitCommonWithIntergationAct: _propTypes.default.func.isRequired, updateOperationAct: _propTypes.default.func.isRequired, - updateLayoutAct: _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 - onLcmsPageRequest: _propTypes.default.func, 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, - clearHplcMsStateAct: _propTypes.default.func.isRequired -}; -LayerInit.defaultProps = { - onLcmsPageRequest: null + updateDSCMetaDataAct: _propTypes.default.func.isRequired }; var _default = exports.default = (0, _reactRedux.connect)( // eslint-disable-line diff --git a/dist/layer_prism.js b/dist/layer_prism.js index 07650926..7680524a 100644 --- a/dist/layer_prism.js +++ b/dist/layer_prism.js @@ -22,13 +22,6 @@ react/function-component-definition, react/require-default-props */ const styles = () => ({}); -const getThresholdState = state => { - const curveIdx = state?.curve?.curveIdx; - const thresholdList = state?.threshold?.list; - if (!Array.isArray(thresholdList)) return {}; - if (!Number.isInteger(curveIdx)) return thresholdList[0] || {}; - return thresholdList[curveIdx] || thresholdList[0] || {}; -}; const LayerPrism = ({ entity, cLabel, @@ -43,25 +36,16 @@ const LayerPrism = ({ thresSt, scanSt, uiSt, - curveSt, - integrationSt, canChangeDescription, - onDescriptionChanged, - entityFileNames, - userManualLink + onDescriptionChanged }) => { const { topic, feature, hasEdit, - integration: initialIntegration, - features + integration } = (0, _extractParams.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; @@ -83,7 +67,6 @@ const LayerPrism = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_content.default, { topic: topic, feature: feature, - features: features || [], cLabel: cLabel, xLabel: xLabel, yLabel: yLabel, @@ -112,7 +95,6 @@ const LayerPrism = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_content.default, { topic: topic, feature: feature, - features: features || [], cLabel: cLabel, xLabel: xLabel, yLabel: yLabel, @@ -129,8 +111,6 @@ const LayerPrism = ({ editorOnly: editorOnly, molSvg: molSvg, exactMass: exactMass, - entityFileNames: entityFileNames, - userManualLink: userManualLink, descriptions: descriptions, canChangeDescription: canChangeDescription, onDescriptionChanged: onDescriptionChanged @@ -144,10 +124,8 @@ const mapStateToProps = (state, props) => ( // eslint-disable-line { scanSt: state.scan, - thresSt: getThresholdState(state), - uiSt: state.ui, - curveSt: state.curve, - integrationSt: state.integration.present + thresSt: state.threshold.list[state.curve.curveIdx], + uiSt: state.ui }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch); LayerPrism.propTypes = { @@ -164,12 +142,8 @@ LayerPrism.propTypes = { thresSt: _propTypes.default.object.isRequired, scanSt: _propTypes.default.object.isRequired, uiSt: _propTypes.default.object.isRequired, - curveSt: _propTypes.default.object.isRequired, - integrationSt: _propTypes.default.object.isRequired, canChangeDescription: _propTypes.default.bool.isRequired, - onDescriptionChanged: _propTypes.default.func, - entityFileNames: _propTypes.default.array, - userManualLink: _propTypes.default.object + onDescriptionChanged: _propTypes.default.func }; var _default = exports.default = (0, _reactRedux.connect)( // eslint-disable-line diff --git a/dist/reducers/index.js b/dist/reducers/index.js index 6217cadb..50868a3b 100644 --- a/dist/reducers/index.js +++ b/dist/reducers/index.js @@ -26,7 +26,6 @@ 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")); -var _reducer_hplc_ms = _interopRequireDefault(require("./reducer_hplc_ms")); const rootReducer = (0, _redux.combineReducers)({ threshold: _reducer_threshold.default, editPeak: _reducer_edit_peak.default, @@ -47,7 +46,6 @@ const rootReducer = (0, _redux.combineReducers)({ cyclicvolta: _reducer_voltammetry.default, curve: _reducer_curve.default, axesUnits: _reducer_axes.default, - detector: _reducer_detector.default, - hplcMs: _reducer_hplc_ms.default + detector: _reducer_detector.default }); var _default = exports.default = rootReducer; \ No newline at end of file diff --git a/dist/reducers/reducer_curve.js b/dist/reducers/reducer_curve.js index 50cf529c..91c11de1 100644 --- a/dist/reducers/reducer_curve.js +++ b/dist/reducers/reducer_curve.js @@ -7,8 +7,6 @@ Object.defineProperty(exports, "__esModule", { exports.default = void 0; var _action_type = require("../constants/action_type"); var _extractParams = require("../helpers/extractParams"); -var _extractEntityLCMS = require("../helpers/extractEntityLCMS"); -var _list_layout = require("../constants/list_layout"); var _chem = require("../helpers/chem"); var _format = _interopRequireDefault(require("../helpers/format")); /* eslint-disable prefer-object-spread, default-param-last, max-len */ @@ -22,60 +20,44 @@ const setAllCurves = (state, action) => { const { payload } = action; - if (!payload) return { - ...state, - curveIdx: 0, - listCurves: [] - }; - const isLcmsGroup = (0, _extractEntityLCMS.isLcMsGroup)(payload); - const entities = payload.map((entity, idx) => { - const lcmsInfo = (0, _extractEntityLCMS.getLcMsInfo)(entity); - const layout = isLcmsGroup && lcmsInfo.kind !== 'unknown' ? _list_layout.LIST_LAYOUT.LC_MS : entity.layout; - const extracted = (0, _extractParams.extractParams)(entity, { - isEdit: true - }, null, { - forceLcms: isLcmsGroup && lcmsInfo.kind !== 'unknown' + 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 }); - const { - topic, - feature, - hasEdit, - integration, - multiplicity, - features, - entity: entityFromExtract, - spectra - } = extracted; - let finalFeatures = features; - if (!finalFeatures || Array.isArray(finalFeatures) && finalFeatures.length === 0) { - finalFeatures = entityFromExtract?.features || entity.features || []; - } - const maxminPeak = (0, _chem.Convert2MaxMinPeak)(layout, feature, 0); - const color = _format.default.mutiEntitiesColors(idx); - return { - layout, - lcmsKind: lcmsInfo.kind, - lcmsPolarity: lcmsInfo.polarity, - topic, - feature, - hasEdit, - integration, - multiplicity, - maxminPeak, - color, - curveIdx: idx, - features: finalFeatures, - entity: entityFromExtract || entity, - spectra: spectra || entity.spectra - }; + } + return Object.assign({}, state, { + curveIdx: 0, + listCurves: payload }); - const maxIdx = entities.length - 1; - const safeCurveIdx = Math.min(state.curveIdx || 0, maxIdx); - return { - ...state, - curveIdx: safeCurveIdx, - listCurves: entities - }; }; const curveReducer = (state = initialState, action) => { switch (action.type) { diff --git a/dist/reducers/reducer_integration.js b/dist/reducers/reducer_integration.js index 1b606355..9d25b023 100644 --- a/dist/reducers/reducer_integration.js +++ b/dist/reducers/reducer_integration.js @@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau Object.defineProperty(exports, "__esModule", { value: true }); -exports.integrationReducer = exports.default = void 0; +exports.default = void 0; var _reduxUndo = _interopRequireDefault(require("redux-undo")); var _action_type = require("../constants/action_type"); var _integration = require("../helpers/integration"); @@ -37,7 +37,7 @@ const addToStack = (state, action) => { integrations } = state; let selectedIntegration = integrations[curveIdx]; - if (!selectedIntegration) { + if (selectedIntegration === false || selectedIntegration === undefined) { selectedIntegration = defaultEmptyIntegration; } const { @@ -53,7 +53,7 @@ const addToStack = (state, action) => { xL, xU } = xExtent; - if (!Number.isFinite(xL) || !Number.isFinite(xU) || xU - xL === 0) { + if (!xL || !xU || xU - xL === 0) { return state; } const area = (0, _integration.getArea)(xL, xU, data); @@ -76,22 +76,6 @@ const addToStack = (state, action) => { 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, @@ -110,251 +94,16 @@ const rmFromStack = (state, action) => { stack } = selectedIntegration; let [txL, txU] = [0, 0]; - if (Number.isFinite(xL) && Number.isFinite(xU)) { + 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 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 = (0, _integration.splitAreaProportionally)(original.area, (0, _integration.getArea)(xL, splitX, data), (0, _integration.getArea)(splitX, xU, data)); - const absParts = (0, _integration.splitAreaProportionally)(original.absoluteArea, (0, _integration.getAbsoluteArea)(xL, splitX, data), (0, _integration.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, (0, _integration.getArea)(xL, xU, data), (0, _integration.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) { - 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 splitParts = buildSplitParts(original, xL, splitX, xU, shift, data, stack); - const [leftIntegration, rightIntegration] = splitParts; - 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) { - 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 = (0, _integration.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) { - 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 newStack = stack.filter(k => k.xL !== txL && k.xU !== txU); const newIntegration = Object.assign({}, selectedIntegration, { stack: newStack }); @@ -465,12 +214,6 @@ const integrationReducer = (state = initialState, action) => { 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.ADD_VISUAL_SPLIT: - return addVisualSplitLine(state, action); - case _action_type.INTEGRATION.RM_VISUAL_SPLIT: - return removeVisualSplitLine(state, action); case _action_type.INTEGRATION.SET_REF: return setRef(state, action); case _action_type.INTEGRATION.SET_FKR: @@ -487,6 +230,5 @@ const integrationReducer = (state = initialState, action) => { 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_layout.js b/dist/reducers/reducer_layout.js index 6b0db6e1..c264e570 100644 --- a/dist/reducers/reducer_layout.js +++ b/dist/reducers/reducer_layout.js @@ -14,7 +14,7 @@ const layoutReducer = (state = initialState, action) => { case _action_type.LAYOUT.UPDATE: return action.payload; case _action_type.MANAGER.RESETALL: - return action.payload?.operation?.layout || state; + return action.payload.operation.layout; default: return state; } diff --git a/dist/reducers/reducer_submit.js b/dist/reducers/reducer_submit.js index 7d166344..6fc47bf8 100644 --- a/dist/reducers/reducer_submit.js +++ b/dist/reducers/reducer_submit.js @@ -45,8 +45,7 @@ const submitReducer = (state = initialState, action) => { } case _action_type.MANAGER.RESETALL: { - const layout = action.payload?.operation?.layout; - const decimal = layout ? _format.default.spectraDigit(layout) : state.decimal; + const decimal = _format.default.spectraDigit(action.payload.operation.layout); return Object.assign({}, state, { decimal, isIntensity: true, diff --git a/dist/reducers/reducer_threshold.js b/dist/reducers/reducer_threshold.js index 7fc7f727..72737d40 100644 --- a/dist/reducers/reducer_threshold.js +++ b/dist/reducers/reducer_threshold.js @@ -16,14 +16,12 @@ const initialState = { lower: false }] }; - -// const defaultThresHold = { -// isEdit: true, -// value: false, -// upper: false, -// lower: false, -// }; - +const defaultThresHold = { + isEdit: true, + value: false, + upper: false, + lower: false +}; const setThresHoldValue = (state, action) => { const { payload @@ -126,12 +124,16 @@ const setThresHoldLower = (state, action) => { list: newListThres }); }; -const setThresHoldIsEdit = state => { +const setThresHoldIsEdit = (state, action) => { + const { + payload + } = action; const { list, selectedIdx } = state; - const selectedThres = list[selectedIdx]; + const curveIdx = payload && payload.curveIdx !== undefined ? payload.curveIdx : selectedIdx; + const selectedThres = list[curveIdx] || defaultThresHold; const { isEdit } = selectedThres; @@ -139,9 +141,10 @@ const setThresHoldIsEdit = state => { isEdit: !isEdit }); const newListThres = [...list]; - newListThres[selectedIdx] = newSelectedThres; + newListThres[curveIdx] = newSelectedThres; return Object.assign({}, state, { - list: newListThres + list: newListThres, + selectedIdx: curveIdx }); }; const resetAll = (state, action) => { @@ -151,6 +154,21 @@ const resetAll = (state, action) => { const { list } = state; + if (payload && payload.curveIdx !== undefined) { + const { + curveIdx + } = payload; + const selectedThres = list[curveIdx] || defaultThresHold; + const newSelectedThres = Object.assign({}, selectedThres, { + value: payload.thresRef + }); + const newListThres = [...list]; + newListThres[curveIdx] = newSelectedThres; + return Object.assign({}, state, { + selectedIdx: curveIdx, + list: newListThres + }); + } const newList = list.map(item => ({ isEdit: item.isEdit, value: payload && payload.thresRef, @@ -210,7 +228,7 @@ const thresholdReducer = (state = initialState, action) => { case _action_type.THRESHOLD.RESET_VALUE: return setThresHoldValue(state, action); case _action_type.THRESHOLD.TOGGLE_ISEDIT: - return setThresHoldIsEdit(state); + return setThresHoldIsEdit(state, action); case _action_type.MANAGER.RESET_INIT_COMMON: return resetInitCommon(state); case _action_type.MANAGER.RESETALL: diff --git a/dist/reducers/reducer_ui.js b/dist/reducers/reducer_ui.js index db00437d..14b7533f 100644 --- a/dist/reducers/reducer_ui.js +++ b/dist/reducers/reducer_ui.js @@ -15,137 +15,7 @@ const initialState = { xExtent: false, yExtent: false }, - jcampIdx: 0, - subViewerAt: { - x: null, - y: null - }, - zoom: { - graphIndex: 0, - sweepExtent: [{ - xExtent: false, - yExtent: false - }, { - xExtent: false, - yExtent: false - }, { - xExtent: false, - yExtent: false - }], - sweepTypes: [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET] - } -}; -const updateSweepType = (state, action) => { - const { - payload - } = action; - const { - graphIndex, - sweepType - } = payload; - if (!sweepType) { - return Object.assign({}, state, { - sweepType: action.payload, - jcampIdx: action.jcampIdx, - zoom: { - ...state.zoom, - sweepTypes: [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET] - } - }); - } - const { - zoom - } = state; - let newSweepTypes = zoom.sweepTypes.slice(); - if (sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN) { - newSweepTypes = newSweepTypes.map((val, idx) => idx === graphIndex ? _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN : _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET); - } else { - newSweepTypes = newSweepTypes.map(() => _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET); - if (graphIndex !== undefined) { - newSweepTypes[graphIndex] = sweepType; - } - } - const newZoom = Object.assign({}, zoom, { - sweepTypes: newSweepTypes, - graphIndex - }); - return Object.assign({}, state, { - zoom: newZoom, - sweepType - }); -}; -const updateZoom = (state, action) => { - const { - payload - } = action; - const { - graphIndex, - zoomValue, - lcmsSyncX - } = payload; - if (!zoomValue) { - return Object.assign({}, state, { - sweepExtent: payload - }); - } - const { - zoom - } = state; - const sweepExtent = Array.isArray(zoom.sweepExtent) ? [...zoom.sweepExtent] : []; - const selectedGraph = sweepExtent[graphIndex]; - const newSweepExtent = Object.assign({}, selectedGraph, zoomValue); - sweepExtent[graphIndex] = newSweepExtent; - if (lcmsSyncX != null && zoomValue && zoomValue.xExtent) { - const otherIdx = lcmsSyncX; - const otherGraph = sweepExtent[otherIdx] || {}; - sweepExtent[otherIdx] = Object.assign({}, otherGraph, { - xExtent: zoomValue.xExtent, - yExtent: false - }); - } - const newZoom = Object.assign({}, zoom, { - sweepExtent, - graphIndex - }); - return Object.assign({}, state, { - zoom: newZoom - }); -}; -const resetZoom = (state, action) => { - const { - payload - } = action; - const { - graphIndex - } = payload || {}; - if (graphIndex === undefined) { - return Object.assign({}, state, { - sweepExtent: { - xExtent: false, - yExtent: false - } - }); - } - const { - zoom - } = state; - const sweepExtent = Array.isArray(zoom.sweepExtent) ? [...zoom.sweepExtent] : []; - const indicesToReset = graphIndex === 0 || graphIndex === 1 ? [0, 1] : [graphIndex]; - indicesToReset.forEach(idx => { - const selectedGraph = sweepExtent[idx] || {}; - sweepExtent[idx] = Object.assign({}, selectedGraph, { - xExtent: false, - yExtent: false - }); - }); - return Object.assign({}, state, { - zoom: { - sweepExtent, - graphIndex, - sweepTypes: [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET] - }, - sweepType: _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET - }); + jcampIdx: 0 }; const uiReducer = (state = initialState, action) => { switch (action.type) { @@ -154,27 +24,21 @@ const uiReducer = (state = initialState, action) => { viewer: action.payload }); case _action_type.UI.SWEEP.SET_TYPE: - if (action.payload.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET || action.payload === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET) { - // return Object.assign({}, state, { - // sweepExtent: { xExtent: false, yExtent: false }, - // }); - return resetZoom(state, action); + 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, - // }); - return updateSweepType(state, action); + return Object.assign({}, state, { + sweepType: action.payload, + jcampIdx: action.jcampIdx + }); case _action_type.UI.SWEEP.SELECT_ZOOMIN: - { - // return Object.assign({}, state, { - // sweepExtent: action.payload, - // }); - return updateZoom(state, action); - } - case _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT: return Object.assign({}, state, { - subViewerAt: action.payload + sweepExtent: action.payload }); case _action_type.MANAGER.RESETALL: return initialState; diff --git a/dist/reducers/undo_redo_config.js b/dist/reducers/undo_redo_config.js index b1f61d03..7a8cfeaa 100644 --- a/dist/reducers/undo_redo_config.js +++ b/dist/reducers/undo_redo_config.js @@ -6,11 +6,11 @@ Object.defineProperty(exports, "__esModule", { 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.ADD_VISUAL_SPLIT, _action_type.INTEGRATION.RM_VISUAL_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 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.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: false, + 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] diff --git a/dist/sagas/saga_ui.js b/dist/sagas/saga_ui.js index 4a6a3772..adf16e94 100644 --- a/dist/sagas/saga_ui.js +++ b/dist/sagas/saga_ui.js @@ -3,17 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.shouldDisplayLcmsSubViewerAt = exports.default = void 0; +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"); -var _list_graph = require("../constants/list_graph"); -var _saga_lcms_ui = require("./saga_lcms_ui"); -const getUiState = state => state.ui; -const getCurveState = state => state.curve; -const getHplcMsState = state => state.hplcMs; -const getSubViewZoomActionType = () => _action_type.UI.SWEEP.SELECT_ZOOMIN_SUBVIEW || _action_type.UI.SWEEP.SELECT_ZOOMIN; +const getUiSt = state => state.ui; +const getCurveSt = state => state.curve; const calcPeaks = payload => { const { xExtent, @@ -32,110 +28,76 @@ const calcPeaks = payload => { const peaks = dataPks.filter(p => xL <= p.x && p.x <= xU && yL <= p.y && p.y <= yU); return peaks; }; -const getLayoutState = state => state.layout; function* selectUiSweep(action) { - const uiState = yield (0, _effects.select)(getUiState); - const { - sweepType, - zoom - } = uiState; + const uiSt = yield (0, _effects.select)(getUiSt); const { payload } = action; - const curveState = yield (0, _effects.select)(getCurveState); + const curveSt = yield (0, _effects.select)(getCurveSt); const { curveIdx - } = curveState; - const hplcMsState = yield (0, _effects.select)(getHplcMsState); - const { - uvvis - } = hplcMsState; - const layoutState = yield (0, _effects.select)(getLayoutState); - switch (sweepType) { + } = curveSt; + switch (uiSt.sweepType) { case _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN: - if (layoutState === _list_layout.LIST_LAYOUT.LC_MS && uvvis.listWaveLength) { - yield* (0, _saga_lcms_ui.lcmsHandleSelectZoomIn)({ - payload, - zoom - }); - } else { - yield (0, _effects.put)({ - type: _action_type.UI.SWEEP.SELECT_ZOOMIN, - payload - }); - } + yield (0, _effects.put)({ + type: _action_type.UI.SWEEP.SELECT_ZOOMIN, + payload + }); break; case _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET: - if (layoutState === _list_layout.LIST_LAYOUT.LC_MS && (payload?.graphIndex === 0 || payload?.graphIndex === 1)) { - yield* (0, _saga_lcms_ui.lcmsHandleSelectZoomReset)(); - } else { - yield (0, _effects.put)({ - type: _action_type.UI.SWEEP.SELECT_ZOOMRESET, - payload - }); - } + yield (0, _effects.put)({ + type: _action_type.UI.SWEEP.SELECT_ZOOMRESET, + payload + }); break; case _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD: - { - if (uvvis.selectedWaveLength && layoutState === _list_layout.LIST_LAYOUT.LC_MS) { - yield* (0, _saga_lcms_ui.lcmsHandleIntegrationAdd)({ - uvvis, - payload - }); - } else { - yield (0, _effects.put)({ - type: _action_type.UI.SWEEP.SELECT_INTEGRATION, - payload: { - newData: payload, - curveIdx - } - }); + yield (0, _effects.put)({ + type: _action_type.UI.SWEEP.SELECT_INTEGRATION, + payload: { + newData: payload, + curveIdx } - break; - } + }); + 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 = { - ...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 - } - }); + 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 layoutState = yield (0, _effects.select)(getLayoutState); + const layoutSt = yield (0, _effects.select)(getLayoutSt); const { payload } = action; - if (!payload?.xExtent || !payload?.yExtent) return; const { xExtent, yExtent, - direction, - brushClass + direction } = payload; const { yL, @@ -148,7 +110,7 @@ function* scrollUiWheel(action) { yExtent: false }; let [nyeL, nyeU, h, nytL, nytU] = [0, 1, 1, 0, 1]; - switch (layoutState) { + switch (layoutSt) { case _list_layout.LIST_LAYOUT.IR: case _list_layout.LIST_LAYOUT.RAMAN: [nyeL, nyeU] = [yeL + (yeU - yeL) * (1 - scale), yeU]; @@ -192,83 +154,40 @@ function* scrollUiWheel(action) { }; break; } - if (brushClass === `.${_list_graph.LIST_BRUSH_SVG_GRAPH.RECT}`) { - yield (0, _effects.put)({ - type: getSubViewZoomActionType(), - payload: nextExtent - }); - } else { - yield (0, _effects.put)({ - type: _action_type.UI.SWEEP.SELECT_ZOOMIN, - payload: nextExtent - }); - } + yield (0, _effects.put)({ + type: _action_type.UI.SWEEP.SELECT_ZOOMIN, + payload: nextExtent + }); } const getUiSweepType = state => state.ui.sweepType; -const shouldDisplayLcmsSubViewerAt = ({ - isLcmsLayout, - payload, - sourceHint, - uiSweepType -}) => isLcmsLayout && sourceHint === 'lcms_tic' && Number.isFinite(payload?.x) && [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT].includes(uiSweepType); -exports.shouldDisplayLcmsSubViewerAt = shouldDisplayLcmsSubViewerAt; function* clickUiTarget(action) { const { payload, onPeak, voltammetryPeakIdx, - onPecker, - sourceHint + onPecker } = action; const uiSweepType = yield (0, _effects.select)(getUiSweepType); - const curveState = yield (0, _effects.select)(getCurveState); + const curveSt = yield (0, _effects.select)(getCurveSt); const { curveIdx - } = curveState; - const hplcMsState = yield (0, _effects.select)(getHplcMsState); - const { - uvvis - } = hplcMsState; - const isLcmsLayout = (yield (0, _effects.select)(getLayoutState)) === _list_layout.LIST_LAYOUT.LC_MS; - if (shouldDisplayLcmsSubViewerAt({ - isLcmsLayout, - payload, - sourceHint, - uiSweepType - })) { - yield (0, _effects.put)({ - type: _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT, - payload - }); - return; - } + } = curveSt; if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD && !onPeak) { - const spectrumId = hplcMsState?.uvvis?.selectedWaveLength; - if (isLcmsLayout && spectrumId == null) return; - const currentPeaks = hplcMsState?.uvvis?.currentSpectrum?.peaks || []; - const updatedPeaks = [...currentPeaks, payload]; yield (0, _effects.put)({ - type: _action_type.HPLC_MS.UPDATE_HPLCMS_PEAKS, + type: _action_type.EDITPEAK.ADD_POSITIVE, payload: { - spectrumId, - peaks: updatedPeaks + dataToAdd: payload, + curveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_DELETE && onPeak) { - if (isLcmsLayout && uvvis.selectedWaveLength) { - yield* (0, _saga_lcms_ui.lcmsHandlePeakDelete)({ - uvvis, - payload - }); - } else { - yield (0, _effects.put)({ - type: _action_type.EDITPEAK.ADD_NEGATIVE, - payload: { - dataToAdd: payload, - curveIdx - } - }); - } + 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, @@ -278,20 +197,13 @@ function* clickUiTarget(action) { } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_RM && onPeak) { - if (uvvis.selectedWaveLength && isLcmsLayout) { - yield* (0, _saga_lcms_ui.lcmsHandleIntegrationRm)({ - uvvis, - payload - }); - } else { - yield (0, _effects.put)({ - type: _action_type.INTEGRATION.RM_ONE, - payload: { - dataToRemove: payload, - curveIdx - } - }); - } + 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, @@ -403,11 +315,6 @@ function* clickUiTarget(action) { jcampIdx: curveIdx } }); - } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT) { - yield (0, _effects.put)({ - type: _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT, - payload - }); } } 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)]; diff --git a/dist/setupTests.js b/dist/setupTests.js index 859d0d6e..fc453d7d 100644 --- a/dist/setupTests.js +++ b/dist/setupTests.js @@ -1,8 +1,8 @@ "use strict"; -const Enzyme = require('enzyme'); -const AdapterModule = require('@wojtekmaj/enzyme-adapter-react-17'); -const Adapter = AdapterModule.default || AdapterModule; -Enzyme.configure({ - adapter: new Adapter() +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/src/actions/threshold.js b/src/actions/threshold.js index 001a4cdb..0b3fc4a8 100644 --- a/src/actions/threshold.js +++ b/src/actions/threshold.js @@ -7,10 +7,10 @@ const updateThresholdValue = (payload) => ( } ); -const resetThresholdValue = () => ( +const resetThresholdValue = (payload = false) => ( { type: THRESHOLD.RESET_VALUE, - payload: false, + payload, } ); diff --git a/src/components/cmd_bar/r03_threshold.js b/src/components/cmd_bar/r03_threshold.js index 77b49a19..bca9be2b 100644 --- a/src/components/cmd_bar/r03_threshold.js +++ b/src/components/cmd_bar/r03_threshold.js @@ -102,6 +102,9 @@ const Threshold = ({ } else { thresVal = thresValSt || (feature ? feature.thresRef : hplcMsSt?.threshold?.value); } + const { curveIdx } = curveSt; + const onResetThreshold = () => resetThresholdValueAct({ value: false, curveIdx }); + const onToggleThreshold = () => toggleThresholdIsEditAct({ curveIdx }); return ( @@ -115,7 +118,7 @@ const Threshold = ({ ) } disabled={Cfg.btnCmdThres(thresVal)} - onClick={resetThresholdValueAct} + onClick={onResetThreshold} > @@ -134,7 +137,7 @@ const Threshold = ({ ) } disabled={Cfg.btnCmdThres(thresVal)} - onClick={toggleThresholdIsEditAct} + onClick={onToggleThreshold} > { restoreIcon(classes, hasEdit, isEditSt) } diff --git a/src/components/common/draw.js b/src/components/common/draw.js index c8478546..b1861001 100644 --- a/src/components/common/draw.js +++ b/src/components/common/draw.js @@ -22,7 +22,7 @@ const drawDisplay = (klass, isHidden) => { } }; -const drawDestroy = (klass) => d3.select(`${klass} > *`).remove(); +const drawDestroy = (klass) => d3.select(klass).selectAll('*').remove(); const drawArrowOnCurve = (klass, isHidden) => { if (isHidden) { diff --git a/src/components/d3_line/line_focus.js b/src/components/d3_line/line_focus.js index e819583e..c47b03a8 100644 --- a/src/components/d3_line/line_focus.js +++ b/src/components/d3_line/line_focus.js @@ -307,6 +307,12 @@ class LineFocus { mpp.exit() .attr('class', 'exit') .remove(); + const clearPeakLabels = () => { + const bpTxt = this.tags.bpTxt.selectAll('text').data([]); + bpTxt.exit() + .attr('class', 'exit') + .remove(); + }; const linePath = [ { x: -0.5, y: 10 }, @@ -367,6 +373,8 @@ class LineFocus { .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)); + } else { + clearPeakLabels(); } } @@ -376,8 +384,35 @@ class LineFocus { } = this.shouldUpdate; if (sameXY && sameLySt && sameItSt && sameData) return; + const clearIntegralPaths = () => { + const empty = []; + const igbp = this.tags.igbPath.selectAll('path').data(empty); + igbp.exit() + .attr('class', 'exit') + .remove(); + const igcp = this.tags.igcPath.selectAll('path').data(empty); + igcp.exit() + .attr('class', 'exit') + .remove(); + const igtp = this.tags.igtPath.selectAll('text').data(empty); + igtp.exit() + .attr('class', 'exit') + .remove(); + }; + const clearAUC = () => { + const auc = this.tags.aucPath.selectAll('path').data([]); + auc.exit() + .attr('class', 'exit') + .remove(); + }; + const { selectedIdx, integrations } = integrationState; const selectedIntegration = integrations[selectedIdx]; + if (selectedIntegration === false || selectedIntegration === undefined) { + clearIntegralPaths(); + clearAUC(); + return; + } const { stack, refArea, refFactor, shift, @@ -406,19 +441,16 @@ class LineFocus { .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); - this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); + clearIntegralPaths(); + clearAUC(); return; } if (ignoreRef) { + clearIntegralPaths(); this.drawAUC(stack, shift); } else { + clearAUC(); // rescale for zoom const { xt } = TfRescale(this); diff --git a/src/components/d3_multi/index.js b/src/components/d3_multi/index.js index 1aa27a4a..2eb4541d 100644 --- a/src/components/d3_multi/index.js +++ b/src/components/d3_multi/index.js @@ -29,6 +29,10 @@ import { const W = Math.round(window.innerWidth * 0.90 * 9 / 12); // ROI const H = Math.round(window.innerHeight * 0.90 * 0.85); // ROI +const buildResetPayload = (feature, curveSt) => ( + { ...feature, curveIdx: curveSt.curveIdx } +); + class ViewerMulti extends React.Component { constructor(props) { super(props); @@ -215,10 +219,12 @@ class ViewerMulti extends React.Component { } normChange(prevProps) { - const { feature, resetAllAct, entities } = this.props; + const { + feature, resetAllAct, entities, curveSt, + } = this.props; const oldEntities = prevProps.entities; if (oldEntities !== entities) { - resetAllAct(feature); + resetAllAct(buildResetPayload(feature, curveSt)); } } @@ -255,7 +261,7 @@ class ViewerMulti extends React.Component { drawDestroy(this.rootKlass); if (shouldReset) { - resetAllAct(feature); + resetAllAct(buildResetPayload(feature, curveSt)); } const { xxLabel, yyLabel } = this.resolveAxisLabels(props); diff --git a/src/components/d3_multi/multi_focus.js b/src/components/d3_multi/multi_focus.js index a1d20da8..179df9fd 100644 --- a/src/components/d3_multi/multi_focus.js +++ b/src/components/d3_multi/multi_focus.js @@ -126,6 +126,7 @@ class MultiFocus { const { prevXt, prevYt, prevEpSt, prevLySt, prevTePt, prevDtPk, prevSfPk, prevData, prevYFactor, + prevJcampIdx, } = this.shouldUpdate; const { xt, yt } = TfRescale(this); const sameXY = xt(1.1) === prevXt && prevYt === yt(1.1); @@ -142,12 +143,13 @@ class MultiFocus { ); const sameData = prevData === this.data.length; const sameYFactor = prevYFactor === this.yTransformFactor; + const sameJcampIdx = prevJcampIdx === this.jcampIdx; this.shouldUpdate = Object.assign( {}, this.shouldUpdate, { sameXY, sameEpSt, sameLySt, // eslint-disable-line - sameTePt, sameDtPk, sameSfPk, sameData, sameYFactor, // eslint-disable-line + sameTePt, sameDtPk, sameSfPk, sameData, sameYFactor, sameJcampIdx, // eslint-disable-line }, ); } @@ -162,12 +164,13 @@ class MultiFocus { const prevData = this.data.length; const prevLySt = this.layout; const prevYFactor = this.yTransformFactor; + const prevJcampIdx = this.jcampIdx; this.shouldUpdate = Object.assign( {}, this.shouldUpdate, { prevXt, prevYt, prevEpSt, prevLySt, // eslint-disable-line - prevTePt, prevDtPk, prevSfPk, prevData, prevYFactor, // eslint-disable-line + prevTePt, prevDtPk, prevSfPk, prevData, prevYFactor, prevJcampIdx, // eslint-disable-line }, ); } @@ -426,11 +429,11 @@ class MultiFocus { drawPeaks(editPeakSt) { const { - sameXY, sameEpSt, sameDtPk, sameSfPk, + sameXY, sameEpSt, sameDtPk, sameSfPk, sameJcampIdx, } = this.shouldUpdate; if (!Format.isCyclicVoltaLayout(this.layout) - && sameXY && sameEpSt && sameDtPk && sameSfPk) return; + && sameXY && sameEpSt && sameDtPk && sameSfPk && sameJcampIdx) return; // rescale for zoom const { xt, yt } = TfRescale(this); @@ -454,6 +457,12 @@ class MultiFocus { mpp.exit() .attr('class', 'exit') .remove(); + const clearPeakLabels = () => { + const bpTxt = this.tags.bpTxt.selectAll('text').data([]); + bpTxt.exit() + .attr('class', 'exit') + .remove(); + }; const linePath = [ { x: -0.5, y: 10 }, @@ -528,6 +537,8 @@ class MultiFocus { .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)); + } else { + clearPeakLabels(); } mpp.attr('fill', (_, index) => { @@ -541,11 +552,11 @@ class MultiFocus { drawPeckers() { const { - sameXY, sameEpSt, sameDtPk, sameSfPk, + sameXY, sameEpSt, sameDtPk, sameSfPk, sameJcampIdx, } = this.shouldUpdate; if (!Format.isCyclicVoltaLayout(this.layout) && sameXY - && sameEpSt && sameDtPk && sameSfPk) return; + && sameEpSt && sameDtPk && sameSfPk && sameJcampIdx) return; // rescale for zoom const { xt, yt } = TfRescale(this); @@ -598,31 +609,37 @@ class MultiFocus { drawInteg(integrationState) { const { - sameXY, sameLySt, sameItSt, sameData, + sameXY, sameLySt, sameItSt, sameData, sameJcampIdx, } = this.shouldUpdate; - if (sameXY && sameLySt && sameItSt && sameData) return; + if (sameXY && sameLySt && sameItSt && sameData && sameJcampIdx) return; - const { integrations } = integrationState; - 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); + const clearIntegralPaths = () => { + const empty = []; + const igbp = this.tags.igbPath.selectAll('path').data(empty); igbp.exit() .attr('class', 'exit') .remove(); - const igcp = this.tags.igcPath.selectAll('path').data(itgs); + const igcp = this.tags.igcPath.selectAll('path').data(empty); igcp.exit() .attr('class', 'exit') .remove(); - - const igtp = this.tags.igtPath.selectAll('text').data(itgs); + const igtp = this.tags.igtPath.selectAll('text').data(empty); igtp.exit() .attr('class', 'exit') .remove(); - this.drawVisualSplitLines([], 0, false); + }; + const clearAUC = () => { + const auc = this.tags.aucPath.selectAll('path').data([]); + auc.exit() + .attr('class', 'exit') + .remove(); + }; + + const { integrations } = integrationState; + const selectedIntegration = integrations[this.jcampIdx]; + if (selectedIntegration === false || selectedIntegration === undefined) { + clearIntegralPaths(); + clearAUC(); return; } @@ -653,19 +670,16 @@ class MultiFocus { .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); - this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); + clearIntegralPaths(); + clearAUC(); return; } if (ignoreRef) { + clearIntegralPaths(); this.drawAUC(stack, shift); } else { + clearAUC(); // rescale for zoom const { xt } = TfRescale(this); @@ -797,8 +811,10 @@ class MultiFocus { } drawMtply(mtplySt) { - const { sameXY, sameLySt, sameMySt } = this.shouldUpdate; - if (sameXY && sameLySt && sameMySt) return; + const { + sameXY, sameLySt, sameMySt, sameJcampIdx, + } = this.shouldUpdate; + if (sameXY && sameLySt && sameMySt && sameJcampIdx) return; const { multiplicities } = mtplySt; const selectedMulti = multiplicities[this.jcampIdx]; diff --git a/src/reducers/reducer_threshold.js b/src/reducers/reducer_threshold.js index 9755c67d..a6a0c6c3 100644 --- a/src/reducers/reducer_threshold.js +++ b/src/reducers/reducer_threshold.js @@ -13,12 +13,12 @@ const initialState = { ], }; -// const defaultThresHold = { -// 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; @@ -77,19 +77,34 @@ const setThresHoldLower = (state, action) => { return Object.assign({}, state, { list: newListThres }); }; -const setThresHoldIsEdit = (state) => { +const setThresHoldIsEdit = (state, action) => { + const { payload } = action; const { list, selectedIdx } = state; - const selectedThres = list[selectedIdx]; + const curveIdx = payload && payload.curveIdx !== undefined ? payload.curveIdx : selectedIdx; + const selectedThres = list[curveIdx] || defaultThresHold; const { isEdit } = selectedThres; const newSelectedThres = Object.assign({}, selectedThres, { isEdit: !isEdit }); const newListThres = [...list]; - newListThres[selectedIdx] = newSelectedThres; - return Object.assign({}, state, { list: newListThres }); + newListThres[curveIdx] = newSelectedThres; + return Object.assign({}, state, { list: newListThres, selectedIdx: curveIdx }); }; const resetAll = (state, action) => { const { payload } = action; const { list } = state; + if (payload && payload.curveIdx !== undefined) { + const { curveIdx } = payload; + const selectedThres = list[curveIdx] || defaultThresHold; + const newSelectedThres = Object.assign( + {}, + selectedThres, + { value: payload.thresRef }, + ); + const newListThres = [...list]; + newListThres[curveIdx] = newSelectedThres; + return Object.assign({}, state, { selectedIdx: curveIdx, list: newListThres }); + } + const newList = list.map((item) => ( { isEdit: item.isEdit, @@ -158,7 +173,7 @@ const thresholdReducer = (state = initialState, action) => { case THRESHOLD.RESET_VALUE: return setThresHoldValue(state, action); case THRESHOLD.TOGGLE_ISEDIT: - return setThresHoldIsEdit(state); + return setThresHoldIsEdit(state, action); case MANAGER.RESET_INIT_COMMON: return resetInitCommon(state); case MANAGER.RESETALL: diff --git a/yarn.lock b/yarn.lock index 7307128e..e6147cde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10417,15 +10417,6 @@ react-dev-utils@^12.0.1: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - react-dropzone@^8.0.3: version "8.2.0" resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-8.2.0.tgz#e889455c4259c018bc5595ab0e2a5f7d958d173a" @@ -10614,14 +10605,6 @@ react-transition-group@^4.3.0, react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - read-cache@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" From 4e86881a8c607efc6fbca9d28a85fa0a95dcfe04 Mon Sep 17 00:00:00 2001 From: Nicolass67 Date: Wed, 10 Jun 2026 12:37:45 +0200 Subject: [PATCH 2/7] fix: hide irrelevant toolbar controls and improve multi-spectra panel Hide layout-specific cmd bar groups instead of disabling them, support multi-open side panels, improve graph selection labels, and fix submit payload for multi-curve layouts. --- dist/components/cmd_bar/01_viewer.js | 3 +- dist/components/cmd_bar/03_peak.js | 20 +-- dist/components/cmd_bar/04_integration.js | 19 ++- dist/components/cmd_bar/05_multiplicity.js | 13 +- dist/components/cmd_bar/07_pecker.js | 8 +- dist/components/cmd_bar/index.js | 5 +- dist/components/cmd_bar/r05_submit_btn.js | 21 ++- dist/components/cmd_bar/r07_wavelength_btn.js | 13 +- dist/components/cmd_bar/r08_change_axes.js | 3 +- dist/components/cmd_bar/r09_detector.js | 13 +- dist/components/cmd_bar/r10_cv_density.js | 2 +- dist/components/panel/graph_selection.js | 104 ++++++--------- dist/components/panel/index.js | 17 +-- src/components/cmd_bar/01_viewer.js | 27 ++-- src/components/cmd_bar/03_peak.js | 100 ++++++++------ src/components/cmd_bar/04_integration.js | 70 +++++----- src/components/cmd_bar/05_multiplicity.js | 27 ++-- src/components/cmd_bar/07_pecker.js | 9 +- src/components/cmd_bar/index.js | 7 +- src/components/cmd_bar/r05_submit_btn.js | 14 +- src/components/cmd_bar/r07_wavelength_btn.js | 17 +-- src/components/cmd_bar/r08_change_axes.js | 6 +- src/components/cmd_bar/r09_detector.js | 17 +-- src/components/cmd_bar/r10_cv_density.js | 2 +- src/components/panel/graph_selection.js | 122 +++++++++--------- src/components/panel/index.js | 19 +-- 26 files changed, 352 insertions(+), 326 deletions(-) diff --git a/dist/components/cmd_bar/01_viewer.js b/dist/components/cmd_bar/01_viewer.js index 637df919..2f77ca2c 100644 --- a/dist/components/cmd_bar/01_viewer.js +++ b/dist/components/cmd_bar/01_viewer.js @@ -47,14 +47,13 @@ const Viewer = ({ className: classes.icon }) }) - }), hideCmdAnaViewerSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { + }), hideCmdAnaViewerSt || disableCmdAnaViewerSt ? 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 diff --git a/dist/components/cmd_bar/03_peak.js b/dist/components/cmd_bar/03_peak.js index ea2777d2..e446428f 100644 --- a/dist/components/cmd_bar/03_peak.js +++ b/dist/components/cmd_bar/03_peak.js @@ -58,6 +58,13 @@ const Peak = ({ dataPeaks }); }; + const showAddPeak = !disableAddPeakSt; + const showRmPeak = !disableRmPeakSt; + const showSetRef = !disableSetRefSt; + const showClearAll = !disableRmPeakSt; + if (!showAddPeak && !showRmPeak && !showSetRef && !showClearAll) { + return null; + } if (isHandleMaxAndMinPeaksSt) { const { spectraList @@ -80,7 +87,7 @@ const Peak = ({ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { className: classes.group, "data-testid": "Peak", - children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { + children: [showAddPeak ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "txt-sv-tp", children: "Add Peak" @@ -88,7 +95,6 @@ const 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'), @@ -96,7 +102,7 @@ const Peak = ({ }) }) }) - }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { + }) : null, showRmPeak ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "txt-sv-tp", children: "Remove Peak" @@ -104,7 +110,6 @@ const 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'), @@ -112,12 +117,12 @@ const Peak = ({ }) }) }) - }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { + }) : null, showClearAll ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { content: { tp: 'Clear All Peaks' }, cb: onClearAll, - isClearAllDisabled: disableRmPeakSt, + isClearAllDisabled: false, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmallpeaks'), children: "P" @@ -125,7 +130,7 @@ const Peak = ({ className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-rmallpeaks'), children: "x" })] - }), !disableSetRefSt ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { + }) : null, showSetRef ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "txt-sv-tp", children: "Set Reference" @@ -133,7 +138,6 @@ const Peak = ({ 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 diff --git a/dist/components/cmd_bar/04_integration.js b/dist/components/cmd_bar/04_integration.js index 2152a917..1fc83521 100644 --- a/dist/components/cmd_bar/04_integration.js +++ b/dist/components/cmd_bar/04_integration.js @@ -34,7 +34,7 @@ const styles = () => Object.assign({ txtIcon: {} }, _common.commonStyle); const iconSize = '16px'; -const setFactor = (classes, isDisable, integrationSt, setIntegrationFkrAct, curveIdx) => { +const setFactor = (classes, integrationSt, setIntegrationFkrAct, curveIdx) => { const onFactorChanged = e => { e.target.blur(); setIntegrationFkrAct({ @@ -60,7 +60,6 @@ const setFactor = (classes, isDisable, integrationSt, setIntegrationFkrAct, curv } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, { className: classes.field, - disabled: isDisable, id: "intg-factor-name", type: "number", value: refFactor, @@ -101,6 +100,9 @@ const Integration = ({ const onClearAll = () => clearIntegrationAllAct({ curveIdx }); + if (isDisableSt) { + return null; + } return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { className: classes.group, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { @@ -111,12 +113,11 @@ const Integration = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_common.MuButton, { className: (0, _classnames.default)((0, _common.focusStyle)(isFocusAddIntgSt, classes), 'btn-add-inter'), - disabled: isDisableSt, onClick: onSweepIntegtAdd, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, { path: _js.mdiMathIntegral, size: iconSize, - color: iconColor(isFocusAddIntgSt || isDisableSt), + color: iconColor(isFocusAddIntgSt), className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-addint') }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-addint'), @@ -132,12 +133,11 @@ const 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), + color: iconColor(isFocusRmIntgSt), 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'), @@ -153,17 +153,16 @@ const Integration = ({ 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), + color: iconColor(isFocusSetRefSt), className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-refint') }) }) }) - }), !ignoreRef ? setFactor(classes, isDisableSt, integrationSt, setIntegrationFkrAct, curveIdx) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { + }), !ignoreRef ? setFactor(classes, integrationSt, setIntegrationFkrAct, curveIdx) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { content: { tp: 'Clear All Integration' }, @@ -171,7 +170,7 @@ const Integration = ({ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, { path: _js.mdiMathIntegral, size: iconSize, - color: iconColor(isDisableSt), + color: iconColor(false), 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'), diff --git a/dist/components/cmd_bar/05_multiplicity.js b/dist/components/cmd_bar/05_multiplicity.js index c725320e..a00b860e 100644 --- a/dist/components/cmd_bar/05_multiplicity.js +++ b/dist/components/cmd_bar/05_multiplicity.js @@ -47,6 +47,9 @@ const Multiplicity = ({ const onClearAll = () => clearMpyAllAct({ curveIdx }); + if (disableAddMpySt) { + return null; + } return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { className: classes.group, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { @@ -57,7 +60,6 @@ const 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'), @@ -73,7 +75,6 @@ const 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'), @@ -89,7 +90,6 @@ const 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'), @@ -105,7 +105,6 @@ const 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'), @@ -113,14 +112,12 @@ const Multiplicity = ({ }) }) }) - }), disableAddMpySt ? null : - /*#__PURE__*/ - // eslint-disable-line - (0, _jsxRuntime.jsx)(_tri_btn.default, { + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_tri_btn.default, { content: { tp: 'Clear All Multiplicity' }, cb: onClearAll, + isClearAllDisabled: false, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txt, 'txt-sv-bar-rmallmpy'), children: "Jx" diff --git a/dist/components/cmd_bar/07_pecker.js b/dist/components/cmd_bar/07_pecker.js index d8fbf678..d19d4e9f 100644 --- a/dist/components/cmd_bar/07_pecker.js +++ b/dist/components/cmd_bar/07_pecker.js @@ -110,7 +110,11 @@ const Pecker = ({ } = spectra; hasRefPeaks = hasRefPeak; } - return !_cfg.default.hidePanelCyclicVolta(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { + if (_cfg.default.hidePanelCyclicVolta(layoutSt)) { + return null; + } + return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { + className: classes.group, "data-testid": "Pecker", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { @@ -161,7 +165,7 @@ const Pecker = ({ }) }) })] - }) : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {}); + }); }; const mapStateToProps = (state, _) => ( // eslint-disable-line diff --git a/dist/components/cmd_bar/index.js b/dist/components/cmd_bar/index.js index 5b000116..95ac6cd4 100644 --- a/dist/components/cmd_bar/index.js +++ b/dist/components/cmd_bar/index.js @@ -26,6 +26,7 @@ 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 _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, function-paren-newline, react/function-component-definition, react/require-default-props */ @@ -43,6 +44,8 @@ const CmdBar = ({ layoutSt }) => { const isCvLayout = _format.default.isCyclicVoltaLayout(layoutSt); + const hideIntegration = isCvLayout || _cfg.default.btnCmdIntg(layoutSt); + const hideMultiplicity = isCvLayout || _cfg.default.btnCmdMpy(layoutSt); return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: classes.card, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_viewer.default, { @@ -52,7 +55,7 @@ const CmdBar = ({ 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, { + }), hideIntegration ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_integration.default, {}), hideMultiplicity ? 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, diff --git a/dist/components/cmd_bar/r05_submit_btn.js b/dist/components/cmd_bar/r05_submit_btn.js index 78747a3d..88a350a0 100644 --- a/dist/components/cmd_bar/r05_submit_btn.js +++ b/dist/components/cmd_bar/r05_submit_btn.js @@ -136,6 +136,7 @@ const buildSpectrumPayload = ({ return { peaks: peaksEdit, layout: layoutSt, + xUnit: xLabel, shift, scan, thres, @@ -187,7 +188,10 @@ const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, ana decimalSt }); }); + const selectedIdx = Number.isFinite(curveSt?.curveIdx) ? curveSt.curveIdx : 0; + const selectedSpectrumPayload = spectraList[selectedIdx] || spectraList[0] || {}; const payload = { + ...selectedSpectrumPayload, spectra_list: spectraList }; if (Number.isFinite(curveSt?.curveIdx)) { @@ -218,7 +222,10 @@ const BtnSubmit = ({ curveList, axesUnitsSt, detectorSt, - metaSt + metaSt, + disabled, + className, + children }) => { // const disBtn = peaksEdit.length === 0 || statusSt.btnSubmit || disabled; const { @@ -247,13 +254,14 @@ const BtnSubmit = ({ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "txt-sv-tp", - children: "Submit" + children: operation.name || 'Submit' }), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_common.MuButton, { - className: (0, _classnames.default)('btn-sv-bar-submit'), + className: (0, _classnames.default)('btn-sv-bar-submit', className), color: "primary", + disabled: disabled, 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, { + children: children || /*#__PURE__*/(0, _jsxRuntime.jsx)(_PlayCircleOutline.default, { className: classes.icon }) }) @@ -301,6 +309,9 @@ BtnSubmit.propTypes = { curveList: _propTypes.default.array.isRequired, axesUnitsSt: _propTypes.default.object.isRequired, detectorSt: _propTypes.default.object.isRequired, - metaSt: _propTypes.default.object.isRequired + metaSt: _propTypes.default.object.isRequired, + disabled: _propTypes.default.bool, + className: _propTypes.default.string, + children: _propTypes.default.node }; 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/r07_wavelength_btn.js b/dist/components/cmd_bar/r07_wavelength_btn.js index 326026e6..734760e1 100644 --- a/dist/components/cmd_bar/r07_wavelength_btn.js +++ b/dist/components/cmd_bar/r07_wavelength_btn.js @@ -30,7 +30,7 @@ const styles = () => Object.assign({ }, _common.commonStyle); const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWaveLengthAct) => { if (!_format.default.isXRDLayout(layoutSt)) { - return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {}); + return null; } const onChange = e => updateWaveLengthAct(e.target.value); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, { @@ -64,10 +64,13 @@ const Wavelength = ({ waveLengthSt, layoutSt, updateWaveLengthAct -}) => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: classes.groupRight, - children: wavelengthSelect(classes, waveLengthSt, layoutSt, updateWaveLengthAct) -}); +}) => { + if (!_format.default.isXRDLayout(layoutSt)) return null; + return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: classes.groupRight, + children: wavelengthSelect(classes, waveLengthSt, layoutSt, updateWaveLengthAct) + }); +}; const mapStateToProps = (state, props) => ( // eslint-disable-line { diff --git a/dist/components/cmd_bar/r08_change_axes.js b/dist/components/cmd_bar/r08_change_axes.js index b8d3ee75..4c8a1051 100644 --- a/dist/components/cmd_bar/r08_change_axes.js +++ b/dist/components/cmd_bar/r08_change_axes.js @@ -131,7 +131,7 @@ const axisY = (classes, layoutSt, axesUnitsSt, updateYAxisAct, curveSt) => { }; const showSelect = (classes, layoutSt, curveSt, axesUnitsSt, updateXAxisAct, updateYAxisAct) => { if (!listLayoutToShow.includes(layoutSt)) { - return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {}); + return null; } return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { children: [axisX(classes, layoutSt, axesUnitsSt, updateXAxisAct, curveSt), axisY(classes, layoutSt, axesUnitsSt, updateYAxisAct, curveSt)] @@ -161,6 +161,7 @@ const ChangeAxes = ({ }); } }, [layoutSt, axes, curveIdx, updateYAxisAct]); + if (!listLayoutToShow.includes(layoutSt)) return null; return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: classes.groupRight, "data-testid": "ChangeAxes", diff --git a/dist/components/cmd_bar/r09_detector.js b/dist/components/cmd_bar/r09_detector.js index 3efdcf7c..e40b4e68 100644 --- a/dist/components/cmd_bar/r09_detector.js +++ b/dist/components/cmd_bar/r09_detector.js @@ -30,7 +30,7 @@ const styles = () => Object.assign({ }, _common.commonStyle); const detectorSelect = (classes, detectorSt, curveSt, layoutSt, updateDetectorAct) => { if (!_format.default.isSECLayout(layoutSt)) { - return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {}); + return null; } const { curveIdx @@ -80,10 +80,13 @@ const Detector = ({ curveSt, layoutSt, updateDetectorAct -}) => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - className: classes.groupRight, - children: detectorSelect(classes, detectorSt, curveSt, layoutSt, updateDetectorAct) -}); +}) => { + if (!_format.default.isSECLayout(layoutSt)) return null; + return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: classes.groupRight, + children: detectorSelect(classes, detectorSt, curveSt, layoutSt, updateDetectorAct) + }); +}; const mapStateToProps = (state, _props) => ( // eslint-disable-line { diff --git a/dist/components/cmd_bar/r10_cv_density.js b/dist/components/cmd_bar/r10_cv_density.js index 4f850b0b..c2cf51a3 100644 --- a/dist/components/cmd_bar/r10_cv_density.js +++ b/dist/components/cmd_bar/r10_cv_density.js @@ -51,7 +51,7 @@ const CvDensityControls = ({ setAreaUnitAct, toggleDensityAct }) => { - if (layoutSt !== _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) return /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {}); + if (layoutSt !== _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY) return null; const handleAreaChange = e => { const raw = e.target.value; if (raw === '') { diff --git a/dist/components/panel/graph_selection.js b/dist/components/panel/graph_selection.js index 5ab8adf3..c1d9bce9 100644 --- a/dist/components/panel/graph_selection.js +++ b/dist/components/panel/graph_selection.js @@ -50,6 +50,38 @@ const styles = () => ({ overflowWrap: 'anywhere' } }); +const fallbackName = (entityFileNames, idx) => { + if (entityFileNames && idx < entityFileNames.length) { + return entityFileNames[idx]; + } + return ''; +}; +const displayName = (spectra, idx, entityFileNames) => spectra?.title || spectra?.feature?.title || spectra?.spectrum?.title || fallbackName(entityFileNames, idx) || `Spectrum ${idx + 1}`; +const renderCurveItem = (classes, item, curveIdx, onChange) => /*#__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.label !== '' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + children: item.label + }) : null // eslint-disable-line + ] + })] + }) +}, item.idx); const GraphSelectionPanel = ({ classes, curveSt, @@ -57,7 +89,9 @@ const GraphSelectionPanel = ({ subLayoutsInfo, layoutSt, selectCurveAct, - toggleShowAllCurveAct + toggleShowAllCurveAct, + expand, + onExapnd }) => { let subLayoutValues = []; if (subLayoutsInfo) { @@ -96,15 +130,11 @@ const GraphSelectionPanel = ({ const { color } = spectra; - let filename = ''; - if (entityFileNames && spectraIdx < entityFileNames.length) { - filename = entityFileNames[spectraIdx]; - } return { name: `${idx + 1}.`, idx: spectraIdx, color, - filename + label: displayName(spectra, spectraIdx, entityFileNames) }; }); } catch (e) { @@ -115,19 +145,17 @@ const GraphSelectionPanel = ({ const { color } = spectra; - let filename = ''; - if (entityFileNames && idx < entityFileNames.length) { - filename = entityFileNames[idx]; - } return { name: `${idx + 1}.`, idx, color, - filename + label: displayName(spectra, idx, entityFileNames) }; }); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, { "data-testid": "GraphSelectionPanel", + expanded: expand, + onChange: onExapnd, disableGutters: true, sx: { '&.MuiAccordion-root.Mui-expanded': { @@ -181,58 +209,10 @@ const GraphSelectionPanel = ({ }, 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)) + children: itemsSubLayout.map(item => renderCurveItem(classes, item, curveIdx, onChange)) })] }) : /*#__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)) + children: items.map(item => renderCurveItem(classes, item, curveIdx, onChange)) })] }); }; @@ -254,7 +234,7 @@ GraphSelectionPanel.propTypes = { curveSt: _propTypes.default.object.isRequired, selectCurveAct: _propTypes.default.func.isRequired, entityFileNames: _propTypes.default.array.isRequired, - subLayoutsInfo: _propTypes.default.array, + subLayoutsInfo: _propTypes.default.object, 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 index 66cbcca9..cce814a6 100644 --- a/dist/components/panel/index.js +++ b/dist/components/panel/index.js @@ -48,7 +48,7 @@ class PanelViewer extends _react.default.Component { constructor(props) { super(props); this.state = { - expand: 'info' + expand: ['info', 'graph'] }; this.onExapnd = this.onExapnd.bind(this); this.handleDescriptionChanged = this.handleDescriptionChanged.bind(this); @@ -63,7 +63,7 @@ class PanelViewer extends _react.default.Component { const { expand } = this.state; - const nextExpand = input === expand ? '' : input; + const nextExpand = expand.includes(input) ? expand.filter(item => item !== input) : [...expand, input]; this.setState({ expand: nextExpand }); @@ -95,6 +95,7 @@ class PanelViewer extends _react.default.Component { const onExapndCompare = () => this.onExapnd('compare'); const onExapndCyclicVolta = () => this.onExapnd('cyclicvolta'); const onExapndGraphSelection = () => this.onExapnd('graph'); + const isExpanded = name => expand.includes(name); const { listCurves } = curveSt; @@ -108,14 +109,14 @@ class PanelViewer extends _react.default.Component { children: [hideGraphSelection ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_graph_selection.default, { jcampIdx: jcampIdx, entityFileNames: entityFileNames, - expand: expand === 'graph', + expand: isExpanded('graph'), onExapnd: onExapndGraphSelection, subLayoutsInfo: subLayoutsInfo }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_info.default, { feature: feature, integration: integration, editorOnly: editorOnly, - expand: expand === 'info', + expand: isExpanded('info'), molSvg: molSvg, exactMass: exactMass, onExapnd: onExapndInfo, @@ -123,18 +124,18 @@ class PanelViewer extends _react.default.Component { canChangeDescription: canChangeDescription, onDescriptionChanged: this.handleDescriptionChanged }), _cfg.default.hidePanelPeak(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_peaks.default, { - expand: expand === 'peak', + expand: isExpanded('peak'), onExapnd: onExapndPeak }), _cfg.default.hidePanelMpy(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, { - expand: expand === 'mpy', + expand: isExpanded('mpy'), onExapnd: onExapndMpy }), _cfg.default.hidePanelCompare(layoutSt) || listCurves.length > 1 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_compare.default, { - expand: expand === 'compare', + expand: isExpanded('compare'), onExapnd: onExapndCompare }), _cfg.default.hidePanelCyclicVolta(layoutSt) || hideCyclicVolta ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_cyclic_voltamery_data.default, { jcampIdx: jcampIdx, feature: feature, - expand: expand === 'cyclicvolta', + expand: isExpanded('cyclicvolta'), onExapnd: onExapndCyclicVolta, userManualLink: userManualLink ? userManualLink.cv : undefined })] diff --git a/src/components/cmd_bar/01_viewer.js b/src/components/cmd_bar/01_viewer.js index 3837f6bc..34af34c3 100644 --- a/src/components/cmd_bar/01_viewer.js +++ b/src/components/cmd_bar/01_viewer.js @@ -48,24 +48,21 @@ const Viewer = ({ { - hideCmdAnaViewerSt + (hideCmdAnaViewerSt || disableCmdAnaViewerSt) ? null : ( Analysis Viewer}> - - - - - + + + ) } diff --git a/src/components/cmd_bar/03_peak.js b/src/components/cmd_bar/03_peak.js index aa219869..c780e18c 100644 --- a/src/components/cmd_bar/03_peak.js +++ b/src/components/cmd_bar/03_peak.js @@ -50,6 +50,15 @@ const Peak = ({ clearAllPeaksAct({ curveIdx, dataPeaks }); } }; + const showAddPeak = !disableAddPeakSt; + const showRmPeak = !disableRmPeakSt; + const showSetRef = !disableSetRefSt; + const showClearAll = !disableRmPeakSt; + + if (!showAddPeak && !showRmPeak && !showSetRef && !showClearAll) { + return null; + } + if (isHandleMaxAndMinPeaksSt) { const { spectraList } = cyclicVoltaState; const spectra = spectraList[curveIdx]; @@ -68,48 +77,58 @@ const Peak = ({ return ( - Add Peak}> - - - P+ - - - - Remove Peak}> - - Add Peak}> + + + P+ + + + + ) : null + } + { + showRmPeak ? ( + Remove Peak}> + + + P- + + + + ) : null + } + { + showClearAll ? ( + - P- - - - - - P - x - + P + x + + ) : null + } { - !disableSetRefSt ? ( + showSetRef ? ( Set Reference}> diff --git a/src/components/cmd_bar/04_integration.js b/src/components/cmd_bar/04_integration.js index 679a86da..8ae4f84c 100644 --- a/src/components/cmd_bar/04_integration.js +++ b/src/components/cmd_bar/04_integration.js @@ -55,7 +55,7 @@ const styles = () => ( const iconSize = '16px'; const setFactor = ( - classes, isDisable, integrationSt, setIntegrationFkrAct, curveIdx, + classes, integrationSt, setIntegrationFkrAct, curveIdx, ) => { const onFactorChanged = (e) => { e.target.blur(); @@ -83,7 +83,6 @@ const setFactor = ( return ( Add Integration}> @@ -154,13 +157,12 @@ const Integration = ({ 'btn-add-inter', ) } - disabled={isDisableSt} onClick={onSweepIntegtAdd} > { @@ -180,46 +182,38 @@ const Integration = ({ 'btn-remove-inter', ) } - disabled={isDisableSt} onClick={onSweepIntegtRm} > - - { - ignoreRef - ? null - : ( - Set Integration Reference}> - - - - - - - ) - } + Set Integration Reference}> + + + + + + { showIntegSplitToolsSt ? ( @@ -233,13 +227,12 @@ const Integration = ({ 'btn-split-inter', ) } - disabled={isDisableSt} onClick={onSweepIntegtSplit} > { @@ -259,13 +252,12 @@ const Integration = ({ 'btn-visual-split-inter', ) } - disabled={isDisableSt} onClick={onSweepIntegtVisualSplit} > { @@ -283,7 +275,7 @@ const Integration = ({ { !ignoreRef ? setFactor( - classes, isDisableSt, integrationSt, setIntegrationFkrAct, curveIdx, + classes, integrationSt, setIntegrationFkrAct, curveIdx, ) : null } @@ -294,7 +286,7 @@ const Integration = ({ x diff --git a/src/components/cmd_bar/05_multiplicity.js b/src/components/cmd_bar/05_multiplicity.js index fca449f7..d5b0b02a 100644 --- a/src/components/cmd_bar/05_multiplicity.js +++ b/src/components/cmd_bar/05_multiplicity.js @@ -38,6 +38,10 @@ const Multiplicity = ({ const { curveIdx } = curveSt; const onClearAll = () => clearMpyAllAct({ curveIdx }); + if (disableAddMpySt) { + return null; + } + return ( Add Multiplicity}> @@ -49,7 +53,6 @@ const Multiplicity = ({ 'btn-sv-bar-addmpy', ) } - disabled={disableAddMpySt} onClick={onSweepMutAdd} > J+ @@ -65,7 +68,6 @@ const Multiplicity = ({ 'btn-sv-bar-rmmpy', ) } - disabled={disableRmMpySt} onClick={onOneMutAdd} > J- @@ -81,7 +83,6 @@ const Multiplicity = ({ 'btn-sv-bar-addpeakmpy', ) } - disabled={disableMpyPeakSt} onClick={onPeakMutAdd} > JP+ @@ -97,25 +98,19 @@ const Multiplicity = ({ 'btn-sv-bar-rmpeakmpy', ) } - disabled={disableMpyPeakSt} onClick={onPeakMutRm} > JP- - { - disableAddMpySt ? null - : // eslint-disable-line - ( - - Jx - - ) - } + + Jx + ); }; diff --git a/src/components/cmd_bar/07_pecker.js b/src/components/cmd_bar/07_pecker.js index 4b8cf4ee..3029e6e7 100644 --- a/src/components/cmd_bar/07_pecker.js +++ b/src/components/cmd_bar/07_pecker.js @@ -97,9 +97,12 @@ const Pecker = ({ hasRefPeaks = hasRefPeak; } + if (Cfg.hidePanelCyclicVolta(layoutSt)) { + return null; + } + return ( - (!Cfg.hidePanelCyclicVolta(layoutSt)) ? ( - + Add Pecker}> - ) - : () ); }; diff --git a/src/components/cmd_bar/index.js b/src/components/cmd_bar/index.js index 450c109d..f4d98ee0 100644 --- a/src/components/cmd_bar/index.js +++ b/src/components/cmd_bar/index.js @@ -23,6 +23,7 @@ import ChangeAxes from './r08_change_axes'; import Detector from './r09_detector'; import CvDensityControls from './r10_cv_density'; import Format from '../../helpers/format'; +import Cfg from '../../helpers/cfg'; const styles = () => ( Object.assign( @@ -71,6 +72,8 @@ const CmdBar = ({ prependLcMsToolbar, }) => { const isCvLayout = Format.isCyclicVoltaLayout(layoutSt); + const hideIntegration = isCvLayout || Cfg.btnCmdIntg(layoutSt); + const hideMultiplicity = isCvLayout || Cfg.btnCmdMpy(layoutSt); const rightCluster = ( <> @@ -117,8 +120,8 @@ const CmdBar = ({ - {isCvLayout ? null : } - {isCvLayout ? null : } + {hideIntegration ? null : } + {hideMultiplicity ? null : } ) diff --git a/src/components/cmd_bar/r05_submit_btn.js b/src/components/cmd_bar/r05_submit_btn.js index 428b031c..acf1690f 100644 --- a/src/components/cmd_bar/r05_submit_btn.js +++ b/src/components/cmd_bar/r05_submit_btn.js @@ -172,6 +172,7 @@ const buildSpectrumPayload = ({ return { peaks: peaksEdit, layout: layoutSt, + xUnit: xLabel, shift, scan, thres, @@ -255,7 +256,10 @@ const onClickCb = ( } return spectrumPayload; }); + const selectedIdx = Number.isFinite(curveSt?.curveIdx) ? curveSt.curveIdx : 0; + const selectedSpectrumPayload = spectraList[selectedIdx] || spectraList[0] || {}; const payload = { + ...selectedSpectrumPayload, spectra_list: spectraList, }; if (lcmsGlobalFields) { @@ -275,6 +279,7 @@ const BtnSubmit = ({ waveLengthSt, cyclicvoltaSt, curveSt, curveList, axesUnitsSt, detectorSt, metaSt, hplcMsSt, + disabled, className, children, }) => { // const disBtn = peaksEdit.length === 0 || statusSt.btnSubmit || disabled; const { dscMetaData } = metaSt; @@ -303,14 +308,16 @@ const BtnSubmit = ({ if (!operation) return null; return ( - Submit}> + {operation.name || 'Submit'}}> - + {children || } ); @@ -375,6 +382,9 @@ BtnSubmit.propTypes = { detectorSt: PropTypes.object.isRequired, metaSt: PropTypes.object.isRequired, hplcMsSt: PropTypes.object, + disabled: PropTypes.bool, + className: PropTypes.string, + children: PropTypes.node, }; BtnSubmit.defaultProps = { diff --git a/src/components/cmd_bar/r07_wavelength_btn.js b/src/components/cmd_bar/r07_wavelength_btn.js index ebdabc32..a835245b 100644 --- a/src/components/cmd_bar/r07_wavelength_btn.js +++ b/src/components/cmd_bar/r07_wavelength_btn.js @@ -31,9 +31,7 @@ const styles = () => ( const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWavelengthAct) => { if (!Format.isXRDLayout(layoutSt)) { - return ( - - ); + return null; } const onChange = (e) => updateWavelengthAct(e.target.value); @@ -72,11 +70,14 @@ const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWavelengthAct) const Wavelength = ({ classes, waveLengthSt, layoutSt, updateWavelengthAct, -}) => ( - - { wavelengthSelect(classes, waveLengthSt, layoutSt, updateWavelengthAct) } - -); +}) => { + if (!Format.isXRDLayout(layoutSt)) return null; + return ( + + { wavelengthSelect(classes, waveLengthSt, layoutSt, updateWavelengthAct) } + + ); +}; const mapStateToProps = (state, props) => ( // eslint-disable-line { diff --git a/src/components/cmd_bar/r08_change_axes.js b/src/components/cmd_bar/r08_change_axes.js index 6ceb4199..62a04537 100644 --- a/src/components/cmd_bar/r08_change_axes.js +++ b/src/components/cmd_bar/r08_change_axes.js @@ -124,9 +124,7 @@ const axisY = (classes, layoutSt, axesUnitsSt, updateYAxisAct, curveSt) => { const showSelect = (classes, layoutSt, curveSt, axesUnitsSt, updateXAxisAct, updateYAxisAct) => { if (!listLayoutToShow.includes(layoutSt)) { - return ( - - ); + return null; } return ( @@ -151,6 +149,8 @@ const ChangeAxes = ({ } }, [layoutSt, axes, curveIdx, updateYAxisAct]); + if (!listLayoutToShow.includes(layoutSt)) return null; + return ( { showSelect(classes, layoutSt, curveSt, axesUnitsSt, updateXAxisAct, updateYAxisAct) } diff --git a/src/components/cmd_bar/r09_detector.js b/src/components/cmd_bar/r09_detector.js index 2ab696c9..d2116b5d 100644 --- a/src/components/cmd_bar/r09_detector.js +++ b/src/components/cmd_bar/r09_detector.js @@ -31,9 +31,7 @@ const styles = () => ( const detectorSelect = (classes, detectorSt, curveSt, layoutSt, updateDetectorAct) => { if (!Format.isSECLayout(layoutSt)) { - return ( - - ); + return null; } const { curveIdx } = curveSt; @@ -85,11 +83,14 @@ const detectorSelect = (classes, detectorSt, curveSt, layoutSt, updateDetectorAc const Detector = ({ classes, detectorSt, curveSt, layoutSt, updateDetectorAct, -}) => ( - - { detectorSelect(classes, detectorSt, curveSt, layoutSt, updateDetectorAct) } - -); +}) => { + if (!Format.isSECLayout(layoutSt)) return null; + return ( + + { detectorSelect(classes, detectorSt, curveSt, layoutSt, updateDetectorAct) } + + ); +}; const mapStateToProps = (state, _props) => ( // eslint-disable-line { diff --git a/src/components/cmd_bar/r10_cv_density.js b/src/components/cmd_bar/r10_cv_density.js index 12218bb1..a74ddd4e 100644 --- a/src/components/cmd_bar/r10_cv_density.js +++ b/src/components/cmd_bar/r10_cv_density.js @@ -42,7 +42,7 @@ const CvDensityControls = ({ classes, layoutSt, areaValue, areaUnit, useCurrentDensity, setAreaValueAct, setAreaUnitAct, toggleDensityAct, }) => { - if (layoutSt !== LIST_LAYOUT.CYCLIC_VOLTAMMETRY) return ; + if (layoutSt !== LIST_LAYOUT.CYCLIC_VOLTAMMETRY) return null; const handleAreaChange = (e) => { const raw = e.target.value; diff --git a/src/components/panel/graph_selection.js b/src/components/panel/graph_selection.js index 60316157..a2d546ce 100644 --- a/src/components/panel/graph_selection.js +++ b/src/components/panel/graph_selection.js @@ -46,10 +46,48 @@ const styles = () => ({ }, }); +const fallbackName = (entityFileNames, idx) => { + if (entityFileNames && idx < entityFileNames.length) { + return entityFileNames[idx]; + } + return ''; +}; + +const displayName = (spectra, idx, entityFileNames) => ( + spectra?.title + || spectra?.feature?.title + || spectra?.spectrum?.title + || fallbackName(entityFileNames, idx) + || `Spectrum ${idx + 1}` +); + +const renderCurveItem = (classes, item, curveIdx, onChange) => ( + onChange(item.idx)} + className={ + classNames((item.idx === curveIdx ? classes.curveSelected : classes.curveDefault)) // eslint-disable-line + } + > + + { item.name } + +
+ { + item.label !== '' ? { item.label } : null // eslint-disable-line + } +
+
+
+); + const GraphSelectionPanel = ({ classes, curveSt, entityFileNames, subLayoutsInfo, layoutSt, - selectCurveAct, toggleShowAllCurveAct, + selectCurveAct, toggleShowAllCurveAct, expand, onExapnd, }) => { let subLayoutValues = []; if (subLayoutsInfo) { @@ -89,33 +127,37 @@ const GraphSelectionPanel = ({ let itemsSubLayout = []; if (selectedSubLayout && subLayoutValues.length > 1) { const subLayout = subLayoutsInfo?.[resolvedSelectedSubLayout]; - itemsSubLayout = Array.isArray(subLayout) ? 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, - }; - }) : []; + try { + itemsSubLayout = Array.isArray(subLayout) ? subLayout.map((spectra, idx) => { + const spectraIdx = spectra.curveIdx; + const { color } = spectra; + return { + name: `${idx + 1}.`, + idx: spectraIdx, + color, + label: displayName(spectra, spectraIdx, entityFileNames), + }; + }) : []; + } 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, + name: `${idx + 1}.`, + idx, + color, + label: displayName(spectra, idx, entityFileNames), }; }); return ( { - itemsSubLayout.map((item) => ( - onChange(item.idx)} - className={ - classNames((item.idx === curveIdx ? classes.curveSelected : classes.curveDefault)) // eslint-disable-line - } - > - - { item.name } - -
- { - item.filename !== '' ? File: { item.filename } : null // eslint-disable-line - } -
-
-
- )) + itemsSubLayout.map((item) => renderCurveItem(classes, item, curveIdx, onChange)) }
@@ -201,28 +222,7 @@ const GraphSelectionPanel = ({ : ( { - items.map((item) => ( - onChange(item.idx)} - className={ - classNames((item.idx === curveIdx ? classes.curveSelected : classes.curveDefault)) // eslint-disable-line - } - > - - { item.name } - -
- { - item.filename !== '' ? File: { item.filename } : null // eslint-disable-line - } -
-
-
- )) + items.map((item) => renderCurveItem(classes, item, curveIdx, onChange)) }
) diff --git a/src/components/panel/index.js b/src/components/panel/index.js index 7461dc40..c4ae356d 100644 --- a/src/components/panel/index.js +++ b/src/components/panel/index.js @@ -47,7 +47,7 @@ class PanelViewer extends React.Component { super(props); this.state = { - expand: 'info', + expand: ['info', 'graph'], }; this.onToggleExpand = this.onToggleExpand.bind(this); @@ -63,7 +63,9 @@ class PanelViewer extends React.Component { onToggleExpand(input) { const { expand } = this.state; - const nextExpand = input === expand ? '' : input; + const nextExpand = expand.includes(input) + ? expand.filter((item) => item !== input) + : [...expand, input]; this.setState({ expand: nextExpand }); } @@ -81,6 +83,7 @@ class PanelViewer extends React.Component { const onExpandCompare = () => this.onToggleExpand('compare'); const onExpandCyclicVolta = () => this.onToggleExpand('cyclicvolta'); const onExpandGraphSelection = () => this.onToggleExpand('graph'); + const isExpanded = (name) => expand.includes(name); const { listCurves } = curveSt; const curveCount = Array.isArray(listCurves) ? listCurves.length : 0; const hideGraphSelection = curveCount <= 1 || Format.isLCMsLayout(layoutSt); @@ -91,13 +94,13 @@ class PanelViewer extends React.Component { - { hideGraphSelection ? null : } + { hideGraphSelection ? null : } - { Cfg.hidePanelPeak(layoutSt) ? null : } - { Cfg.hidePanelMpy(layoutSt) ? null : } - { (Cfg.hidePanelCompare(layoutSt) || curveCount > 1) ? null : } + { Cfg.hidePanelPeak(layoutSt) ? null : } + { Cfg.hidePanelMpy(layoutSt) ? null : } + { (Cfg.hidePanelCompare(layoutSt) || listCurves.length > 1) ? null : } { (Cfg.hidePanelCyclicVolta(layoutSt) || hideCyclicVolta) ? null : ( From 24c0175f093bbcc774aa9e17003a2b507284b8f1 Mon Sep 17 00:00:00 2001 From: Nicolass67 Date: Wed, 10 Jun 2026 14:14:44 +0200 Subject: [PATCH 3/7] fix(comparison): align per-curve shift, integrations and multiplicity in multi viewer --- dist/actions/ui.js | 7 +- dist/app.js | 8 +- dist/components/cmd_bar/r05_submit_btn.js | 12 +- dist/components/d3_line/line_focus.js | 11 +- dist/components/d3_multi/index.js | 22 +++- dist/components/d3_multi/multi_focus.js | 44 ++------ dist/components/d3_rect/index.js | 6 + dist/components/d3_rect/rect_focus.js | 22 +++- dist/components/panel/graph_selection.js | 86 +++++++------- dist/components/panel/index.js | 4 +- dist/components/panel/info.js | 60 +++++----- dist/helpers/chem.js | 16 +-- dist/helpers/compass.js | 7 ++ dist/helpers/extractPeaksEdit.js | 20 +--- dist/helpers/format.js | 98 +++++++++++++--- dist/helpers/init.js | 30 ++++- dist/helpers/shift.js | 15 ++- dist/layer_init.js | 64 +++++++++-- dist/reducers/reducer_curve.js | 45 ++++++-- dist/reducers/reducer_edit_peak.js | 4 + dist/reducers/reducer_integration.js | 26 +++-- dist/reducers/reducer_multiplicity.js | 23 +++- dist/reducers/reducer_shift.js | 10 +- dist/reducers/reducer_threshold.js | 4 + dist/sagas/saga_manager.js | 45 ++++---- dist/sagas/saga_multi_entities.js | 36 +++++- dist/sagas/saga_multiplicity.js | 34 +++--- dist/sagas/saga_ui.js | 34 +++--- src/__tests__/units/helpers/format.test.tsx | 55 ++++++++- src/__tests__/units/helpers/shift.test.tsx | 21 +++- .../units/reducers/reducer_curve.test.tsx | 18 +++ .../reducers/reducer_integration.test.tsx | 39 +++++++ src/actions/ui.js | 8 ++ src/app.js | 6 +- src/components/cmd_bar/r05_submit_btn.js | 10 +- src/components/d3_line/line_focus.js | 10 +- src/components/d3_multi/index.js | 29 ++++- src/components/d3_multi/multi_focus.js | 51 +++------ src/components/panel/graph_selection.js | 66 ++++++----- src/components/panel/index.js | 2 +- src/components/panel/info.js | 50 +-------- src/helpers/chem.js | 13 +-- src/helpers/extractPeaksEdit.js | 17 +-- src/helpers/format.js | 106 +++++++++++++++--- src/helpers/shift.js | 10 +- src/layer_init.js | 55 +++++++-- src/reducers/reducer_curve.js | 29 ++++- src/reducers/reducer_edit_peak.js | 4 +- src/reducers/reducer_integration.js | 21 ++-- src/reducers/reducer_multiplicity.js | 20 ++-- src/reducers/reducer_shift.js | 8 +- src/reducers/reducer_threshold.js | 2 + src/sagas/saga_manager.js | 42 +++---- src/sagas/saga_multi_entities.js | 35 +++++- src/sagas/saga_multiplicity.js | 33 +++--- src/sagas/saga_ui.js | 33 +++--- 56 files changed, 1043 insertions(+), 543 deletions(-) diff --git a/dist/actions/ui.js b/dist/actions/ui.js index aaa15a98..7a0e7507 100644 --- a/dist/actions/ui.js +++ b/dist/actions/ui.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.setUiViewerType = exports.setUiSweepType = exports.selectUiSweep = exports.scrollUiWheel = exports.clickUiTarget = void 0; +exports.setUiViewerType = exports.setUiSweepType = exports.selectUiSweep = exports.scrollUiWheel = exports.restoreSweepExtent = exports.clickUiTarget = void 0; var _action_type = require("../constants/action_type"); const setUiViewerType = payload => ({ type: _action_type.UI.VIEWER.SET_TYPE, @@ -26,6 +26,11 @@ const scrollUiWheel = payload => ({ payload }); exports.scrollUiWheel = scrollUiWheel; +const restoreSweepExtent = payload => ({ + type: _action_type.UI.SWEEP.SELECT_ZOOMIN, + payload +}); +exports.restoreSweepExtent = restoreSweepExtent; const clickUiTarget = (payload, onPeak, voltammetryPeakIdx = 0, jcampIdx = 0, onPecker = false) => ({ type: _action_type.UI.CLICK_TARGET, payload, diff --git a/dist/app.js b/dist/app.js index a6bd495c..9821f72f 100644 --- a/dist/app.js +++ b/dist/app.js @@ -62,7 +62,9 @@ const SpectraEditor = ({ multiEntities, multiMolSvgs, entityFileNames, - userManualLink + userManualLink, + curveIdx, + sweepExtent }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactRedux.Provider, { store: store, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.StyledEngineProvider, { @@ -70,6 +72,8 @@ const SpectraEditor = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_init.default, { entity: entity, multiEntities: multiEntities, + curveIdx: curveIdx, + sweepExtent: sweepExtent, entityFileNames: entityFileNames, userManualLink: userManualLink, others: others, @@ -92,6 +96,8 @@ exports.SpectraEditor = SpectraEditor; SpectraEditor.propTypes = { entity: _propTypes.default.object.isRequired, multiEntities: _propTypes.default.array, + curveIdx: _propTypes.default.number, + sweepExtent: _propTypes.default.object, entityFileNames: _propTypes.default.array, others: _propTypes.default.object, cLabel: _propTypes.default.string, diff --git a/dist/components/cmd_bar/r05_submit_btn.js b/dist/components/cmd_bar/r05_submit_btn.js index 88a350a0..c4582990 100644 --- a/dist/components/cmd_bar/r05_submit_btn.js +++ b/dist/components/cmd_bar/r05_submit_btn.js @@ -154,10 +154,11 @@ const buildSpectrumPayload = ({ axesUnitsSt, detectorSt, dscMetaData, + feature, ...optionalBooleanFlags }; }; -const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, analysis, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaSt, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature) => () => { +const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, analysis, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaSt, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature, sweepExtentSt) => () => { const defaultCurves = feature ? [{ feature }] : []; @@ -199,6 +200,9 @@ const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, ana curveIdx: curveSt.curveIdx }; } + if (sweepExtentSt?.xExtent || sweepExtentSt?.yExtent) { + payload.sweepExtent = sweepExtentSt; + } operationValue(payload); }; const BtnSubmit = ({ @@ -223,6 +227,7 @@ const BtnSubmit = ({ axesUnitsSt, detectorSt, metaSt, + sweepExtentSt, disabled, className, children @@ -260,7 +265,7 @@ const BtnSubmit = ({ className: (0, _classnames.default)('btn-sv-bar-submit', className), color: "primary", disabled: disabled, - onClick: onClickCb(operation.value, isAscend, isIntensity, layoutSt, shiftSt, forecastSt.predictions, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaPayload, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature), + onClick: onClickCb(operation.value, isAscend, isIntensity, layoutSt, shiftSt, forecastSt.predictions, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaPayload, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature, sweepExtentSt), children: children || /*#__PURE__*/(0, _jsxRuntime.jsx)(_PlayCircleOutline.default, { className: classes.icon }) @@ -285,7 +290,8 @@ const mapStateToProps = (state, props) => ( curveList: state.curve.listCurves, axesUnitsSt: state.axesUnits, detectorSt: state.detector, - metaSt: state.meta + metaSt: state.meta, + sweepExtentSt: state.ui.sweepExtent }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch); BtnSubmit.propTypes = { diff --git a/dist/components/d3_line/line_focus.js b/dist/components/d3_line/line_focus.js index 30004133..922a2379 100644 --- a/dist/components/d3_line/line_focus.js +++ b/dist/components/d3_line/line_focus.js @@ -479,14 +479,11 @@ class LineFocus { 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; + const hasMpy = !isDisable && selectedMulti?.stack?.length > 0; + const mpys = hasMpy ? selectedMulti.stack : []; + const smExtext = hasMpy ? selectedMulti.smExtext : false; + const shift = hasMpy ? selectedMulti.shift : 0; // rescale for zoom const { xt diff --git a/dist/components/d3_multi/index.js b/dist/components/d3_multi/index.js index a179f126..3f28c98a 100644 --- a/dist/components/d3_multi/index.js +++ b/dist/components/d3_multi/index.js @@ -28,6 +28,12 @@ const buildResetPayload = (feature, curveSt) => ({ ...feature, curveIdx: curveSt.curveIdx }); +const hasActiveZoom = sweepExtentSt => { + if (!sweepExtentSt) return false; + return !!(sweepExtentSt.xExtent || sweepExtentSt.yExtent); +}; +const canSkipReset = (sweepExtentSt, layoutSt, feature) => hasActiveZoom(sweepExtentSt) && layoutSt === feature?.operation?.layout; +const isSameMultiComparison = (oldEntities, newEntities) => Array.isArray(oldEntities) && Array.isArray(newEntities) && oldEntities.length > 0 && oldEntities.length === newEntities.length; class ViewerMulti extends _react.default.Component { constructor(props) { super(props); @@ -72,12 +78,15 @@ class ViewerMulti extends _react.default.Component { isHidden, resetAllAct, cyclicvoltaSt, + shiftSt, integationSt, mtplySt, axesUnitsSt } = this.props; (0, _draw.drawDestroy)(this.rootKlass); - resetAllAct(buildResetPayload(feature, curveSt)); + if (!canSkipReset(sweepExtentSt, layoutSt, feature)) { + resetAllAct(buildResetPayload(feature, curveSt)); + } let xxLabel = xLabel; let yyLabel = yLabel; if (axesUnitsSt) { @@ -120,6 +129,7 @@ class ViewerMulti extends _react.default.Component { sweepExtentSt, isUiNoBrushSt, cyclicvoltaSt, + shiftSt, integationSt, mtplySt }); @@ -144,6 +154,7 @@ class ViewerMulti extends _react.default.Component { isUiNoBrushSt, isHidden, cyclicvoltaSt, + shiftSt, integationSt, mtplySt, axesUnitsSt @@ -194,6 +205,7 @@ class ViewerMulti extends _react.default.Component { sweepExtentSt, isUiNoBrushSt, cyclicvoltaSt, + shiftSt, integationSt, mtplySt }); @@ -259,7 +271,7 @@ class ViewerMulti extends _react.default.Component { curveSt } = this.props; const oldEntities = prevProps.entities; - if (oldEntities !== entities) { + if (oldEntities !== entities && !isSameMultiComparison(oldEntities, entities)) { resetAllAct(buildResetPayload(feature, curveSt)); } } @@ -281,6 +293,7 @@ class ViewerMulti extends _react.default.Component { isHidden, resetAllAct, cyclicvoltaSt, + shiftSt, integationSt, mtplySt, axesUnitsSt, @@ -292,7 +305,7 @@ class ViewerMulti extends _react.default.Component { const size = this.getTargetSize(layoutSt); this.currentSize = size; (0, _draw.drawDestroy)(this.rootKlass); - if (shouldReset) { + if (shouldReset && !canSkipReset(sweepExtentSt, layoutSt, feature)) { resetAllAct(buildResetPayload(feature, curveSt)); } let xxLabel = xLabel; @@ -340,6 +353,7 @@ class ViewerMulti extends _react.default.Component { sweepExtentSt, isUiNoBrushSt, cyclicvoltaSt, + shiftSt, integationSt, mtplySt }); @@ -372,6 +386,7 @@ const mapStateToProps = (state, props) => ({ sweepExtentSt: state.ui.sweepExtent, isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0, cyclicvoltaSt: state.cyclicvolta, + shiftSt: state.shift, maxminPeakSt: (0, _chem.Feature2MaxMinPeak)(state, props), integationSt: state.integration.present, mtplySt: state.multiplicity.present, @@ -408,6 +423,7 @@ ViewerMulti.propTypes = { scrollUiWheelAct: _propTypes.default.func.isRequired, isHidden: _propTypes.default.bool, cyclicvoltaSt: _propTypes.default.object.isRequired, + shiftSt: _propTypes.default.object.isRequired, maxminPeakSt: _propTypes.default.object, addNewCylicVoltaPairPeakAct: _propTypes.default.func.isRequired, addCylicVoltaMaxPeakAct: _propTypes.default.func.isRequired, diff --git a/dist/components/d3_multi/multi_focus.js b/dist/components/d3_multi/multi_focus.js index e646b50c..f229f8ab 100644 --- a/dist/components/d3_multi/multi_focus.js +++ b/dist/components/d3_multi/multi_focus.js @@ -13,6 +13,7 @@ var _compass = require("../../helpers/compass"); var _list_layout = require("../../constants/list_layout"); var _format = _interopRequireDefault(require("../../helpers/format")); var _chem = require("../../helpers/chem"); +var _shift = require("../../helpers/shift"); var _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _focus = require("../../helpers/focus"); var _integration = require("../../helpers/integration"); @@ -190,7 +191,7 @@ class MultiFocus { transformYValue(y) { return y * this.yTransformFactor; } - setDataParams(filterSeed, peaks, tTrEndPts, tSfPeaks, layout, cyclicvoltaSt, jcampIdx = 0) { + setDataParams(filterSeed, peaks, tTrEndPts, tSfPeaks, layout, cyclicvoltaSt, shiftSt, jcampIdx = 0) { this.data = []; this.otherLineData = []; let filterSubLayoutValue = null; @@ -202,7 +203,7 @@ class MultiFocus { feature, color } = entry; - const offset = (0, _chem.GetCyclicVoltaPreviousShift)(cyclicvoltaSt, jcampIdx); + const offset = _format.default.isCyclicVoltaLayout(layout) ? (0, _chem.GetCyclicVoltaPreviousShift)(cyclicvoltaSt, idx) : (0, _shift.shiftOffsetAtIndex)(shiftSt, idx); let currData = (0, _chem.convertTopic)(topic, layout, feature, offset); if (idx === jcampIdx) { if (!_format.default.isCyclicVoltaLayout(layout)) { @@ -720,36 +721,11 @@ class MultiFocus { 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; + const hasMpy = !isDisable && selectedMulti?.stack?.length > 0; + const mpys = hasMpy ? selectedMulti.stack : []; + const smExtext = hasMpy ? selectedMulti.smExtext : false; + const shift = hasMpy ? selectedMulti.shift : 0; // rescale for zoom const { xt @@ -886,6 +862,7 @@ class MultiFocus { sweepExtentSt, isUiNoBrushSt, cyclicvoltaSt, + shiftSt, integationSt, mtplySt }) { @@ -901,7 +878,7 @@ class MultiFocus { 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); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, shiftSt, jcampIdx); (0, _compass.MountCompass)(this); this.axis = (0, _mount.MountAxis)(this); this.path = (0, _mount.MountPath)(this, this.pathColor); @@ -938,6 +915,7 @@ class MultiFocus { sweepExtentSt, isUiNoBrushSt, cyclicvoltaSt, + shiftSt, integationSt, mtplySt }) { @@ -950,7 +928,7 @@ class MultiFocus { const jcampIdx = curveIdx; this.isShowAllCurves = isShowAllCurve; this.entities = entities; - this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, shiftSt, jcampIdx); if (this.data && this.data.length > 0) { this.setConfig(sweepExtentSt); this.getShouldUpdate(editPeakSt); diff --git a/dist/components/d3_rect/index.js b/dist/components/d3_rect/index.js index 8c537de3..d20f50a0 100644 --- a/dist/components/d3_rect/index.js +++ b/dist/components/d3_rect/index.js @@ -50,6 +50,7 @@ class ViewerRect extends _react.default.Component { tTrEndPts, tSfPeaks, isHidden, + decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, @@ -65,6 +66,7 @@ class ViewerRect extends _react.default.Component { filterPeak, tTrEndPts, tSfPeaks, + decimal: decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -79,6 +81,7 @@ class ViewerRect extends _react.default.Component { tTrEndPts, tSfPeaks, isHidden, + decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -91,6 +94,7 @@ class ViewerRect extends _react.default.Component { filterPeak, tTrEndPts, tSfPeaks, + decimal: decimalSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -119,6 +123,7 @@ class ViewerRect extends _react.default.Component { const mapStateToProps = (state, props) => ({ seed: (0, _chem.Topic2Seed)(state, props), peak: (0, _chem.Feature2Peak)(state, props), + decimalSt: state.submit.decimal, tTrEndPts: (0, _chem.ToThresEndPts)(state, props), tSfPeaks: (0, _chem.ToShiftPeaks)(state, props), sweepExtentSt: state.ui.sweepExtent, @@ -134,6 +139,7 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ ViewerRect.propTypes = { seed: _propTypes.default.array.isRequired, peak: _propTypes.default.array.isRequired, + decimalSt: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired, cLabel: _propTypes.default.string.isRequired, xLabel: _propTypes.default.string.isRequired, yLabel: _propTypes.default.string.isRequired, diff --git a/dist/components/d3_rect/rect_focus.js b/dist/components/d3_rect/rect_focus.js index bc58f31e..2a42ac1b 100644 --- a/dist/components/d3_rect/rect_focus.js +++ b/dist/components/d3_rect/rect_focus.js @@ -11,6 +11,7 @@ var _mount = require("../../helpers/mount"); var _compass = require("../../helpers/compass"); var _converter = require("../../helpers/converter"); var _list_layout = require("../../constants/list_layout"); +var _format = _interopRequireDefault(require("../../helpers/format")); const d3 = require('d3'); class RectFocus { constructor(props) { @@ -53,6 +54,7 @@ class RectFocus { this.factor = 0.125; this.currentExtent = null; this.layout = _list_layout.LIST_LAYOUT.MS; + this.decimal = 3; this.setTip = this.setTip.bind(this); this.setDataParams = this.setDataParams.bind(this); this.create = this.create.bind(this); @@ -68,11 +70,14 @@ class RectFocus { this.tip = (0, _init.InitTip)(); this.root.call(this.tip); } - setDataParams(data, peaks, tTrEndPts, tSfPeaks) { + setDataParams(data, peaks, tTrEndPts, tSfPeaks, decimal) { this.data = [...data]; this.dataPks = [...peaks]; this.tTrEndPts = tTrEndPts; this.tSfPeaks = tSfPeaks; + if (decimal !== undefined) { + this.decimal = _format.default.clampDecimalPlaces(decimal); + } } updatePathCall(xt, yt) { this.pathCall = d3.line().x(d => xt(d.x)).y(d => yt(d.y)); @@ -131,6 +136,7 @@ class RectFocus { } = (0, _compass.TfRescale)(this); this.updatePathCall(xt, yt); const yRef = this.tTrEndPts[0].y; + const msMaxY = d3.max(this.data, row => row.y) || 0; const bars = this.bars.selectAll('rect').data(this.data); bars.exit().attr('class', 'exit').remove(); const gnd = yt(0); @@ -139,7 +145,9 @@ class RectFocus { d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'blue'); const tipParams = { d, - layout: this.layout + layout: this.layout, + msMaxY, + xDigits: this.decimal }; this.tip.show(tipParams, event.target); }).on('mouseout', (event, d) => { @@ -147,7 +155,9 @@ class RectFocus { d3.select(`#bpt${Math.round(1000 * d.x)}`).style('fill', 'red'); const tipParams = { d, - layout: this.layout + layout: this.layout, + msMaxY, + xDigits: this.decimal }; this.tip.hide(tipParams, event.target); }); @@ -174,6 +184,7 @@ class RectFocus { filterPeak, tTrEndPts, tSfPeaks, + decimal, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt @@ -183,7 +194,7 @@ class RectFocus { (0, _mount.MountClip)(this); this.root = d3.select(this.rootKlass).selectAll('.focus-main'); this.setTip(); - this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, decimal); (0, _compass.MountCompass)(this); this.axis = (0, _mount.MountAxis)(this); [this.thresLine] = (0, _mount.MountThresLine)(this, 'green'); @@ -205,12 +216,13 @@ class RectFocus { filterPeak, tTrEndPts, tSfPeaks, + decimal, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt }) { this.root = d3.select(this.rootKlass).selectAll('.focus-main'); - this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, decimal); if (this.data && this.data.length > 0) { this.setConfig(sweepExtentSt); this.drawBar(); diff --git a/dist/components/panel/graph_selection.js b/dist/components/panel/graph_selection.js index c1d9bce9..4a1536ce 100644 --- a/dist/components/panel/graph_selection.js +++ b/dist/components/panel/graph_selection.js @@ -25,29 +25,37 @@ const styles = () => ({ backgroundColor: '#eee', height: 22 }, - curve: { - width: '100%' - }, - line: { - height: '2px', - borderWidth: '0', - margin: '0' + curveItem: { + display: 'flex', + alignItems: 'center', + width: '100%', + fontSize: '0.8em', + padding: '6px 8px', + margin: 0, + cursor: 'pointer' }, curveDefault: { - backgroundColor: '#fff', - fontSize: '0.8em', - margin: '0', - padding: '10px 2px 2px 10px', - maxWidth: '95%', - overflowWrap: 'anywhere' + backgroundColor: '#fff' }, curveSelected: { - backgroundColor: '#2196f3', - fontSize: '0.8em', - color: '#fff', - padding: '10px 2px 2px 10px', - maxWidth: '95%', + backgroundColor: '#e0e0e0' + }, + curveIndex: { + flexShrink: 0, + marginRight: '4px', + fontStyle: 'italic' + }, + curveLabel: { + flexShrink: 0, + marginRight: '8px', overflowWrap: 'anywhere' + }, + colorBar: { + flex: 1, + height: '6px', + borderRadius: '1px', + minWidth: '24px', + alignSelf: 'center' } }); const fallbackName = (entityFileNames, idx) => { @@ -57,30 +65,22 @@ const fallbackName = (entityFileNames, idx) => { return ''; }; const displayName = (spectra, idx, entityFileNames) => spectra?.title || spectra?.feature?.title || spectra?.spectrum?.title || fallbackName(entityFileNames, idx) || `Spectrum ${idx + 1}`; -const renderCurveItem = (classes, item, curveIdx, onChange) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.ListItem, { +const renderCurveItem = (classes, item, curveIdx, onChange) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.ListItem, { + disablePadding: true, 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.label !== '' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { - children: item.label - }) : null // eslint-disable-line - ] - })] - }) + className: (0, _classnames.default)(classes.curveItem, item.idx === curveIdx ? classes.curveSelected : classes.curveDefault), + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: classes.curveIndex, + children: item.name + }), item.label !== '' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: classes.curveLabel, + children: item.label + }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: classes.colorBar, + style: { + backgroundColor: item.color + } + })] }, item.idx); const GraphSelectionPanel = ({ classes, @@ -124,7 +124,7 @@ const GraphSelectionPanel = ({ let itemsSubLayout = []; if (selectedSubLayout && subLayoutValues.length > 1) { const subLayout = subLayoutsInfo[selectedSubLayout]; - try { + if (subLayout) { itemsSubLayout = subLayout.map((spectra, idx) => { const spectraIdx = spectra.curveIdx; const { @@ -137,8 +137,6 @@ const GraphSelectionPanel = ({ label: displayName(spectra, spectraIdx, entityFileNames) }; }); - } catch (e) { - console.log(e); //eslint-disable-line } } const items = listCurves.map((spectra, idx) => { diff --git a/dist/components/panel/index.js b/dist/components/panel/index.js index cce814a6..84b9eec7 100644 --- a/dist/components/panel/index.js +++ b/dist/components/panel/index.js @@ -99,7 +99,7 @@ class PanelViewer extends _react.default.Component { const { listCurves } = curveSt; - const hideGraphSelection = listCurves === false || listCurves === undefined; + const hideGraphSelection = !Array.isArray(listCurves); return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: (0, _classnames.default)(classes.panels), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.StyledEngineProvider, { @@ -129,7 +129,7 @@ class PanelViewer extends _react.default.Component { }), _cfg.default.hidePanelMpy(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, { expand: isExpanded('mpy'), onExapnd: onExapndMpy - }), _cfg.default.hidePanelCompare(layoutSt) || listCurves.length > 1 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_compare.default, { + }), _cfg.default.hidePanelCompare(layoutSt) || !listCurves || listCurves.length > 1 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_compare.default, { expand: isExpanded('compare'), onExapnd: onExapndCompare }), _cfg.default.hidePanelCyclicVolta(layoutSt) || hideCyclicVolta ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_cyclic_voltamery_data.default, { diff --git a/dist/components/panel/info.js b/dist/components/panel/info.js index 72928355..166dbcb6 100644 --- a/dist/components/panel/info.js +++ b/dist/components/panel/info.js @@ -21,6 +21,7 @@ var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable no-mixed-operators, react/function-component-definition, react/require-default-props, max-len */ +const ELECTRON_MASS = 0.000548579909065; const styles = () => ({ chip: { margin: '1px 0 1px 0' @@ -74,11 +75,16 @@ const styles = () => ({ }, rowOddSim: { backgroundColor: '#fff', - height: 108, + height: 'auto', + minHeight: 36, lineHeight: '24px', - overflowY: 'hidden', + overflow: 'visible', overflowWrap: 'word-break' }, + simPlaceholder: { + color: 'rgba(0, 0, 0, 0.54)', + fontStyle: 'italic' + }, tHead: { fontWeight: 'bold', float: 'left', @@ -111,12 +117,21 @@ const styles = () => ({ } }); const simTitle = () => 'Simulated signals from NMRshiftDB'; -const simContent = nmrSimPeaks => nmrSimPeaks && nmrSimPeaks.sort((a, b) => a - b).join(', '); +const simContent = nmrSimPeaks => { + if (!Array.isArray(nmrSimPeaks) || nmrSimPeaks.length === 0) return ''; + return [...nmrSimPeaks].sort((a, b) => a - b).join(', '); +}; +const simPlaceholder = () => 'No simulated signals available.'; const normalizeQuillValue = val => { if (!val) return ''; if (val === '


' || val === '

') return ''; return val; }; +const formatMsExactMass = exactMass => { + const neutralMass = parseFloat(exactMass); + if (Number.isNaN(neutralMass)) return null; + return (neutralMass - ELECTRON_MASS).toFixed(6); +}; const chemSubStyle = { fontSize: '0.85em', position: 'relative', @@ -150,31 +165,6 @@ const handleDescriptionChanged = (content, delta, source, editor, onDescriptionC 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, @@ -325,6 +315,7 @@ const InfoPanel = ({ updateDSCMetaDataAct }) => { if (!feature) return null; + const msExactMass = _format.default.isMsLayout(layoutSt) && exactMass ? formatMsExactMass(exactMass) : null; const { title, observeFrequency, @@ -363,6 +354,7 @@ const InfoPanel = ({ if (integration) { originStack = integration.originStack; // eslint-disable-line } + const simulatedSignals = simContent(simulationSt.nmrSimPeaks); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, { "data-testid": "PanelInfo", expanded: expand, @@ -419,14 +411,14 @@ const InfoPanel = ({ className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'), children: renderReadableSubscript(showSolvName) })] - }) : null, _format.default.isMsLayout(layoutSt) && exactMass ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { + }) : null, msExactMass ? /*#__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: " + children: "Exact mass (M+): " }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'), - children: `${parseFloat(exactMass).toFixed(6)} g/mol` + children: `${msExactMass} g/mol` })] }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(SECData, { classes: classes, @@ -444,7 +436,7 @@ const InfoPanel = ({ 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) + children: _format.default.formatHplcAucPanel(integration, feature) })] }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(DSCData, { classes: classes, @@ -475,8 +467,8 @@ const InfoPanel = ({ }), /*#__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) + className: (0, _classnames.default)(classes.tTxt, classes.tTxtSim, !simulatedSignals && classes.simPlaceholder, 'txt-sv-panel-txt'), + children: simulatedSignals || simPlaceholder() }) })] }) : null] diff --git a/dist/helpers/chem.js b/dist/helpers/chem.js index 65dd81ef..77eb83ef 100644 --- a/dist/helpers/chem.js +++ b/dist/helpers/chem.js @@ -55,21 +55,7 @@ const getShiftOffset = (state, _) => { 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); + return (0, _shift.shiftOffsetAtIndex)(state.shift, curveIdx); }; const calcXYK = (xs, ys, maxY, offset) => { const sp = []; diff --git a/dist/helpers/compass.js b/dist/helpers/compass.js index c23573b0..e351fdaf 100644 --- a/dist/helpers/compass.js +++ b/dist/helpers/compass.js @@ -99,6 +99,13 @@ const MouseMove = (event, focus) => { 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 if (_format.default.isMsLayout(layout)) { + const maxY = d3.max(focus.data, row => row.y) || 0; + const relPct = maxY > 0 ? 100 * pt.y / maxY : 0; + const rel = maxY > 0 ? parseInt(relPct, 10) : 0; + const xPrecision = _format.default.clampDecimalPlaces(focus.decimal); + focus.root.select('.cursor-txt').attr('transform', `translate(${tx},${10})`).text(`${pt.x.toFixed(xPrecision)} (${rel})`); + focus.root.select('.cursor-txt-hz').text(''); } else { focus.root.select('.cursor-txt').attr('transform', `translate(${tx},${10})`).text(pt.x.toFixed(3)); if (freq) { diff --git a/dist/helpers/extractPeaksEdit.js b/dist/helpers/extractPeaksEdit.js index 92af43f4..e68864ec 100644 --- a/dist/helpers/extractPeaksEdit.js +++ b/dist/helpers/extractPeaksEdit.js @@ -10,31 +10,15 @@ 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 offset = _format.default.isMsLayout(layoutSt) ? 0 : (0, _shift.shiftOffsetAtIndex)(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 offset = _format.default.isMsLayout(layoutSt) ? 0 : (0, _shift.shiftOffsetAtIndex)(shiftSt, atIndex); const peaks = (0, _chem.Convert2Peak)(feature, thresSt.value, offset); return peaks; }; diff --git a/dist/helpers/format.js b/dist/helpers/format.js index b528beb8..ef31dd86 100644 --- a/dist/helpers/format.js +++ b/dist/helpers/format.js @@ -41,9 +41,19 @@ const spectraDigit = layout => { } }; const fixDigit = (input, precision) => { - const output = input || 0.0; + const output = Number(input) || 0.0; return output.toFixed(precision); }; + +/** + * Integer 0–20 for toFixed; invalid input uses fallback. + * Default 3 preserves legacy cursor precision. + */ +const clampDecimalPlaces = (value, fallback = 3) => { + const n = Number(value); + if (!Number.isFinite(n)) return fallback; + return Math.max(0, Math.min(20, Math.trunc(n))); +}; const buildData = entity => { if (!entity) return { isExist: false @@ -276,14 +286,72 @@ const formatedDLSIntensity = (peaks, maxY, decimal = 2, isAscend = true, isInten })); return ordered.map(o => `${o.x} nm (${o.y} %)`).join(', '); }; -const formatedHplcUvVis = (peaks, decimal = 2, integration) => { +const HPLC_RT_DECIMAL = 2; +const HPLC_VALUE_DECIMAL = 2; +const HPLC_RT_UNIT = 'min'; +const formatHplcRetentionTime = rt => `${fixDigit(rt, HPLC_RT_DECIMAL)} ${HPLC_RT_UNIT}`; +const formatHplcAuc = area => fixDigit(area, HPLC_VALUE_DECIMAL); +const findHplcPeakRetentionTime = (feature, xL, xU) => { + if (!feature?.data?.[0]) { + return (xL + xU) / 2; + } + const { + x, + y + } = feature.data[0]; + let maxY = -Infinity; + let rt = (xL + xU) / 2; + for (let i = 0; i < x.length; i += 1) { + if (x[i] >= xL && x[i] <= xU && y[i] > maxY) { + maxY = y[i]; + rt = x[i]; + } + } + return rt; +}; +const isSameHplcRt = (a, b) => fixDigit(a, HPLC_RT_DECIMAL) === fixDigit(b, HPLC_RT_DECIMAL); +const integrationApexRt = (inte, feature, peaks) => { + if (feature?.data?.[0]) { + return findHplcPeakRetentionTime(feature, inte.xL, inte.xU); + } + if (!Array.isArray(peaks)) return null; + const peaksInRange = peaks.filter(p => p.x >= inte.xL && p.x <= inte.xU); + if (peaksInRange.length === 0) return null; + return peaksInRange.reduce((best, p) => p.y > best.y ? p : best, peaksInRange[0]).x; +}; +const findIntegrationForPeak = (peakX, stack, peaks, feature) => { + if (!Array.isArray(stack)) return null; + const x = parseFloat(peakX); + return stack.find(s => { + if (s.xL > x || x > s.xU) return false; + const apexRt = integrationApexRt(s, feature, peaks); + return apexRt != null && isSameHplcRt(x, apexRt); + }) || null; +}; +const formatHplcAucPanel = (integration, feature) => { + if (!integration) return ''; + const stackIntegration = integration.stack; + if (!Array.isArray(stackIntegration)) return ''; + const entries = stackIntegration.filter(inte => inte.absoluteArea).map(inte => ({ + rt: findHplcPeakRetentionTime(feature, inte.xL, inte.xU), + area: inte.absoluteArea + })); + if (entries.length === 0) return ''; + const sumVal = entries.reduce((sum, e) => sum + e.area, 0); + return entries.map(e => { + const areaVal = formatHplcAuc(e.area); + const percent = fixDigit(e.area * 100 / sumVal, HPLC_VALUE_DECIMAL); + return `${formatHplcRetentionTime(e.rt)}, AUC=${areaVal} (${percent}%)`; + }).join(', '); +}; +const formatedHplcUvVis = (peaks, decimal = 2, integration, feature) => { let stack = []; if (integration) { stack = integration.stack; } let ordered = {}; peaks.forEach(p => { - const x = fixDigit(p.x, decimal); + const x = Number(p.x); const better = !ordered[x] || p.y > ordered[x]; if (better) { ordered = Object.assign({}, ordered, { @@ -292,19 +360,15 @@ const formatedHplcUvVis = (peaks, decimal = 2, integration) => { } }); ordered = Object.keys(ordered).map(k => ({ - x: k, + x: parseFloat(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})`; - } - }); - } + const rt = formatHplcRetentionTime(o.x); + const yVal = o.y.toFixed(HPLC_VALUE_DECIMAL); + const inte = findIntegrationForPeak(o.x, stack, peaks, feature); + const pStr = inte?.absoluteArea ? `${rt} (${yVal}, AUC=${formatHplcAuc(inte.absoluteArea)})` : `${rt} (${yVal})`; arrResult.push(pStr); }); return arrResult.join(', '); @@ -365,7 +429,8 @@ const peaksBody = ({ integration, atIndex = 0, waveLength, - temperature + temperature, + feature }) => { const result = rmShiftFromPeaks(peaks, shift, atIndex); const ascendFunc = (a, b) => parseFloat(a.x) - parseFloat(b.x); @@ -383,7 +448,7 @@ const peaksBody = ({ return formatedUvVis(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); } if (layout === _list_layout.LIST_LAYOUT.HPLC_UVVIS) { - return formatedHplcUvVis(ordered, decimal, integration); + return formatedHplcUvVis(ordered, decimal, integration, feature); } if (layout === _list_layout.LIST_LAYOUT.EMISSIONS) { return formatedEmissions(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); @@ -639,6 +704,7 @@ const Format = { isEmWaveLayout, isGCLayout, fixDigit, + clampDecimalPlaces, formatPeaksByPrediction, formatedMS, formatedEm, @@ -651,6 +717,8 @@ const Format = { strNumberFixedDecimal, formatedXRD, strNumberFixedLength, - inlineNotation + inlineNotation, + formatHplcAucPanel, + formatedHplcUvVis }; var _default = exports.default = Format; \ No newline at end of file diff --git a/dist/helpers/init.js b/dist/helpers/init.js index 494047e6..436c87bf 100644 --- a/dist/helpers/init.js +++ b/dist/helpers/init.js @@ -55,13 +55,33 @@ const tpDiv = (d, digits, yFactor = 1) => ` y: ${d3.format('.2~e')(d.y * (yFactor || 1))}
`; +const msPeakTpDiv = (d, relInt, digits) => ` +
+ ${_format.default.fixDigit(d.x, digits)} (${relInt}) +
+ `; +const resolveDigits = (layout, xDigits) => xDigits != null && xDigits !== '' ? _format.default.clampDecimalPlaces(xDigits, _format.default.spectraDigit(layout)) : _format.default.spectraDigit(layout); +const peakTipHtml = ({ + d, + layout, + yFactor, + xDigits, + msMaxY +}) => { + const digits = resolveDigits(layout, xDigits); + if (_format.default.isMsLayout(layout) && msMaxY > 0) { + const relPct = 100 * d.y / msMaxY; + const rel = parseInt(relPct, 10); + return msPeakTpDiv(d, rel, digits); + } + return tpDiv(d, digits, 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)); + const tip = (0, _d3Tip.default)().attr('class', 'd3-tip').html(peakTipHtml); return tip; }; exports.InitTip = InitTip; \ No newline at end of file diff --git a/dist/helpers/shift.js b/dist/helpers/shift.js index 917f161e..bffcc55e 100644 --- a/dist/helpers/shift.js +++ b/dist/helpers/shift.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.VirtalPts = exports.RealPts = exports.FromManualToOffset = exports.CalcResidualX = void 0; +exports.shiftOffsetAtIndex = 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 */ @@ -32,4 +32,15 @@ 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 +exports.RealPts = RealPts; +const shiftOffsetAtIndex = (shiftSt, atIndex = 0) => { + if (!shiftSt || !shiftSt.shifts) return 0; + const selectedShift = shiftSt.shifts[atIndex]; + if (!selectedShift) return 0; + const { + ref, + peak + } = selectedShift; + return FromManualToOffset(ref, peak); +}; +exports.shiftOffsetAtIndex = shiftOffsetAtIndex; \ No newline at end of file diff --git a/dist/layer_init.js b/dist/layer_init.js index 3df80431..113ba119 100644 --- a/dist/layer_init.js +++ b/dist/layer_init.js @@ -11,6 +11,7 @@ var _reactRedux = require("react-redux"); var _redux = require("redux"); var _styles = require("@mui/styles"); var _submit = require("./actions/submit"); +var _layout = require("./actions/layout"); var _manager = require("./actions/manager"); var _meta = require("./actions/meta"); var _jcamp = require("./actions/jcamp"); @@ -18,13 +19,32 @@ 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 _ui = require("./actions/ui"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, default-param-last */ +const hasActiveZoom = sweepExtent => { + if (!sweepExtent) return false; + return !!(sweepExtent.xExtent || sweepExtent.yExtent); +}; const styles = () => ({}); class LayerInit extends _react.default.Component { constructor(props) { super(props); + const { + sweepExtent, + restoreSweepExtentAct + } = props; + if (hasActiveZoom(sweepExtent)) { + restoreSweepExtentAct(sweepExtent); + } else { + // Clear any zoom left in the shared store by a previously opened + // spectrum, so it cannot block the RESETALL/layout sync on mount. + restoreSweepExtentAct({ + xExtent: false, + yExtent: false + }); + } this.normChange = this.normChange.bind(this); this.execReset = this.execReset.bind(this); this.initReducer = this.initReducer.bind(this); @@ -35,12 +55,14 @@ class LayerInit extends _react.default.Component { this.execReset(); this.initReducer(); this.updateOthers(); - this.updateMultiEntities(); + this.updateMultiEntities(true); } componentDidUpdate(prevProps) { this.normChange(prevProps); this.updateOthers(); - this.updateMultiEntities(); + if (prevProps.multiEntities !== this.props.multiEntities || prevProps.entity !== this.props.entity) { + this.updateMultiEntities(false); + } } normChange(prevProps) { const { @@ -54,6 +76,7 @@ class LayerInit extends _react.default.Component { const { entity, updateMetaPeaksAct, + updateLayoutAct, resetInitCommonAct, resetInitMsAct, resetInitNmrAct, @@ -68,8 +91,12 @@ class LayerInit extends _react.default.Component { layout, features } = entity; + // Sync the layout deterministically on every spectrum open. Otherwise it + // only updates via the d3 RESETALL, which can be skipped (active zoom or + // same multi-comparison curve count), leaving a stale layout from the + // previously opened spectrum. + updateLayoutAct(layout); 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; @@ -99,7 +126,8 @@ class LayerInit extends _react.default.Component { dscMetaData } = features; updateDSCMetaDataAct(dscMetaData); - } else { + } + if (!_format.default.isNmrLayout(layout)) { resetMultiplicityAct(); } } @@ -117,7 +145,19 @@ class LayerInit extends _react.default.Component { } = this.props; addOthersAct(others); } - updateMultiEntities() { + buildSetAllCurvesPayload(entities, isInitial) { + const { + curveIdx + } = this.props; + if (isInitial && Number.isFinite(curveIdx)) { + return { + entities, + curveIdx + }; + } + return entities; + } + updateMultiEntities(isInitial = false) { const { multiEntities, setAllCurvesAct, @@ -125,12 +165,12 @@ class LayerInit extends _react.default.Component { } = this.props; const isMultiSpectra = Array.isArray(multiEntities) && multiEntities.length > 1; if (isMultiSpectra) { - setAllCurvesAct(multiEntities); + setAllCurvesAct(this.buildSetAllCurvesPayload(multiEntities, isInitial)); return; } if (_format.default.isCyclicVoltaLayout(entity.layout)) { - const payload = Array.isArray(multiEntities) && multiEntities.length > 0 ? multiEntities : [entity]; - setAllCurvesAct(payload); + const entities = Array.isArray(multiEntities) && multiEntities.length > 0 ? multiEntities : [entity]; + setAllCurvesAct(this.buildSetAllCurvesPayload(entities, isInitial)); return; } setAllCurvesAct(false); @@ -213,17 +253,22 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ resetDetectorAct: _manager.resetDetector, resetMultiplicityAct: _manager.resetMultiplicity, updateOperationAct: _submit.updateOperation, + updateLayoutAct: _layout.updateLayout, updateMetaPeaksAct: _meta.updateMetaPeaks, addOthersAct: _jcamp.addOthers, setAllCurvesAct: _curve.setAllCurves, - updateDSCMetaDataAct: _meta.updateDSCMetaData + updateDSCMetaDataAct: _meta.updateDSCMetaData, + restoreSweepExtentAct: _ui.restoreSweepExtent }, dispatch); LayerInit.propTypes = { entity: _propTypes.default.object.isRequired, multiEntities: _propTypes.default.array, // eslint-disable-line + curveIdx: _propTypes.default.number, + sweepExtent: _propTypes.default.object, entityFileNames: _propTypes.default.array, // eslint-disable-line + restoreSweepExtentAct: _propTypes.default.func.isRequired, others: _propTypes.default.object.isRequired, cLabel: _propTypes.default.string.isRequired, xLabel: _propTypes.default.string.isRequired, @@ -239,6 +284,7 @@ LayerInit.propTypes = { resetInitMsAct: _propTypes.default.func.isRequired, resetInitCommonWithIntergationAct: _propTypes.default.func.isRequired, updateOperationAct: _propTypes.default.func.isRequired, + updateLayoutAct: _propTypes.default.func.isRequired, updateMetaPeaksAct: _propTypes.default.func.isRequired, addOthersAct: _propTypes.default.func.isRequired, canChangeDescription: _propTypes.default.bool.isRequired, diff --git a/dist/reducers/reducer_curve.js b/dist/reducers/reducer_curve.js index 91c11de1..509dae76 100644 --- a/dist/reducers/reducer_curve.js +++ b/dist/reducers/reducer_curve.js @@ -16,12 +16,41 @@ const initialState = { curveIdx: 0, isShowAllCurve: false }; +const normalizeSetAllCurvesPayload = payload => { + if (Array.isArray(payload)) { + return { + entities: payload, + curveIdx: undefined + }; + } + if (payload && Array.isArray(payload.entities)) { + return { + entities: payload.entities, + curveIdx: payload.curveIdx + }; + } + return { + entities: null, + curveIdx: undefined + }; +}; +const resolveCurveIdx = (entitiesLength, state, explicitIdx) => { + if (Number.isFinite(explicitIdx)) { + const maxIdx = Math.max(0, entitiesLength - 1); + return Math.min(Math.max(0, explicitIdx), maxIdx); + } + if (state.curveIdx >= 0 && state.curveIdx < entitiesLength) { + return state.curveIdx; + } + return 0; +}; const setAllCurves = (state, action) => { const { - payload - } = action; - if (payload) { - const entities = payload.map((entity, idx) => { + entities, + curveIdx: explicitIdx + } = normalizeSetAllCurvesPayload(action.payload); + if (entities) { + const listCurves = entities.map((entity, idx) => { const { topic, feature, @@ -31,7 +60,6 @@ const setAllCurves = (state, action) => { } = (0, _extractParams.extractParams)(entity, { isEdit: true }); - // const layout = entity.layout; const { layout } = entity; @@ -49,14 +77,15 @@ const setAllCurves = (state, action) => { curveIdx: idx }; }); + const curveIdx = resolveCurveIdx(entities.length, state, explicitIdx); return Object.assign({}, state, { - curveIdx: 0, - listCurves: entities + curveIdx, + listCurves }); } return Object.assign({}, state, { curveIdx: 0, - listCurves: payload + listCurves: entities }); }; const curveReducer = (state = initialState, action) => { diff --git a/dist/reducers/reducer_edit_peak.js b/dist/reducers/reducer_edit_peak.js index 35d38bff..b563f3fe 100644 --- a/dist/reducers/reducer_edit_peak.js +++ b/dist/reducers/reducer_edit_peak.js @@ -216,6 +216,10 @@ const editPeakReducer = (state = initialState, action) => { return processShift(state, action); case _action_type.EDITPEAK.CLEAR_ALL: return clearAllPeaks(state, action); + case _action_type.CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { + selectedIdx: action.payload + }); case _action_type.MANAGER.RESETALL: return { selectedIdx: 0, diff --git a/dist/reducers/reducer_integration.js b/dist/reducers/reducer_integration.js index 9d25b023..c65ce516 100644 --- a/dist/reducers/reducer_integration.js +++ b/dist/reducers/reducer_integration.js @@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = void 0; +exports.integrationReducer = exports.default = void 0; var _reduxUndo = _interopRequireDefault(require("redux-undo")); var _action_type = require("../constants/action_type"); var _integration = require("../helpers/integration"); @@ -170,18 +170,25 @@ const setFkr = (state, action) => { }; const setShift = (state, action) => { const { - selectedIdx, integrations } = state; - const selectedIntegration = integrations[selectedIdx]; - const shift = action.payload.prevOffset; + const { + prevOffset, + curveIdx + } = action.payload; + const targetIdx = Number.isFinite(curveIdx) ? curveIdx : state.selectedIdx; + let selectedIntegration = integrations[targetIdx]; + if (selectedIntegration === false || selectedIntegration === undefined) { + selectedIntegration = defaultEmptyIntegration; + } const newIntegration = Object.assign({}, selectedIntegration, { - shift + shift: prevOffset }); const newArrIntegration = [...integrations]; - newArrIntegration[selectedIdx] = newIntegration; + newArrIntegration[targetIdx] = newIntegration; return Object.assign({}, state, { - integrations: newArrIntegration + integrations: newArrIntegration, + selectedIdx: targetIdx }); }; const resetAll = (state, action) => { @@ -224,11 +231,16 @@ const integrationReducer = (state = initialState, action) => { return clearAll(state, action); case _action_type.EDITPEAK.SHIFT: return setShift(state, action); + case _action_type.CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { + selectedIdx: action.payload + }); 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_multiplicity.js b/dist/reducers/reducer_multiplicity.js index 651182e1..a203f2fa 100644 --- a/dist/reducers/reducer_multiplicity.js +++ b/dist/reducers/reducer_multiplicity.js @@ -26,19 +26,26 @@ const defaultEmptyMultiplicity = { edited: false }; const setShift = (state, action) => { - const shift = action.payload.prevOffset; const { - selectedIdx, + prevOffset, + curveIdx + } = action.payload; + const targetIdx = Number.isFinite(curveIdx) ? curveIdx : state.selectedIdx; + const { multiplicities } = state; - const selectedMulti = multiplicities[selectedIdx]; + let selectedMulti = multiplicities[targetIdx]; + if (selectedMulti === false || selectedMulti === undefined) { + selectedMulti = defaultEmptyMultiplicity; + } const newSelectedMulti = Object.assign({}, selectedMulti, { - shift + shift: prevOffset }); const newMultiplicities = [...multiplicities]; - newMultiplicities[selectedIdx] = newSelectedMulti; + newMultiplicities[targetIdx] = newSelectedMulti; return Object.assign({}, state, { - multiplicities: newMultiplicities + multiplicities: newMultiplicities, + selectedIdx: targetIdx }); }; const rmFromStack = (state, action) => { @@ -168,6 +175,10 @@ const multiplicityReducer = (state = initialState, action) => { switch (action.type) { case _action_type.EDITPEAK.SHIFT: return setShift(state, action); + case _action_type.CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { + selectedIdx: action.payload + }); case _action_type.INTEGRATION.RM_ONE: return rmFromStack(state, action); case _action_type.UI.SWEEP.SELECT_MULTIPLICITY_RDC: diff --git a/dist/reducers/reducer_shift.js b/dist/reducers/reducer_shift.js index 310ac7d8..4f390e47 100644 --- a/dist/reducers/reducer_shift.js +++ b/dist/reducers/reducer_shift.js @@ -71,9 +71,7 @@ const resetShift = (state, action) => { curveIdx, numberOfCurve } = curvesInfo; - const { - shifts - } = state; + const shifts = [...state.shifts]; let selectedShift = shifts[curveIdx]; if (selectedShift === false || selectedShift === undefined) { selectedShift = defaultEmptyShift; @@ -237,7 +235,11 @@ const shiftReducer = (state = initialState, action) => { return updateShift(initialState, action); case _action_type.MANAGER.RESETSHIFT: // case MANAGER.RESETALL: - return resetShift(initialState, action); + return resetShift(state, action); + case _action_type.CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { + selectedIdx: action.payload + }); default: return state; } diff --git a/dist/reducers/reducer_threshold.js b/dist/reducers/reducer_threshold.js index 72737d40..e60f7066 100644 --- a/dist/reducers/reducer_threshold.js +++ b/dist/reducers/reducer_threshold.js @@ -219,6 +219,10 @@ const thresholdReducer = (state = initialState, action) => { switch (action.type) { case _action_type.CURVE.SET_ALL_CURVES: return setListThreshold(state, action); + case _action_type.CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { + selectedIdx: action.payload + }); case _action_type.THRESHOLD.UPDATE_VALUE: return setThresHoldValue(state, action); case _action_type.THRESHOLD.UPDATE_UPPER_VALUE: diff --git a/dist/sagas/saga_manager.js b/dist/sagas/saga_manager.js index e87aec57..b4e04eaf 100644 --- a/dist/sagas/saga_manager.js +++ b/dist/sagas/saga_manager.js @@ -9,6 +9,13 @@ var _action_type = require("../constants/action_type"); const getLayout = state => state.layout; const getCurveSt = state => state.curve; const getIntegrationSt = state => state.integration.present; +const defaultEmptyIntegration = { + stack: [], + refArea: 1, + refFactor: 1, + shift: 0, + edited: false +}; function* resetShift(action) { const curveSt = yield (0, _effects.select)(getCurveSt); const layout = yield (0, _effects.select)(getLayout); @@ -19,7 +26,7 @@ function* resetShift(action) { curveIdx, listCurves } = curveSt; - const numberOfCurve = listCurves.length; + const numberOfCurve = Array.isArray(listCurves) ? listCurves.length : 0; yield (0, _effects.put)({ type: _action_type.MANAGER.RESETSHIFT, payload: Object.assign( @@ -44,22 +51,19 @@ function* resetInitNmr(action) { integration, simulation } = action.payload; - const { - integrations - } = integationSt; - const newArrIntegration = [...integrations]; - newArrIntegration[curveIdx] = integration; + // Always reset: keeping the previous spectrum's integrations would + // display stale data when the new entity has none saved. + const newArrIntegration = new Array(curveIdx + 1).fill(defaultEmptyIntegration); + newArrIntegration[curveIdx] = integration || defaultEmptyIntegration; 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 - }); - } + 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, @@ -76,22 +80,17 @@ function* resetInitCommonWithIntergation(action) { const { integration } = action.payload; - const { - integrations - } = integationSt; - const newArrIntegration = [...integrations]; - newArrIntegration[curveIdx] = integration; + const newArrIntegration = new Array(curveIdx + 1).fill(defaultEmptyIntegration); + newArrIntegration[curveIdx] = integration || defaultEmptyIntegration; 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 - }); - } + 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_multi_entities.js b/dist/sagas/saga_multi_entities.js index ee648abd..48d08e56 100644 --- a/dist/sagas/saga_multi_entities.js +++ b/dist/sagas/saga_multi_entities.js @@ -1,5 +1,6 @@ "use strict"; +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); @@ -7,6 +8,7 @@ exports.default = void 0; var _effects = require("redux-saga/effects"); var _action_type = require("../constants/action_type"); var _list_layout = require("../constants/list_layout"); +var _format = _interopRequireDefault(require("../helpers/format")); /* eslint-disable no-plusplus */ const getLayoutSt = state => state.layout; @@ -167,6 +169,38 @@ function* setCyclicVoltametryRef(action) { } }); } +function* setInitShifts() { + const layoutSt = yield (0, _effects.select)(getLayoutSt); + if (!_format.default.isNmrLayout(layoutSt)) { + return; + } + const curveSt = yield (0, _effects.select)(getCurveSt); + const { + listCurves + } = curveSt; + if (!listCurves || listCurves.length <= 1) { + return; + } + const numberOfCurve = listCurves.length; + for (let index = 0; index < listCurves.length; index += 1) { + const { + feature + } = listCurves[index]; + if (feature) { + yield (0, _effects.put)({ + type: _action_type.MANAGER.RESETSHIFT, + payload: Object.assign({}, feature, { + layout: layoutSt, + curvesInfo: { + isMultiCurve: true, + curveIdx: index, + numberOfCurve + } + }) + }); + } + } +} function* setInitIntegrations(action) { // eslint-disable-line const curveSt = yield (0, _effects.select)(getCurveSt); @@ -230,5 +264,5 @@ function* setInitIntegrations(action) { } } } -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)]; +const multiEntitiesSagas = [(0, _effects.takeEvery)(_action_type.CURVE.SET_ALL_CURVES, setCyclicVoltametry), (0, _effects.takeEvery)(_action_type.CURVE.SET_ALL_CURVES, setInitShifts), (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 index 56645954..86919b5b 100644 --- a/dist/sagas/saga_multiplicity.js +++ b/dist/sagas/saga_multiplicity.js @@ -11,6 +11,12 @@ var _multiplicity_manual = require("../helpers/multiplicity_manual"); const getMetaSt = state => state.meta; const getCurveSt = state => state.curve; const getMultiplicitySt = state => state.multiplicity.present; +const defaultEmptyMultiplicity = { + stack: [], + shift: 0, + smExtext: false, + edited: false +}; function* selectMpy(action) { const metaSt = yield (0, _effects.select)(getMetaSt); const mpySt = yield (0, _effects.select)(getMultiplicitySt); @@ -247,31 +253,19 @@ function* resetInitNmr(action) { const { curveIdx } = curveSt; - const { - multiplicities - } = mpySt; - const newMultiplicities = [...multiplicities]; - newMultiplicities[curveIdx] = multiplicity; + // Always reset: keeping the previous spectrum's multiplicities would + // display stale data when the new entity has none saved. + const newMultiplicities = new Array(curveIdx + 1).fill(defaultEmptyMultiplicity); + newMultiplicities[curveIdx] = multiplicity || defaultEmptyMultiplicity; 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, - // }); - // } + yield (0, _effects.put)({ + type: _action_type.MULTIPLICITY.RESET_ALL_RDC, + payload + }); // const { stack } = multiplicity; // const newStack = stack.map((k) => { diff --git a/dist/sagas/saga_ui.js b/dist/sagas/saga_ui.js index adf16e94..cd98903c 100644 --- a/dist/sagas/saga_ui.js +++ b/dist/sagas/saga_ui.js @@ -165,19 +165,21 @@ function* clickUiTarget(action) { payload, onPeak, voltammetryPeakIdx, - onPecker + onPecker, + jcampIdx } = action; const uiSweepType = yield (0, _effects.select)(getUiSweepType); const curveSt = yield (0, _effects.select)(getCurveSt); const { curveIdx } = curveSt; + const targetCurveIdx = Number.isFinite(jcampIdx) ? jcampIdx : curveIdx; 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 + curveIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_DELETE && onPeak) { @@ -185,7 +187,7 @@ function* clickUiTarget(action) { type: _action_type.EDITPEAK.ADD_NEGATIVE, payload: { dataToAdd: payload, - curveIdx + curveIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT && onPeak) { @@ -193,7 +195,7 @@ function* clickUiTarget(action) { type: _action_type.SHIFT.SET_PEAK, payload: { dataToSet: payload, - curveIdx + curveIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_RM && onPeak) { @@ -201,7 +203,7 @@ function* clickUiTarget(action) { type: _action_type.INTEGRATION.RM_ONE, payload: { dataToRemove: payload, - curveIdx + curveIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_RM && onPeak) { @@ -209,7 +211,7 @@ function* clickUiTarget(action) { type: _action_type.INTEGRATION.RM_ONE, payload: { dataToRemove: payload, - curveIdx + curveIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF && onPeak) { @@ -217,7 +219,7 @@ function* clickUiTarget(action) { type: _action_type.INTEGRATION.SET_REF, payload: { refData: payload, - curveIdx + curveIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_CLICK && onPeak) { @@ -231,7 +233,7 @@ function* clickUiTarget(action) { type: _action_type.MULTIPLICITY.ONE_CLICK_BY_UI, payload: { payloadData: xExtent, - curveIdx + curveIdx: targetCurveIdx } }); } else if (xL && xU) { @@ -242,7 +244,7 @@ function* clickUiTarget(action) { xL, xU }, - curveIdx + curveIdx: targetCurveIdx } }); } @@ -262,7 +264,7 @@ function* clickUiTarget(action) { payload: { peak: payload, index: voltammetryPeakIdx, - jcampIdx: curveIdx + jcampIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK && onPeak) { @@ -270,7 +272,7 @@ function* clickUiTarget(action) { type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_MAX_PEAK, payload: { index: voltammetryPeakIdx, - jcampIdx: curveIdx + jcampIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK && !onPeak) { @@ -279,7 +281,7 @@ function* clickUiTarget(action) { payload: { peak: payload, index: voltammetryPeakIdx, - jcampIdx: curveIdx + jcampIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK && onPeak) { @@ -287,7 +289,7 @@ function* clickUiTarget(action) { type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_MIN_PEAK, payload: { index: voltammetryPeakIdx, - jcampIdx: curveIdx + jcampIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_PECKER && !onPecker) { @@ -296,7 +298,7 @@ function* clickUiTarget(action) { payload: { peak: payload, index: voltammetryPeakIdx, - jcampIdx: curveIdx + jcampIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_PECKER && onPecker) { @@ -304,7 +306,7 @@ function* clickUiTarget(action) { type: _action_type.CYCLIC_VOLTA_METRY.REMOVE_PECKER, payload: { index: voltammetryPeakIdx, - jcampIdx: curveIdx + jcampIdx: targetCurveIdx } }); } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_SET_REF && onPeak) { @@ -312,7 +314,7 @@ function* clickUiTarget(action) { type: _action_type.CYCLIC_VOLTA_METRY.SET_REF, payload: { index: voltammetryPeakIdx, - jcampIdx: curveIdx + jcampIdx: targetCurveIdx } }); } diff --git a/src/__tests__/units/helpers/format.test.tsx b/src/__tests__/units/helpers/format.test.tsx index 7e3d0e1e..ec1b27db 100644 --- a/src/__tests__/units/helpers/format.test.tsx +++ b/src/__tests__/units/helpers/format.test.tsx @@ -139,7 +139,60 @@ describe('Test format helper', () => { it('Get peaks for HPLC layout', () => { params.layout = LIST_LAYOUT.HPLC_UVVIS const body = Format.peaksBody(params) - expect(body).toEqual('2.0 (2.00), 1.0 (1.00)') + expect(body).toEqual('2.00 min (2.00), 1.00 min (1.00)') + }) + + it('Get peaks for HPLC layout with integration', () => { + params.layout = LIST_LAYOUT.HPLC_UVVIS + params.integration = { + stack: [ + { xL: 1.5, xU: 2.5, absoluteArea: 1234.5678 }, + { xL: 0.5, xU: 1.5, absoluteArea: 987.6543 }, + ], + } + const body = Format.peaksBody(params) + expect(body).toEqual( + '2.00 min (2.00, AUC=1234.57), 1.00 min (1.00, AUC=987.65)', + ) + }) + + it('Does not assign AUC to peaks inside integration but not at apex', () => { + params.layout = LIST_LAYOUT.HPLC_UVVIS + params.isAscend = true + params.peaks = [ + { x: 16.99, y: 319.83 }, + { x: 14.05, y: 401.21 }, + { x: 13.71, y: -0.77 }, + ] + params.integration = { + stack: [ + { xL: 13.5, xU: 14.5, absoluteArea: 31467.89 }, + { xL: 16.5, xU: 17.5, absoluteArea: 31447.95 }, + ], + } + const body = Format.peaksBody(params) + expect(body).toEqual( + '13.71 min (-0.77), 14.05 min (401.21, AUC=31467.89), 16.99 min (319.83, AUC=31447.95)', + ) + }) + + it('Format HPLC AUC panel with retention time', () => { + const integration = { + stack: [ + { xL: 12.5, xU: 13.5, absoluteArea: 1000 }, + { xL: 15.5, xU: 16.5, absoluteArea: 2000 }, + ], + } + const feature = { + data: [{ + x: [12, 13, 14, 15, 16, 17], + y: [10, 50, 20, 15, 40, 10], + }], + } + const panel = Format.formatHplcAucPanel(integration, feature) + expect(panel).toEqual( + '13.00 min, AUC=1000.00 (33.33%), 16.00 min, AUC=2000.00 (66.67%)', + ) }) it('Get peaks for Emission layout', () => { diff --git a/src/__tests__/units/helpers/shift.test.tsx b/src/__tests__/units/helpers/shift.test.tsx index 47df37ad..38c2a304 100644 --- a/src/__tests__/units/helpers/shift.test.tsx +++ b/src/__tests__/units/helpers/shift.test.tsx @@ -1,4 +1,6 @@ -import { CalcResidualX, FromManualToOffset, RealPts, VirtalPts } from "../../../helpers/shift"; +import { + CalcResidualX, FromManualToOffset, RealPts, VirtalPts, shiftOffsetAtIndex, +} from "../../../helpers/shift"; import { LIST_SHIFT_1H, LIST_SHIFT_13C } from "../../../constants/list_shift"; describe('Test helper for shift', () => { @@ -65,6 +67,23 @@ describe('Test helper for shift', () => { }) }) + describe('Test shift offset at index', () => { + it('Returns zero when shift state is missing', () => { + expect(shiftOffsetAtIndex(null, 0)).toEqual(0) + }) + + it('Returns offset for the requested curve index', () => { + const shiftSt = { + shifts: [ + { ref: LIST_SHIFT_1H[0], peak: false }, + { ref: LIST_SHIFT_1H[1], peak: { x: 1.5, y: 2 } }, + ], + } + expect(shiftOffsetAtIndex(shiftSt, 0)).toEqual(0) + expect(shiftOffsetAtIndex(shiftSt, 1)).toEqual(-0.54) + }) + }) + describe('Test get real points', () => { it('No points', () => { const virtualPoints = RealPts([], 18.0) diff --git a/src/__tests__/units/reducers/reducer_curve.test.tsx b/src/__tests__/units/reducers/reducer_curve.test.tsx index 531d50eb..8cfd1b97 100644 --- a/src/__tests__/units/reducers/reducer_curve.test.tsx +++ b/src/__tests__/units/reducers/reducer_curve.test.tsx @@ -58,6 +58,24 @@ describe('Test redux curve reducer', () => { expect(maxminPeak).toBeNull() }) + it('Preserves the selected curve index when reloading all curves', () => { + action.type = CURVE.SET_ALL_CURVES + const entity = ExtractJcamp(nmr1HJcamp) + curveState = { listCurves: [], curveIdx: 2 } + action.payload = [ entity, entity, entity ] + const { curveIdx } = curveReducer(curveState, action) + expect(curveIdx).toEqual(2) + }) + + it('Uses an explicit curve index when provided', () => { + action.type = CURVE.SET_ALL_CURVES + const entity = ExtractJcamp(nmr1HJcamp) + curveState = { listCurves: [], curveIdx: 0 } + action.payload = { entities: [ entity, entity, entity ], curveIdx: 1 } + const { curveIdx } = curveReducer(curveState, action) + expect(curveIdx).toEqual(1) + }) + it('Toggle show all curves', () => { action.type = CURVE.SET_SHOULD_SHOW_ALL_CURVES action.payload = true diff --git a/src/__tests__/units/reducers/reducer_integration.test.tsx b/src/__tests__/units/reducers/reducer_integration.test.tsx index 602d30e0..62ad9bcd 100644 --- a/src/__tests__/units/reducers/reducer_integration.test.tsx +++ b/src/__tests__/units/reducers/reducer_integration.test.tsx @@ -838,3 +838,42 @@ describe('Test redux reducer for integrations', () => { expect(newState).toBe(state); }); }); + +import { EDITPEAK, CURVE } from '../../../constants/action_type'; + +describe('Test redux integration reducer (per-curve)', () => { + const baseIntegration = { + stack: [{ xL: 1, xU: 2, area: 1, absoluteArea: 1 }], + refArea: 1, + refFactor: 1, + shift: 0, + edited: false, + }; + + it('updates shift on the curve index from the payload', () => { + const state = { + selectedIdx: 0, + integrations: [baseIntegration, { ...baseIntegration, shift: 0 }], + }; + const action = { + type: EDITPEAK.SHIFT, + payload: { prevOffset: 0.42, curveIdx: 1 }, + }; + const nextState = integrationReducer(state, action); + expect(nextState.integrations[1].shift).toEqual(0.42); + expect(nextState.integrations[0].shift).toEqual(0); + expect(nextState.selectedIdx).toEqual(1); + }); + + it('syncs selectedIdx when the working curve changes', () => { + const state = { + selectedIdx: 0, + integrations: [baseIntegration], + }; + const nextState = integrationReducer(state, { + type: CURVE.SELECT_WORKING_CURVE, + payload: 2, + }); + expect(nextState.selectedIdx).toEqual(2); + }); +}); diff --git a/src/actions/ui.js b/src/actions/ui.js index f1c43479..55b97c92 100644 --- a/src/actions/ui.js +++ b/src/actions/ui.js @@ -48,6 +48,13 @@ const scrollUiWheel = (payload) => ( } ); +const restoreSweepExtent = (payload) => ( + { + type: UI.SWEEP.SELECT_ZOOMIN, + payload, + } +); + const clickUiTarget = ( payload, onPeak, @@ -75,6 +82,7 @@ export { setUiSweepType, selectUiSweep, scrollUiWheel, + restoreSweepExtent, clickUiTarget, displaySubViewerAt, }; diff --git a/src/app.js b/src/app.js index 8017f46e..dba0eb8e 100644 --- a/src/app.js +++ b/src/app.js @@ -44,7 +44,7 @@ const SpectraEditor = ({ entity, others, cLabel, xLabel, yLabel, operations, forecast, molSvg, editorOnly, descriptions, exactMass, canChangeDescription, onDescriptionChanged, - multiEntities, multiMolSvgs, entityFileNames, userManualLink, + multiEntities, multiMolSvgs, entityFileNames, userManualLink, curveIdx, sweepExtent, onLcmsPageRequest, }) => ( @@ -52,6 +52,8 @@ const SpectraEditor = ({ ( () => { const defaultCurves = feature ? [{ feature }] : []; @@ -268,6 +269,9 @@ const onClickCb = ( if (Number.isFinite(curveSt?.curveIdx)) { payload.curveSt = { curveIdx: curveSt.curveIdx }; } + if (sweepExtentSt?.xExtent || sweepExtentSt?.yExtent) { + payload.sweepExtent = sweepExtentSt; + } operationValue(payload); } ); @@ -279,6 +283,7 @@ const BtnSubmit = ({ waveLengthSt, cyclicvoltaSt, curveSt, curveList, axesUnitsSt, detectorSt, metaSt, hplcMsSt, + sweepExtentSt, disabled, className, children, }) => { // const disBtn = peaksEdit.length === 0 || statusSt.btnSubmit || disabled; @@ -323,7 +328,7 @@ const BtnSubmit = ({ layoutSt, shiftSt, forecastSt.predictions, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaPayload, curveSt, axesUnitsSt, detectorSt, dscMetaData, - curveList, editPeakSt, thresList, scanSt, feature, hplcMsSt, + curveList, editPeakSt, thresList, scanSt, feature, hplcMsSt, sweepExtentSt, )} > {children || } @@ -351,6 +356,7 @@ const mapStateToProps = (state, props) => ( // eslint-disable-line detectorSt: state.detector, metaSt: state.meta, hplcMsSt: state.hplcMs, + sweepExtentSt: state.ui.sweepExtent, } ); diff --git a/src/components/d3_line/line_focus.js b/src/components/d3_line/line_focus.js index c47b03a8..af3b6c47 100644 --- a/src/components/d3_line/line_focus.js +++ b/src/components/d3_line/line_focus.js @@ -588,16 +588,16 @@ class LineFocus { const { selectedIdx, multiplicities = [] } = mtplySt || {}; const selectedMulti = multiplicities[selectedIdx] || {}; - const { - stack = [], smExtext = false, shift = 0, - } = selectedMulti; + const isDisable = Cfg.btnCmdMpy(this.layout); + const hasMpy = !isDisable && selectedMulti?.stack?.length > 0; + const mpys = hasMpy ? selectedMulti.stack : []; + const smExtext = hasMpy ? selectedMulti.smExtext : false; + const shift = hasMpy ? selectedMulti.shift : 0; const hasValidExtent = (extent) => ( extent && Number.isFinite(extent.xL) && Number.isFinite(extent.xU) ); - const mpys = stack.filter((m) => hasValidExtent(m?.xExtent)); - const isDisable = Cfg.btnCmdMpy(this.layout); if (mpys.length === 0 || isDisable) return; const activeExtent = hasValidExtent(smExtext) ? smExtext : mpys[0].xExtent; // rescale for zoom diff --git a/src/components/d3_multi/index.js b/src/components/d3_multi/index.js index 2eb4541d..0b74654e 100644 --- a/src/components/d3_multi/index.js +++ b/src/components/d3_multi/index.js @@ -33,6 +33,22 @@ const buildResetPayload = (feature, curveSt) => ( { ...feature, curveIdx: curveSt.curveIdx } ); +const hasActiveZoom = (sweepExtentSt) => { + if (!sweepExtentSt) return false; + return !!(sweepExtentSt.xExtent || sweepExtentSt.yExtent); +}; + +const canSkipReset = (sweepExtentSt, layoutSt, feature) => ( + hasActiveZoom(sweepExtentSt) && layoutSt === feature?.operation?.layout +); + +const isSameMultiComparison = (oldEntities, newEntities) => ( + Array.isArray(oldEntities) + && Array.isArray(newEntities) + && oldEntities.length > 0 + && oldEntities.length === newEntities.length +); + class ViewerMulti extends React.Component { constructor(props) { super(props); @@ -74,7 +90,7 @@ class ViewerMulti extends React.Component { seed, peak, cLabel, xLabel, yLabel, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt, - isHidden, cyclicvoltaSt, + isHidden, cyclicvoltaSt, shiftSt, integrationSt, mtplySt, axesUnitsSt, uiSt, } = this.props; @@ -122,6 +138,7 @@ class ViewerMulti extends React.Component { isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, + shiftSt, integrationSt, mtplySt, uiSt, @@ -223,7 +240,8 @@ class ViewerMulti extends React.Component { feature, resetAllAct, entities, curveSt, } = this.props; const oldEntities = prevProps.entities; - if (oldEntities !== entities) { + if (oldEntities !== entities + && !isSameMultiComparison(oldEntities, entities)) { resetAllAct(buildResetPayload(feature, curveSt)); } } @@ -252,7 +270,7 @@ class ViewerMulti extends React.Component { seed, peak, cLabel, feature, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt, - isHidden, resetAllAct, cyclicvoltaSt, + isHidden, resetAllAct, cyclicvoltaSt, shiftSt, integrationSt, mtplySt, uiSt, } = props; @@ -260,7 +278,7 @@ class ViewerMulti extends React.Component { this.currentSize = size; drawDestroy(this.rootKlass); - if (shouldReset) { + if (shouldReset && !canSkipReset(sweepExtentSt, layoutSt, feature)) { resetAllAct(buildResetPayload(feature, curveSt)); } @@ -284,6 +302,7 @@ class ViewerMulti extends React.Component { isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, + shiftSt, integrationSt, mtplySt, uiSt, @@ -324,6 +343,7 @@ const mapStateToProps = (state, props) => ( && state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, isUiNoBrushSt: LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0, cyclicvoltaSt: state.cyclicvolta, + shiftSt: state.shift, maxminPeakSt: Feature2MaxMinPeak(state, props), integrationSt: state.integration.present, mtplySt: state.multiplicity.present, @@ -375,6 +395,7 @@ ViewerMulti.propTypes = { removeVisualSplitLineAct: PropTypes.func.isRequired, isHidden: PropTypes.bool, cyclicvoltaSt: PropTypes.object.isRequired, + shiftSt: PropTypes.object.isRequired, maxminPeakSt: PropTypes.object, addNewCylicVoltaPairPeakAct: PropTypes.func.isRequired, addCylicVoltaMaxPeakAct: PropTypes.func.isRequired, diff --git a/src/components/d3_multi/multi_focus.js b/src/components/d3_multi/multi_focus.js index 179df9fd..1bd925f1 100644 --- a/src/components/d3_multi/multi_focus.js +++ b/src/components/d3_multi/multi_focus.js @@ -24,6 +24,7 @@ import Format from '../../helpers/format'; import { GetCyclicVoltaPreviousShift, convertTopic, } from '../../helpers/chem'; +import { shiftOffsetAtIndex } from '../../helpers/shift'; import Cfg from '../../helpers/cfg'; import { itgIdTag, mpyIdTag } from '../../helpers/focus'; import { @@ -201,7 +202,7 @@ class MultiFocus { return y * this.yTransformFactor; } - setDataParams(filterSeed, peaks, tTrEndPts, tSfPeaks, layout, cyclicvoltaSt, jcampIdx = 0) { + setDataParams(filterSeed, peaks, tTrEndPts, tSfPeaks, layout, cyclicvoltaSt, shiftSt, jcampIdx = 0) { this.data = []; this.otherLineData = []; let filterSubLayoutValue = null; @@ -211,7 +212,9 @@ class MultiFocus { this.entities.forEach((entry, idx) => { const { topic, feature, color } = entry; - const offset = GetCyclicVoltaPreviousShift(cyclicvoltaSt, jcampIdx); + const offset = Format.isCyclicVoltaLayout(layout) + ? GetCyclicVoltaPreviousShift(cyclicvoltaSt, idx) + : shiftOffsetAtIndex(shiftSt, idx); let currData = convertTopic(topic, layout, feature, offset); if (idx === jcampIdx) { if (!Format.isCyclicVoltaLayout(layout)) { @@ -819,42 +822,16 @@ class MultiFocus { 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 = false, shift = 0, - } = selectedMulti || {}; + const isDisable = Cfg.btnCmdMpy(this.layout); + const hasMpy = !isDisable && selectedMulti?.stack?.length > 0; + const mpys = hasMpy ? selectedMulti.stack : []; + const smExtext = hasMpy ? selectedMulti.smExtext : false; + const shift = hasMpy ? selectedMulti.shift : 0; const hasValidExtent = (extent) => ( extent && Number.isFinite(extent.xL) && Number.isFinite(extent.xU) ); - const mpys = stack.filter((m) => hasValidExtent(m?.xExtent)); - const isDisable = Cfg.btnCmdMpy(this.layout); if (mpys.length === 0 || isDisable) return; const activeExtent = hasValidExtent(smExtext) ? smExtext : mpys[0].xExtent; // rescale for zoom @@ -1093,7 +1070,7 @@ class MultiFocus { filterSeed, filterPeak, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt, - cyclicvoltaSt, + cyclicvoltaSt, shiftSt, integrationSt, mtplySt, uiSt, }) { this.uiSt = uiSt; @@ -1109,7 +1086,7 @@ class MultiFocus { this.root = d3.select(this.rootKlass).selectAll('.focus-main'); this.scales = InitScale(this, this.reverseXAxis(layoutSt)); this.setTip(); - this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, shiftSt, jcampIdx); Object.assign(this, { isUiSplitIntgSt, isUiVisualSplitIntgSt }); if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview(); MountCompass(this); @@ -1143,7 +1120,7 @@ class MultiFocus { entities, curveSt, filterSeed, filterPeak, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, - sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, + sweepExtentSt, isUiAddIntgSt, isUiSplitIntgSt, isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, shiftSt, integrationSt, mtplySt, uiSt, }) { this.uiSt = uiSt; @@ -1156,7 +1133,7 @@ class MultiFocus { this.isShowAllCurves = isShowAllCurve; this.entities = entities; - this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, jcampIdx); + this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, shiftSt, jcampIdx); Object.assign(this, { isUiSplitIntgSt, isUiVisualSplitIntgSt }); if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview(); diff --git a/src/components/panel/graph_selection.js b/src/components/panel/graph_selection.js index a2d546ce..4bef9def 100644 --- a/src/components/panel/graph_selection.js +++ b/src/components/panel/graph_selection.js @@ -20,30 +20,38 @@ const styles = () => ({ backgroundColor: '#eee', height: 22, }, - curve: { + curveItem: { + display: 'flex', + alignItems: 'center', width: '100%', - }, - line: { - height: '2px', - borderWidth: '0', - margin: '0', + fontSize: '0.8em', + padding: '6px 8px', + margin: 0, + cursor: 'pointer', }, 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%', + backgroundColor: '#e0e0e0', + }, + curveIndex: { + flexShrink: 0, + marginRight: '4px', + fontStyle: 'italic', + }, + curveLabel: { + flexShrink: 0, + marginRight: '8px', overflowWrap: 'anywhere', }, + colorBar: { + flex: 1, + height: '6px', + borderRadius: '1px', + minWidth: '24px', + alignSelf: 'center', + }, }); const fallbackName = (entityFileNames, idx) => { @@ -64,23 +72,19 @@ const displayName = (spectra, idx, entityFileNames) => ( const renderCurveItem = (classes, item, curveIdx, onChange) => ( onChange(item.idx)} - className={ - classNames((item.idx === curveIdx ? classes.curveSelected : classes.curveDefault)) // eslint-disable-line - } + className={classNames( + classes.curveItem, + item.idx === curveIdx ? classes.curveSelected : classes.curveDefault, + )} > - - { item.name } - -
- { - item.label !== '' ? { item.label } : null // eslint-disable-line - } -
-
+ {item.name} + {item.label !== '' ? {item.label} : null} +
); diff --git a/src/components/panel/index.js b/src/components/panel/index.js index c4ae356d..dfdc79fb 100644 --- a/src/components/panel/index.js +++ b/src/components/panel/index.js @@ -110,7 +110,7 @@ class PanelViewer extends React.Component { /> { Cfg.hidePanelPeak(layoutSt) ? null : } { Cfg.hidePanelMpy(layoutSt) ? null : } - { (Cfg.hidePanelCompare(layoutSt) || listCurves.length > 1) ? null : } + { (Cfg.hidePanelCompare(layoutSt) || !listCurves || listCurves.length > 1) ? null : } { (Cfg.hidePanelCyclicVolta(layoutSt) || hideCyclicVolta) ? null : ( { - 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); - } - }); - } - - const spectraList = hplcMsSt?.uvvis?.spectraList || []; - const listWaveLength = hplcMsSt?.uvvis?.listWaveLength || []; - - spectraList.forEach((spectrum, idx) => { - const wavelength = listWaveLength[idx]; - const integrations = spectrum?.integrations || []; - - if (integrations.length > 0) { - const sumArea = integrations.reduce( - (sum, integ) => sum + (integ.absoluteArea ?? integ.area ?? 0), - 0, - ); - - const integrationStrings = integrations.map((integ) => { - const rawArea = integ.absoluteArea ?? integ.area ?? 0; - const areaVal = rawArea.toFixed(2); - const percent = sumArea > 0 ? ((rawArea * 100) / sumArea).toFixed(2) : '0.00'; - return `${areaVal} (${percent}%)`; - }); - - values.push(`[${wavelength} nm]: ${integrationStrings.join(', ')}`); - } - }); - - return values.join('\n'); -}; - const SECData = ({ classes, layout, detector, secData, }) => { @@ -438,7 +390,7 @@ const InfoPanel = ({
- {aucValue(integration)} + {Format.formatHplcAucPanel(integration, feature)}
) : null diff --git a/src/helpers/chem.js b/src/helpers/chem.js index 338338ed..94e082c2 100644 --- a/src/helpers/chem.js +++ b/src/helpers/chem.js @@ -5,7 +5,8 @@ max-len */ import Jcampconverter from 'jcampconverter'; import { createSelector } from 'reselect'; -import { FromManualToOffset } from './shift'; +import { shiftOffsetAtIndex } from './shift'; +import Cfg from './cfg'; import Format from './format'; import { LIST_LAYOUT } from '../constants/list_layout'; import { getArea } from './integration'; @@ -48,15 +49,7 @@ const getShiftOffset = (state, _) => { // eslint-disable-line return GetCyclicVoltaShiftOffset(cyclicvolta, curveIdx); } - const { shift } = state; - const { shifts } = shift; - const selectedShift = shifts[curveIdx]; - if (!selectedShift) { - return 0.0; - } - - const { ref, peak } = selectedShift; - return FromManualToOffset(ref, peak); + return shiftOffsetAtIndex(state.shift, curveIdx); }; const calcXYK = (xs, ys, maxY, offset) => { diff --git a/src/helpers/extractPeaksEdit.js b/src/helpers/extractPeaksEdit.js index 4930558b..8801cf6a 100644 --- a/src/helpers/extractPeaksEdit.js +++ b/src/helpers/extractPeaksEdit.js @@ -1,7 +1,7 @@ /* eslint-disable max-len */ import { Convert2Peak } from './chem'; import { PksEdit } from './converter'; -import { FromManualToOffset } from './shift'; +import { shiftOffsetAtIndex } from './shift'; import Format from './format'; import { calcArea } from './integration'; import { @@ -10,21 +10,8 @@ import { getLcmsMzPageData, } from '../features/lc-ms/submit'; -const niOffset = (shiftSt, atIndex = 0) => { - const { shifts } = shiftSt; - const selectedShift = shifts[atIndex]; - if (!selectedShift) { - return 0; - } - const { ref, peak } = selectedShift; - const offset = FromManualToOffset(ref, peak); - return offset; -}; - -const msOffset = () => 0; - const extractAutoPeaks = (feature, thresSt, shiftSt, layoutSt, atIndex = 0) => { - const offset = (Format.isMsLayout(layoutSt) || Format.isLCMsLayout(layoutSt)) ? msOffset() : niOffset(shiftSt, atIndex); + const offset = (Format.isMsLayout(layoutSt) || Format.isLCMsLayout(layoutSt)) ? 0 : shiftOffsetAtIndex(shiftSt, atIndex); const peaks = Convert2Peak(feature, thresSt.value, offset); return peaks; }; diff --git a/src/helpers/format.js b/src/helpers/format.js index 049cb08a..823035ca 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.js @@ -35,7 +35,7 @@ const spectraDigit = (layout) => { }; const fixDigit = (input, precision) => { - const output = input || 0.0; + const output = Number(input) || 0.0; return output.toFixed(precision); }; @@ -425,8 +425,86 @@ const formatedDLSIntensity = ( return ordered.map((o) => `${o.x} nm (${o.y} %)`).join(', '); }; +const HPLC_RT_DECIMAL = 2; +const HPLC_VALUE_DECIMAL = 2; +const HPLC_RT_UNIT = 'min'; + +const formatHplcRetentionTime = (rt) => ( + `${fixDigit(rt, HPLC_RT_DECIMAL)} ${HPLC_RT_UNIT}` +); + +const formatHplcAuc = (area) => fixDigit(area, HPLC_VALUE_DECIMAL); + +const findHplcPeakRetentionTime = (feature, xL, xU) => { + if (!feature?.data?.[0]) { + return (xL + xU) / 2; + } + const { x, y } = feature.data[0]; + let maxY = -Infinity; + let rt = (xL + xU) / 2; + for (let i = 0; i < x.length; i += 1) { + if (x[i] >= xL && x[i] <= xU && y[i] > maxY) { + maxY = y[i]; + rt = x[i]; + } + } + return rt; +}; + +const isSameHplcRt = (a, b) => ( + fixDigit(a, HPLC_RT_DECIMAL) === fixDigit(b, HPLC_RT_DECIMAL) +); + +const integrationApexRt = (inte, feature, peaks) => { + if (feature?.data?.[0]) { + return findHplcPeakRetentionTime(feature, inte.xL, inte.xU); + } + if (!Array.isArray(peaks)) return null; + const peaksInRange = peaks.filter((p) => p.x >= inte.xL && p.x <= inte.xU); + if (peaksInRange.length === 0) return null; + return peaksInRange.reduce( + (best, p) => (p.y > best.y ? p : best), + peaksInRange[0], + ).x; +}; + +const findIntegrationForPeak = (peakX, stack, peaks, feature) => { + if (!Array.isArray(stack)) return null; + const x = parseFloat(peakX); + return stack.find((s) => { + if (s.xL > x || x > s.xU) return false; + const apexRt = integrationApexRt(s, feature, peaks); + return apexRt != null && isSameHplcRt(x, apexRt); + }) || null; +}; + +const formatHplcAucPanel = (integration, feature) => { + if (!integration) return ''; + const stackIntegration = integration.stack; + if (!Array.isArray(stackIntegration)) return ''; + + const entries = stackIntegration + .filter((inte) => inte.absoluteArea) + .map((inte) => ({ + rt: findHplcPeakRetentionTime(feature, inte.xL, inte.xU), + area: inte.absoluteArea, + })); + + if (entries.length === 0) return ''; + + const sumVal = entries.reduce((sum, e) => sum + e.area, 0); + + return entries + .map((e) => { + const areaVal = formatHplcAuc(e.area); + const percent = fixDigit((e.area * 100) / sumVal, HPLC_VALUE_DECIMAL); + return `${formatHplcRetentionTime(e.rt)}, AUC=${areaVal} (${percent}%)`; + }) + .join(', '); +}; + const formatedHplcUvVis = ( - peaks, decimal = 2, integration, + peaks, decimal = 2, integration, feature, ) => { let stack = []; if (integration) { @@ -436,7 +514,7 @@ const formatedHplcUvVis = ( let ordered = {}; peaks.forEach((p) => { - const x = fixDigit(p.x, decimal); + const x = Number(p.x); const better = !ordered[x] || (p.y > ordered[x]); if (better) { ordered = Object.assign({}, ordered, { [x]: p.y }); @@ -444,18 +522,16 @@ const formatedHplcUvVis = ( }); ordered = Object.keys(ordered) - .map((k) => ({ x: k, y: ordered[k] })); + .map((k) => ({ x: parseFloat(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})`; - } - }); - } + const rt = formatHplcRetentionTime(o.x); + const yVal = o.y.toFixed(HPLC_VALUE_DECIMAL); + const inte = findIntegrationForPeak(o.x, stack, peaks, feature); + const pStr = inte?.absoluteArea + ? `${rt} (${yVal}, AUC=${formatHplcAuc(inte.absoluteArea)})` + : `${rt} (${yVal})`; arrResult.push(pStr); }); @@ -508,7 +584,7 @@ const rmShiftFromPeaks = (peaks, shift, atIndex = 0) => { const peaksBody = ({ peaks, layout, decimal, shift, isAscend, isIntensity = false, boundary = {}, - integration, atIndex = 0, waveLength, temperature, hplcMsSt = null, + integration, atIndex = 0, waveLength, temperature, hplcMsSt = null, feature, }) => { const result = rmShiftFromPeaks(peaks, shift, atIndex); @@ -531,7 +607,7 @@ const peaksBody = ({ return formatedUvVis(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); } if (layout === LIST_LAYOUT.HPLC_UVVIS) { - return formatedHplcUvVis(ordered, decimal, integration); + return formatedHplcUvVis(ordered, decimal, integration, feature); } if (layout === LIST_LAYOUT.EMISSIONS) { return formatedEmissions(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); @@ -793,6 +869,8 @@ const Format = { strNumberFixedLength, inlineNotation, formatedLCMS, + formatHplcAucPanel, + formatedHplcUvVis, }; export default Format; diff --git a/src/helpers/shift.js b/src/helpers/shift.js index 2baaf83a..50a31a69 100644 --- a/src/helpers/shift.js +++ b/src/helpers/shift.js @@ -40,6 +40,14 @@ const RealPts = (pts, resX) => ( ) ); +const shiftOffsetAtIndex = (shiftSt, atIndex = 0) => { + if (!shiftSt || !shiftSt.shifts) return 0; + const selectedShift = shiftSt.shifts[atIndex]; + if (!selectedShift) return 0; + const { ref, peak } = selectedShift; + return FromManualToOffset(ref, peak); +}; + export { - FromManualToOffset, CalcResidualX, VirtalPts, RealPts, + FromManualToOffset, CalcResidualX, VirtalPts, RealPts, shiftOffsetAtIndex, }; diff --git a/src/layer_init.js b/src/layer_init.js index f9804c5a..f3493b95 100644 --- a/src/layer_init.js +++ b/src/layer_init.js @@ -21,6 +21,12 @@ import MultiJcampsViewer from './components/multi_jcamps_viewer'; import HPLCViewer from './components/hplc_viewer'; import { setAllCurves } from './actions/curve'; import { clearHplcMsState } from './actions/hplc_ms'; +import { restoreSweepExtent } from './actions/ui'; + +const hasActiveZoom = (sweepExtent) => { + if (!sweepExtent) return false; + return !!(sweepExtent.xExtent || sweepExtent.yExtent); +}; const styles = () => ({ }); @@ -44,6 +50,15 @@ class LayerInit extends React.Component { constructor(props) { super(props); + const { sweepExtent, restoreSweepExtentAct } = props; + if (hasActiveZoom(sweepExtent)) { + restoreSweepExtentAct(sweepExtent); + } else { + // Clear any zoom left in the shared store by a previously opened + // spectrum, so it cannot block the RESETALL/layout sync on mount. + restoreSweepExtentAct({ xExtent: false, yExtent: false }); + } + this.normChange = this.normChange.bind(this); this.execReset = this.execReset.bind(this); this.initReducer = this.initReducer.bind(this); @@ -55,7 +70,7 @@ class LayerInit extends React.Component { this.execReset(); this.initReducer(); this.updateOthers(); - this.updateMultiEntities(); + this.updateMultiEntities(true); } componentDidUpdate(prevProps) { @@ -71,7 +86,7 @@ class LayerInit extends React.Component { } if (prevProps.multiEntities !== multiEntities || prevProps.entity !== entity) { - this.updateMultiEntities(); + this.updateMultiEntities(false); } } @@ -96,17 +111,20 @@ class LayerInit extends React.Component { execReset() { const { - entity, updateMetaPeaksAct, + entity, updateMetaPeaksAct, updateLayoutAct, resetInitCommonAct, resetInitMsAct, resetInitNmrAct, resetInitCommonWithIntergationAct, - resetDetectorAct, updateDSCMetaDataAct, resetMultiplicityAct, updateLayoutAct, + resetDetectorAct, updateDSCMetaDataAct, resetMultiplicityAct, } = this.props; if (!entity || !entity.layout) return; resetInitCommonAct(); resetDetectorAct(); const { layout, features = {} } = entity; + // Sync the layout deterministically on every spectrum open. Otherwise it + // only updates via the d3 RESETALL, which can be skipped (active zoom or + // same multi-comparison curve count), leaving a stale layout from the + // previously opened spectrum. updateLayoutAct(layout); if (Format.isMsLayout(layout)) { - // const { autoPeak, editPeak } = features; // TBD const autoPeak = features.autoPeak || features[0]; const editPeak = features.editPeak || features[0]; const baseFeat = editPeak || autoPeak; @@ -126,7 +144,8 @@ class LayerInit extends React.Component { } else if (Format.isDSCLayout(layout)) { const { dscMetaData } = features; updateDSCMetaDataAct(dscMetaData); - } else { + } + if (!Format.isNmrLayout(layout)) { resetMultiplicityAct(); } } @@ -145,7 +164,15 @@ class LayerInit extends React.Component { } } - updateMultiEntities() { + buildSetAllCurvesPayload(entities, isInitial) { + const { curveIdx } = this.props; + if (isInitial && Number.isFinite(curveIdx)) { + return { entities, curveIdx }; + } + return entities; + } + + updateMultiEntities(isInitial = false) { const { multiEntities, setAllCurvesAct, entity } = this.props; if (!entity || !entity.layout) return; const lcmsCurveMeta = () => { @@ -182,23 +209,23 @@ class LayerInit extends React.Component { const isMultiSpectra = Array.isArray(multiEntities) && multiEntities.length > 1; if (isMultiSpectra) { const meta = Format.isLCMsLayout(entity.layout) ? lcmsCurveMeta() : undefined; - setAllCurvesAct(multiEntities, meta); + setAllCurvesAct(this.buildSetAllCurvesPayload(multiEntities, isInitial), meta); return; } if (Format.isLCMsLayout(entity.layout)) { - const payload = (Array.isArray(multiEntities) && multiEntities.length > 0) + const entities = (Array.isArray(multiEntities) && multiEntities.length > 0) ? multiEntities : [entity]; - setAllCurvesAct(payload, lcmsCurveMeta()); + setAllCurvesAct(this.buildSetAllCurvesPayload(entities, isInitial), lcmsCurveMeta()); return; } if (Format.isCyclicVoltaLayout(entity.layout)) { - const payload = (Array.isArray(multiEntities) && multiEntities.length > 0) + const entities = (Array.isArray(multiEntities) && multiEntities.length > 0) ? multiEntities : [entity]; - setAllCurvesAct(payload); + setAllCurvesAct(this.buildSetAllCurvesPayload(entities, isInitial)); return; } @@ -318,13 +345,17 @@ const mapDispatchToProps = (dispatch) => ( setAllCurvesAct: setAllCurves, updateDSCMetaDataAct: updateDSCMetaData, clearHplcMsStateAct: clearHplcMsState, + restoreSweepExtentAct: restoreSweepExtent, }, dispatch) ); LayerInit.propTypes = { entity: PropTypes.object.isRequired, multiEntities: PropTypes.array, // eslint-disable-line + curveIdx: PropTypes.number, + sweepExtent: PropTypes.object, entityFileNames: PropTypes.array, // eslint-disable-line + restoreSweepExtentAct: PropTypes.func.isRequired, others: PropTypes.object.isRequired, cLabel: PropTypes.string.isRequired, xLabel: PropTypes.string.isRequired, diff --git a/src/reducers/reducer_curve.js b/src/reducers/reducer_curve.js index 099c95bf..3d49e08c 100644 --- a/src/reducers/reducer_curve.js +++ b/src/reducers/reducer_curve.js @@ -13,8 +13,30 @@ const initialState = { isShowAllCurve: false, }; +const normalizeSetAllCurvesPayload = (payload) => { + if (Array.isArray(payload)) { + return { entities: payload, curveIdx: undefined }; + } + if (payload && Array.isArray(payload.entities)) { + return { entities: payload.entities, curveIdx: payload.curveIdx }; + } + return { entities: null, curveIdx: undefined }; +}; + +const resolveCurveIdx = (entitiesLength, state, explicitIdx) => { + if (Number.isFinite(explicitIdx)) { + const maxIdx = Math.max(0, entitiesLength - 1); + return Math.min(Math.max(0, explicitIdx), maxIdx); + } + if (state.curveIdx >= 0 && state.curveIdx < entitiesLength) { + return state.curveIdx; + } + return 0; +}; + const setAllCurves = (state, action) => { - const { payload } = action; + const { entities: payloadEntities, curveIdx: explicitIdx } = normalizeSetAllCurvesPayload(action.payload); + const payload = payloadEntities ?? action.payload; if (!payload) return { ...state, curveIdx: 0, listCurves: [] }; const isLcmsGroup = isLcMsGroup(payload); @@ -55,12 +77,11 @@ const setAllCurves = (state, action) => { }; }); - const maxIdx = entities.length - 1; - const safeCurveIdx = Math.min(state.curveIdx || 0, maxIdx); + const curveIdx = resolveCurveIdx(entities.length, state, explicitIdx); return { ...state, - curveIdx: safeCurveIdx, + curveIdx, listCurves: entities, }; }; diff --git a/src/reducers/reducer_edit_peak.js b/src/reducers/reducer_edit_peak.js index 45079f7c..d3fbd43a 100644 --- a/src/reducers/reducer_edit_peak.js +++ b/src/reducers/reducer_edit_peak.js @@ -1,6 +1,6 @@ /* eslint-disable prefer-object-spread, default-param-last */ import undoable from 'redux-undo'; -import { EDITPEAK, MANAGER } from '../constants/action_type'; +import { EDITPEAK, MANAGER, CURVE } from '../constants/action_type'; import { undoRedoConfig, undoRedoActions } from './undo_redo_config'; import { almostEqual } from '../helpers/calc'; @@ -170,6 +170,8 @@ const editPeakReducer = (state = initialState, action) => { return processShift(state, action); case EDITPEAK.CLEAR_ALL: return clearAllPeaks(state, action); + case CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { selectedIdx: action.payload }); case MANAGER.RESETALL: return { selectedIdx: 0, diff --git a/src/reducers/reducer_integration.js b/src/reducers/reducer_integration.js index 22fd0667..992e2b30 100644 --- a/src/reducers/reducer_integration.js +++ b/src/reducers/reducer_integration.js @@ -1,7 +1,7 @@ /* eslint-disable prefer-object-spread, default-param-last */ import undoable from 'redux-undo'; import { - UI, INTEGRATION, EDITPEAK, MANAGER, + UI, INTEGRATION, EDITPEAK, MANAGER, CURVE, } from '../constants/action_type'; import { generateVisualSplitGroupId, @@ -455,15 +455,18 @@ const setFkr = (state, action) => { }; const setShift = (state, action) => { - const { selectedIdx, integrations } = state; - const selectedIntegration = integrations[selectedIdx]; - - const shift = action.payload.prevOffset; + const { integrations } = state; + const { prevOffset, curveIdx } = action.payload; + const targetIdx = Number.isFinite(curveIdx) ? curveIdx : state.selectedIdx; + let selectedIntegration = integrations[targetIdx]; + if (selectedIntegration === false || selectedIntegration === undefined) { + selectedIntegration = defaultEmptyIntegration; + } - const newIntegration = Object.assign({}, selectedIntegration, { shift }); + const newIntegration = Object.assign({}, selectedIntegration, { shift: prevOffset }); const newArrIntegration = [...integrations]; - newArrIntegration[selectedIdx] = newIntegration; - return Object.assign({}, state, { integrations: newArrIntegration }); + newArrIntegration[targetIdx] = newIntegration; + return Object.assign({}, state, { integrations: newArrIntegration, selectedIdx: targetIdx }); }; const resetAll = (state, action) => { @@ -504,6 +507,8 @@ const integrationReducer = (state = initialState, action) => { return clearAll(state, action); case EDITPEAK.SHIFT: return setShift(state, action); + case CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { selectedIdx: action.payload }); case MANAGER.RESETALL: return state; default: diff --git a/src/reducers/reducer_multiplicity.js b/src/reducers/reducer_multiplicity.js index d8195147..f531f809 100644 --- a/src/reducers/reducer_multiplicity.js +++ b/src/reducers/reducer_multiplicity.js @@ -1,7 +1,7 @@ /* eslint-disable prefer-object-spread, default-param-last */ import undoable from 'redux-undo'; import { - UI, EDITPEAK, INTEGRATION, MULTIPLICITY, MANAGER, + UI, EDITPEAK, INTEGRATION, MULTIPLICITY, MANAGER, CURVE, } from '../constants/action_type'; import { undoRedoConfig, undoRedoActions } from './undo_redo_config'; @@ -26,15 +26,19 @@ const defaultEmptyMultiplicity = { }; const setShift = (state, action) => { - const shift = action.payload.prevOffset; + const { prevOffset, curveIdx } = action.payload; + const targetIdx = Number.isFinite(curveIdx) ? curveIdx : state.selectedIdx; - const { selectedIdx, multiplicities } = state; - const selectedMulti = multiplicities[selectedIdx]; + const { multiplicities } = state; + let selectedMulti = multiplicities[targetIdx]; + if (selectedMulti === false || selectedMulti === undefined) { + selectedMulti = defaultEmptyMultiplicity; + } - const newSelectedMulti = Object.assign({}, selectedMulti, { shift }); + const newSelectedMulti = Object.assign({}, selectedMulti, { shift: prevOffset }); const newMultiplicities = [...multiplicities]; - newMultiplicities[selectedIdx] = newSelectedMulti; - return Object.assign({}, state, { multiplicities: newMultiplicities }); + newMultiplicities[targetIdx] = newSelectedMulti; + return Object.assign({}, state, { multiplicities: newMultiplicities, selectedIdx: targetIdx }); }; const rmFromStack = (state, action) => { @@ -127,6 +131,8 @@ const multiplicityReducer = (state = initialState, action) => { switch (action.type) { case EDITPEAK.SHIFT: return setShift(state, action); + case CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { selectedIdx: action.payload }); case INTEGRATION.RM_ONE: return rmFromStack(state, action); case UI.SWEEP.SELECT_MULTIPLICITY_RDC: diff --git a/src/reducers/reducer_shift.js b/src/reducers/reducer_shift.js index ad1446c5..fae0c9d8 100644 --- a/src/reducers/reducer_shift.js +++ b/src/reducers/reducer_shift.js @@ -1,6 +1,6 @@ /* eslint-disable prefer-object-spread, default-param-last */ import { - SHIFT, EDITPEAK, MANAGER, LAYOUT, + SHIFT, EDITPEAK, MANAGER, LAYOUT, CURVE, } from '../constants/action_type'; import { getListShift, LIST_SHIFT_1H } from '../constants/list_shift'; import { CalcResidualX, RealPts } from '../helpers/shift'; @@ -68,7 +68,7 @@ const resetShift = (state, action) => { const { curvesInfo } = payload; const { isMultiCurve, curveIdx, numberOfCurve } = curvesInfo; - const { shifts } = state; + const shifts = [...state.shifts]; let selectedShift = shifts[curveIdx]; if (selectedShift === false || selectedShift === undefined) { selectedShift = defaultEmptyShift; @@ -238,7 +238,9 @@ const shiftReducer = (state = initialState, action) => { case LAYOUT.UPDATE: return updateShift(initialState, action); case MANAGER.RESETSHIFT: // case MANAGER.RESETALL: - return resetShift(initialState, action); + return resetShift(state, action); + case CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { selectedIdx: action.payload }); default: return state; } diff --git a/src/reducers/reducer_threshold.js b/src/reducers/reducer_threshold.js index a6a0c6c3..b62b6d72 100644 --- a/src/reducers/reducer_threshold.js +++ b/src/reducers/reducer_threshold.js @@ -164,6 +164,8 @@ const thresholdReducer = (state = initialState, action) => { switch (action.type) { case CURVE.SET_ALL_CURVES: return setListThreshold(state, action); + case CURVE.SELECT_WORKING_CURVE: + return Object.assign({}, state, { selectedIdx: action.payload }); case THRESHOLD.UPDATE_VALUE: return setThresHoldValue(state, action); case THRESHOLD.UPDATE_UPPER_VALUE: diff --git a/src/sagas/saga_manager.js b/src/sagas/saga_manager.js index 9ac6e748..17ab5aab 100644 --- a/src/sagas/saga_manager.js +++ b/src/sagas/saga_manager.js @@ -8,6 +8,14 @@ const getLayout = (state) => state.layout; const getCurveSt = (state) => state.curve; const getIntegrationSt = (state) => state.integration.present; +const defaultEmptyIntegration = { + stack: [], + refArea: 1, + refFactor: 1, + shift: 0, + edited: false, +}; + function* resetShift(action) { const curveSt = yield select(getCurveSt); const layout = yield select(getLayout); @@ -16,7 +24,7 @@ function* resetShift(action) { const { curveIdx, listCurves } = curveSt; - const numberOfCurve = listCurves.length; + const numberOfCurve = Array.isArray(listCurves) ? listCurves.length : 0; yield put({ type: MANAGER.RESETSHIFT, @@ -41,18 +49,17 @@ function* resetInitNmr(action) { const { curveIdx } = curveSt; const { integration, simulation } = action.payload; - const { integrations } = integationSt; - const newArrIntegration = [...integrations]; - newArrIntegration[curveIdx] = integration; + // Always reset: keeping the previous spectrum's integrations would + // display stale data when the new entity has none saved. + const newArrIntegration = new Array(curveIdx + 1).fill(defaultEmptyIntegration); + newArrIntegration[curveIdx] = integration || defaultEmptyIntegration; const payload = Object.assign({}, integationSt, { integrations: newArrIntegration, selectedIdx: curveIdx }); // eslint-disable-line - if (integration) { - yield put({ - type: INTEGRATION.RESET_ALL_RDC, - payload, - }); - } + yield put({ + type: INTEGRATION.RESET_ALL_RDC, + payload, + }); if (simulation) { yield put({ type: SIMULATION.RESET_ALL_RDC, @@ -68,18 +75,15 @@ function* resetInitCommonWithIntergation(action) { const { integration } = action.payload; - const { integrations } = integationSt; - const newArrIntegration = [...integrations]; - newArrIntegration[curveIdx] = integration; + const newArrIntegration = new Array(curveIdx + 1).fill(defaultEmptyIntegration); + newArrIntegration[curveIdx] = integration || defaultEmptyIntegration; const payload = Object.assign({}, integationSt, { integrations: newArrIntegration, selectedIdx: curveIdx }); // eslint-disable-line - if (integration) { - yield put({ - type: INTEGRATION.RESET_ALL_RDC, - payload, - }); - } + yield put({ + type: INTEGRATION.RESET_ALL_RDC, + payload, + }); } const managerSagas = [ diff --git a/src/sagas/saga_multi_entities.js b/src/sagas/saga_multi_entities.js index 3a72db3a..0bccfc2f 100644 --- a/src/sagas/saga_multi_entities.js +++ b/src/sagas/saga_multi_entities.js @@ -2,10 +2,11 @@ import { put, takeEvery, select } from 'redux-saga/effects'; import { - CURVE, CYCLIC_VOLTA_METRY, INTEGRATION, SIMULATION, MULTIPLICITY, + CURVE, CYCLIC_VOLTA_METRY, INTEGRATION, SIMULATION, MULTIPLICITY, MANAGER, } from '../constants/action_type'; import { LIST_LAYOUT } from '../constants/list_layout'; +import Format from '../helpers/format'; const getLayoutSt = (state) => state.layout; const getCurveSt = (state) => state.curve; @@ -121,6 +122,37 @@ function* setCyclicVoltametryRef(action) { // eslint-disable-line })); } +function* setInitShifts() { + const layoutSt = yield select(getLayoutSt); + if (!Format.isNmrLayout(layoutSt)) { + return; + } + + const curveSt = yield select(getCurveSt); + const { listCurves } = curveSt; + if (!listCurves || listCurves.length <= 1) { + return; + } + + const numberOfCurve = listCurves.length; + for (let index = 0; index < listCurves.length; index += 1) { + const { feature } = listCurves[index]; + if (feature) { + yield put({ + type: MANAGER.RESETSHIFT, + payload: Object.assign({}, feature, { + layout: layoutSt, + curvesInfo: { + isMultiCurve: true, + curveIdx: index, + numberOfCurve, + }, + }), + }); + } + } +} + function* setInitIntegrations(action) { // eslint-disable-line const curveSt = yield select(getCurveSt); const { listCurves } = curveSt; @@ -173,6 +205,7 @@ function* setInitIntegrations(action) { // eslint-disable-line const multiEntitiesSagas = [ takeEvery(CURVE.SET_ALL_CURVES, setCyclicVoltametry), + takeEvery(CURVE.SET_ALL_CURVES, setInitShifts), takeEvery(CURVE.SET_ALL_CURVES, setInitIntegrations), takeEvery(CYCLIC_VOLTA_METRY.SET_FACTOR, setCyclicVoltametryRef), ]; diff --git a/src/sagas/saga_multiplicity.js b/src/sagas/saga_multiplicity.js index d70a0446..b32bdcdf 100644 --- a/src/sagas/saga_multiplicity.js +++ b/src/sagas/saga_multiplicity.js @@ -9,6 +9,13 @@ const getCurveSt = (state) => state.curve; const getMultiplicitySt = (state) => state.multiplicity.present; +const defaultEmptyMultiplicity = { + stack: [], + shift: 0, + smExtext: false, + edited: false, +}; + function* selectMpy(action) { const metaSt = yield select(getMetaSt); const mpySt = yield select(getMultiplicitySt); @@ -201,26 +208,16 @@ function* resetInitNmr(action) { const mpySt = yield select(getMultiplicitySt); const { curveIdx } = curveSt; - const { multiplicities } = mpySt; - const newMultiplicities = [...multiplicities]; - newMultiplicities[curveIdx] = multiplicity; + // Always reset: keeping the previous spectrum's multiplicities would + // display stale data when the new entity has none saved. + const newMultiplicities = new Array(curveIdx + 1).fill(defaultEmptyMultiplicity); + newMultiplicities[curveIdx] = multiplicity || defaultEmptyMultiplicity; const payload = Object.assign({}, mpySt, { multiplicities: newMultiplicities, selectedIdx: curveIdx }); // eslint-disable-line - if (multiplicity) { - yield put({ - 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, - // }); - // } + yield put({ + type: MULTIPLICITY.RESET_ALL_RDC, + payload, + }); // const { stack } = multiplicity; // const newStack = stack.map((k) => { diff --git a/src/sagas/saga_ui.js b/src/sagas/saga_ui.js index 8458dc86..25f0976c 100644 --- a/src/sagas/saga_ui.js +++ b/src/sagas/saga_ui.js @@ -168,12 +168,13 @@ export const shouldDisplayLcmsSubViewerAt = ({ function* clickUiTarget(action) { const { - payload, onPeak, voltammetryPeakIdx, onPecker, sourceHint, + payload, onPeak, voltammetryPeakIdx, onPecker, sourceHint, jcampIdx, } = action; const uiSweepType = yield select(getUiSweepType); const curveState = yield select(getCurveState); const { curveIdx } = curveState; + const targetCurveIdx = Number.isFinite(jcampIdx) ? jcampIdx : curveIdx; const hplcMsState = yield select(getHplcMsState); const { uvvis } = hplcMsState; @@ -208,7 +209,7 @@ function* clickUiTarget(action) { } else { yield put({ type: EDITPEAK.ADD_POSITIVE, - payload: { dataToAdd: payload, curveIdx }, + payload: { dataToAdd: payload, curveIdx: targetCurveIdx }, }); } } else if (uiSweepType === LIST_UI_SWEEP_TYPE.PEAK_DELETE && onPeak) { @@ -217,13 +218,13 @@ function* clickUiTarget(action) { } else { yield put({ type: EDITPEAK.ADD_NEGATIVE, - payload: { dataToAdd: payload, curveIdx }, + payload: { dataToAdd: payload, curveIdx: targetCurveIdx }, }); } } else if (uiSweepType === LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT && onPeak) { yield put({ type: SHIFT.SET_PEAK, - payload: { dataToSet: payload, curveIdx }, + payload: { dataToSet: payload, curveIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_RM && onPeak) { if (uvvis.selectedWaveLength && isLcmsLayout) { @@ -231,30 +232,30 @@ function* clickUiTarget(action) { } else { yield put({ type: INTEGRATION.RM_ONE, - payload: { dataToRemove: payload, curveIdx }, + payload: { dataToRemove: payload, curveIdx: targetCurveIdx }, }); } } else if (uiSweepType === LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_RM && onPeak) { yield put({ type: INTEGRATION.RM_ONE, - payload: { dataToRemove: payload, curveIdx }, + payload: { dataToRemove: payload, curveIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF && onPeak) { yield put({ type: INTEGRATION.SET_REF, - payload: { refData: payload, curveIdx }, + payload: { refData: payload, curveIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_CLICK && onPeak) { const { xExtent, xL, xU } = payload; if (xExtent) { yield put({ type: MULTIPLICITY.ONE_CLICK_BY_UI, - payload: { payloadData: xExtent, curveIdx }, + payload: { payloadData: xExtent, curveIdx: targetCurveIdx }, }); } else if (xL && xU) { yield put({ type: MULTIPLICITY.ONE_CLICK_BY_UI, - payload: { payloadData: { xL, xU }, curveIdx }, + payload: { payloadData: { xL, xU }, curveIdx: targetCurveIdx }, }); } } else if (uiSweepType === LIST_UI_SWEEP_TYPE.MULTIPLICITY_PEAK_ADD) { @@ -270,37 +271,37 @@ function* clickUiTarget(action) { } else if (uiSweepType === LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MAX_PEAK && !onPeak) { yield put({ type: CYCLIC_VOLTA_METRY.ADD_MAX_PEAK, - payload: { peak: payload, index: voltammetryPeakIdx, jcampIdx: curveIdx }, + payload: { peak: payload, index: voltammetryPeakIdx, jcampIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MAX_PEAK && onPeak) { yield put({ type: CYCLIC_VOLTA_METRY.REMOVE_MAX_PEAK, - payload: { index: voltammetryPeakIdx, jcampIdx: curveIdx }, + payload: { index: voltammetryPeakIdx, jcampIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_MIN_PEAK && !onPeak) { yield put({ type: CYCLIC_VOLTA_METRY.ADD_MIN_PEAK, - payload: { peak: payload, index: voltammetryPeakIdx, jcampIdx: curveIdx }, + payload: { peak: payload, index: voltammetryPeakIdx, jcampIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_MIN_PEAK && onPeak) { yield put({ type: CYCLIC_VOLTA_METRY.REMOVE_MIN_PEAK, - payload: { index: voltammetryPeakIdx, jcampIdx: curveIdx }, + payload: { index: voltammetryPeakIdx, jcampIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_ADD_PECKER && !onPecker) { yield put({ type: CYCLIC_VOLTA_METRY.ADD_PECKER, - payload: { peak: payload, index: voltammetryPeakIdx, jcampIdx: curveIdx }, + payload: { peak: payload, index: voltammetryPeakIdx, jcampIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_RM_PECKER && onPecker) { yield put({ type: CYCLIC_VOLTA_METRY.REMOVE_PECKER, - payload: { index: voltammetryPeakIdx, jcampIdx: curveIdx }, + payload: { index: voltammetryPeakIdx, jcampIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.CYCLIC_VOLTA_SET_REF && onPeak) { yield put({ type: CYCLIC_VOLTA_METRY.SET_REF, - payload: { index: voltammetryPeakIdx, jcampIdx: curveIdx }, + payload: { index: voltammetryPeakIdx, jcampIdx: targetCurveIdx }, }); } else if (uiSweepType === LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT) { yield put({ From 490e22ac962208adbd225d64db51b7a79905cf82 Mon Sep 17 00:00:00 2001 From: Nicolass67 Date: Wed, 10 Jun 2026 14:31:34 +0200 Subject: [PATCH 4/7] chore: update dependencies and improve component props handling --- dist/components/cmd_bar/05_multiplicity.js | 2 - dist/components/cmd_bar/r05_submit_btn.js | 1 + dist/helpers/format.js | 17 +-- dist/layer_init.js | 11 +- dist/sagas/saga_multi_entities.js | 5 +- .../units/components/cmd_bar/03_peak.test.js | 2 +- .../components/cmd_bar/r05_submit_btn.test.js | 1 + src/components/cmd_bar/05_multiplicity.js | 4 +- src/components/cmd_bar/07_pecker.js | 114 +++++++++--------- src/components/cmd_bar/r05_submit_btn.js | 1 + src/components/panel/graph_selection.js | 13 +- src/helpers/format.js | 18 +-- src/layer_init.js | 6 + src/sagas/saga_multi_entities.js | 5 +- yarn.lock | 17 +++ 15 files changed, 128 insertions(+), 89 deletions(-) diff --git a/dist/components/cmd_bar/05_multiplicity.js b/dist/components/cmd_bar/05_multiplicity.js index a00b860e..223e38aa 100644 --- a/dist/components/cmd_bar/05_multiplicity.js +++ b/dist/components/cmd_bar/05_multiplicity.js @@ -29,10 +29,8 @@ const Multiplicity = ({ isFocusAddMpySt, disableAddMpySt, isFocusRmMpySt, - disableRmMpySt, isFocusAddPeakSt, isFocusRmPeakSt, - disableMpyPeakSt, setUiSweepTypeAct, clearMpyAllAct, curveSt diff --git a/dist/components/cmd_bar/r05_submit_btn.js b/dist/components/cmd_bar/r05_submit_btn.js index c4582990..6f3faba8 100644 --- a/dist/components/cmd_bar/r05_submit_btn.js +++ b/dist/components/cmd_bar/r05_submit_btn.js @@ -316,6 +316,7 @@ BtnSubmit.propTypes = { axesUnitsSt: _propTypes.default.object.isRequired, detectorSt: _propTypes.default.object.isRequired, metaSt: _propTypes.default.object.isRequired, + sweepExtentSt: _propTypes.default.object, disabled: _propTypes.default.bool, className: _propTypes.default.string, children: _propTypes.default.node diff --git a/dist/helpers/format.js b/dist/helpers/format.js index ef31dd86..ac6c2239 100644 --- a/dist/helpers/format.js +++ b/dist/helpers/format.js @@ -344,25 +344,26 @@ const formatHplcAucPanel = (integration, feature) => { return `${formatHplcRetentionTime(e.rt)}, AUC=${areaVal} (${percent}%)`; }).join(', '); }; -const formatedHplcUvVis = (peaks, decimal = 2, integration, feature) => { +const formatedHplcUvVis = (peaks, decimal = 2, integration, feature, isAscend = false) => { let stack = []; if (integration) { stack = integration.stack; } - let ordered = {}; + let bestByX = {}; peaks.forEach(p => { const x = Number(p.x); - const better = !ordered[x] || p.y > ordered[x]; + const better = bestByX[x] === undefined || p.y > bestByX[x]; if (better) { - ordered = Object.assign({}, ordered, { + bestByX = Object.assign({}, bestByX, { [x]: p.y }); } }); - ordered = Object.keys(ordered).map(k => ({ + const sortFunc = isAscend ? (a, b) => a.x - b.x : (a, b) => b.x - a.x; + const ordered = Object.keys(bestByX).map(k => ({ x: parseFloat(k), - y: ordered[k] - })); + y: bestByX[k] + })).sort(sortFunc); const arrResult = []; ordered.forEach(o => { const rt = formatHplcRetentionTime(o.x); @@ -448,7 +449,7 @@ const peaksBody = ({ return formatedUvVis(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); } if (layout === _list_layout.LIST_LAYOUT.HPLC_UVVIS) { - return formatedHplcUvVis(ordered, decimal, integration, feature); + return formatedHplcUvVis(ordered, decimal, integration, feature, isAscend); } if (layout === _list_layout.LIST_LAYOUT.EMISSIONS) { return formatedEmissions(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); diff --git a/dist/layer_init.js b/dist/layer_init.js index 113ba119..84ef3c26 100644 --- a/dist/layer_init.js +++ b/dist/layer_init.js @@ -58,9 +58,13 @@ class LayerInit extends _react.default.Component { this.updateMultiEntities(true); } componentDidUpdate(prevProps) { + const { + multiEntities, + entity + } = this.props; this.normChange(prevProps); this.updateOthers(); - if (prevProps.multiEntities !== this.props.multiEntities || prevProps.entity !== this.props.entity) { + if (prevProps.multiEntities !== multiEntities || prevProps.entity !== entity) { this.updateMultiEntities(false); } } @@ -260,6 +264,11 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ updateDSCMetaDataAct: _meta.updateDSCMetaData, restoreSweepExtentAct: _ui.restoreSweepExtent }, dispatch); +LayerInit.defaultProps = { + multiEntities: undefined, + curveIdx: undefined, + sweepExtent: undefined +}; LayerInit.propTypes = { entity: _propTypes.default.object.isRequired, multiEntities: _propTypes.default.array, diff --git a/dist/sagas/saga_multi_entities.js b/dist/sagas/saga_multi_entities.js index 48d08e56..92d74fc2 100644 --- a/dist/sagas/saga_multi_entities.js +++ b/dist/sagas/saga_multi_entities.js @@ -189,14 +189,15 @@ function* setInitShifts() { if (feature) { yield (0, _effects.put)({ type: _action_type.MANAGER.RESETSHIFT, - payload: Object.assign({}, feature, { + payload: { + ...feature, layout: layoutSt, curvesInfo: { isMultiCurve: true, curveIdx: index, numberOfCurve } - }) + } }); } } diff --git a/src/__tests__/units/components/cmd_bar/03_peak.test.js b/src/__tests__/units/components/cmd_bar/03_peak.test.js index 32463fa3..cc4bbdc1 100644 --- a/src/__tests__/units/components/cmd_bar/03_peak.test.js +++ b/src/__tests__/units/components/cmd_bar/03_peak.test.js @@ -9,7 +9,7 @@ import { LIST_LAYOUT } from '../../../../constants/list_layout'; const mockStore = configureStore([]); const store = mockStore({ ui:{ sweepType: LIST_UI_SWEEP_TYPE.ZOOMIN }, - layout: LIST_LAYOUT.MS, + layout: LIST_LAYOUT.IR, curve: { curveIdx: 0 }, editPeak: { present: { diff --git a/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js b/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js index 07fc359c..1a3042ec 100644 --- a/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js +++ b/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js @@ -32,6 +32,7 @@ const buildBaseState = (overrides = {}) => ({ detector: {}, meta: { dscMetaData: {} }, hplcMs: {}, + ui: { sweepExtent: { xExtent: false, yExtent: false } }, ...overrides, }); diff --git a/src/components/cmd_bar/05_multiplicity.js b/src/components/cmd_bar/05_multiplicity.js index d5b0b02a..f7a4a41f 100644 --- a/src/components/cmd_bar/05_multiplicity.js +++ b/src/components/cmd_bar/05_multiplicity.js @@ -27,8 +27,8 @@ const styles = () => ( ); const Multiplicity = ({ - classes, isFocusAddMpySt, disableAddMpySt, isFocusRmMpySt, disableRmMpySt, - isFocusAddPeakSt, isFocusRmPeakSt, disableMpyPeakSt, + classes, isFocusAddMpySt, disableAddMpySt, isFocusRmMpySt, + isFocusAddPeakSt, isFocusRmPeakSt, setUiSweepTypeAct, clearMpyAllAct, curveSt, }) => { const onSweepMutAdd = () => setUiSweepTypeAct(LIST_UI_SWEEP_TYPE.MULTIPLICITY_SWEEP_ADD); diff --git a/src/components/cmd_bar/07_pecker.js b/src/components/cmd_bar/07_pecker.js index 3029e6e7..3959911c 100644 --- a/src/components/cmd_bar/07_pecker.js +++ b/src/components/cmd_bar/07_pecker.js @@ -103,63 +103,63 @@ const Pecker = ({ return ( - Add Pecker}> - - - - I - λ0 - + - - - - - Remove Pecker}> - - - - I - λ0 - - - - - - - { - setRef(classes, cyclicVotaSt, curveIdx, setCylicVoltaRefFactorAct) - } - {hasRefPeaks ? 'Set Reference' : 'Set Shift'}}> - - - - - - - + Add Pecker}> + + + + I + λ0 + + + + + + + Remove Pecker}> + + + + I + λ0 + - + + + + + { + setRef(classes, cyclicVotaSt, curveIdx, setCylicVoltaRefFactorAct) + } + {hasRefPeaks ? 'Set Reference' : 'Set Shift'}}> + + + + + + + ); }; diff --git a/src/components/cmd_bar/r05_submit_btn.js b/src/components/cmd_bar/r05_submit_btn.js index 5e37c198..2e499c9e 100644 --- a/src/components/cmd_bar/r05_submit_btn.js +++ b/src/components/cmd_bar/r05_submit_btn.js @@ -388,6 +388,7 @@ BtnSubmit.propTypes = { detectorSt: PropTypes.object.isRequired, metaSt: PropTypes.object.isRequired, hplcMsSt: PropTypes.object, + sweepExtentSt: PropTypes.object, disabled: PropTypes.bool, className: PropTypes.string, children: PropTypes.node, diff --git a/src/components/panel/graph_selection.js b/src/components/panel/graph_selection.js index 4bef9def..c50842aa 100644 --- a/src/components/panel/graph_selection.js +++ b/src/components/panel/graph_selection.js @@ -222,14 +222,13 @@ const GraphSelectionPanel = ({ }
+ ) : ( + + { + items.map((item) => renderCurveItem(classes, item, curveIdx, onChange)) + } + ) - : ( - - { - items.map((item) => renderCurveItem(classes, item, curveIdx, onChange)) - } - - ) } ); diff --git a/src/helpers/format.js b/src/helpers/format.js index 823035ca..62353309 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.js @@ -504,25 +504,29 @@ const formatHplcAucPanel = (integration, feature) => { }; const formatedHplcUvVis = ( - peaks, decimal = 2, integration, feature, + peaks, decimal = 2, integration, feature, isAscend = false, ) => { let stack = []; if (integration) { stack = integration.stack; } - let ordered = {}; + let bestByX = {}; peaks.forEach((p) => { const x = Number(p.x); - const better = !ordered[x] || (p.y > ordered[x]); + const better = bestByX[x] === undefined || (p.y > bestByX[x]); if (better) { - ordered = Object.assign({}, ordered, { [x]: p.y }); + bestByX = Object.assign({}, bestByX, { [x]: p.y }); } }); - ordered = Object.keys(ordered) - .map((k) => ({ x: parseFloat(k), y: ordered[k] })); + const sortFunc = isAscend + ? (a, b) => a.x - b.x + : (a, b) => b.x - a.x; + const ordered = Object.keys(bestByX) + .map((k) => ({ x: parseFloat(k), y: bestByX[k] })) + .sort(sortFunc); const arrResult = []; ordered.forEach((o) => { @@ -607,7 +611,7 @@ const peaksBody = ({ return formatedUvVis(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); } if (layout === LIST_LAYOUT.HPLC_UVVIS) { - return formatedHplcUvVis(ordered, decimal, integration, feature); + return formatedHplcUvVis(ordered, decimal, integration, feature, isAscend); } if (layout === LIST_LAYOUT.EMISSIONS) { return formatedEmissions(ordered, maxY, decimal, isAscend, isIntensity, boundary, false); diff --git a/src/layer_init.js b/src/layer_init.js index f3493b95..fdd99c25 100644 --- a/src/layer_init.js +++ b/src/layer_init.js @@ -349,6 +349,12 @@ const mapDispatchToProps = (dispatch) => ( }, dispatch) ); +LayerInit.defaultProps = { + multiEntities: undefined, + curveIdx: undefined, + sweepExtent: undefined, +}; + LayerInit.propTypes = { entity: PropTypes.object.isRequired, multiEntities: PropTypes.array, // eslint-disable-line diff --git a/src/sagas/saga_multi_entities.js b/src/sagas/saga_multi_entities.js index 0bccfc2f..5c664304 100644 --- a/src/sagas/saga_multi_entities.js +++ b/src/sagas/saga_multi_entities.js @@ -140,14 +140,15 @@ function* setInitShifts() { if (feature) { yield put({ type: MANAGER.RESETSHIFT, - payload: Object.assign({}, feature, { + payload: { + ...feature, layout: layoutSt, curvesInfo: { isMultiCurve: true, curveIdx: index, numberOfCurve, }, - }), + }, }); } } diff --git a/yarn.lock b/yarn.lock index e6147cde..7307128e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10417,6 +10417,15 @@ react-dev-utils@^12.0.1: strip-ansi "^6.0.1" text-table "^0.2.0" +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + react-dropzone@^8.0.3: version "8.2.0" resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-8.2.0.tgz#e889455c4259c018bc5595ab0e2a5f7d958d173a" @@ -10605,6 +10614,14 @@ react-transition-group@^4.3.0, react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + read-cache@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" From b6612ff3ca8205fba5aa851c65e49cbe0b2b9397 Mon Sep 17 00:00:00 2001 From: Nicolass67 Date: Thu, 11 Jun 2026 15:06:48 +0200 Subject: [PATCH 5/7] fix: multi-curve peak add and save for comparison spectra --- dist/actions/ui.js | 21 +++++---- dist/components/cmd_bar/r05_submit_btn.js | 21 +++++++-- dist/helpers/compass.js | 2 +- dist/helpers/format.js | 33 ++++++-------- dist/helpers/shift.js | 33 +++++++++++--- dist/index.js | 16 ++----- dist/reducers/reducer_shift.js | 21 ++++----- dist/sagas/saga_multi_entities.js | 5 +-- .../components/cmd_bar/r05_submit_btn.test.js | 24 +++++++++++ src/__tests__/units/helpers/format.test.tsx | 6 +++ src/components/cmd_bar/r05_submit_btn.js | 24 ++++++++--- src/helpers/compass.js | 2 +- src/helpers/format.js | 28 ++++++------ src/helpers/shift.js | 43 ++++++++++++++++--- src/index.js | 9 +--- src/reducers/reducer_shift.js | 8 +--- src/sagas/saga_multi_entities.js | 6 +-- 17 files changed, 185 insertions(+), 117 deletions(-) diff --git a/dist/actions/ui.js b/dist/actions/ui.js index 7a0e7507..d088011d 100644 --- a/dist/actions/ui.js +++ b/dist/actions/ui.js @@ -31,12 +31,17 @@ const restoreSweepExtent = payload => ({ payload }); exports.restoreSweepExtent = restoreSweepExtent; -const clickUiTarget = (payload, onPeak, voltammetryPeakIdx = 0, jcampIdx = 0, onPecker = false) => ({ - type: _action_type.UI.CLICK_TARGET, - payload, - onPeak, - voltammetryPeakIdx, - jcampIdx, - onPecker -}); +const clickUiTarget = (payload, onPeak, voltammetryPeakIdx = 0, jcampIdx, onPecker = false) => { + const action = { + type: _action_type.UI.CLICK_TARGET, + payload, + onPeak, + voltammetryPeakIdx, + onPecker + }; + if (Number.isFinite(jcampIdx)) { + action.jcampIdx = jcampIdx; + } + return action; +}; exports.clickUiTarget = clickUiTarget; \ 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 index 6f3faba8..daff7d47 100644 --- a/dist/components/cmd_bar/r05_submit_btn.js +++ b/dist/components/cmd_bar/r05_submit_btn.js @@ -17,6 +17,7 @@ var _chem = require("../../helpers/chem"); var _common = require("./common"); var _extractPeaksEdit = require("../../helpers/extractPeaksEdit"); var _format = _interopRequireDefault(require("../../helpers/format")); +var _shift = require("../../helpers/shift"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, function-paren-newline, react/function-component-definition, function-call-argument-newline, @@ -76,7 +77,19 @@ const defaultThreshold = { upper: false, lower: false }; -const pickFromList = (list, index, fallback = null) => Array.isArray(list) && list[index] !== undefined ? list[index] : fallback; +const emptyIntegration = { + stack: [], + refArea: 1, + refFactor: 1, + shift: 0, + edited: false +}; +const emptyMultiplicity = { + stack: [], + shift: 0, + smExtext: false, + edited: false +}; const hasBoolean = value => typeof value === 'boolean'; const resolveOptionalBooleanFlags = analysis => { const flags = {}; @@ -111,9 +124,9 @@ const buildSpectrumPayload = ({ 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 shift = (0, _shift.shiftEntryAtIndex)(shiftSt, curveIdx); + const integration = (0, _shift.listEntryAtIndex)(integrationSt?.integrations, curveIdx, emptyIntegration); + const multiplicity = (0, _shift.listEntryAtIndex)(multiplicitySt?.multiplicities, curveIdx, emptyMultiplicity); const { xLabel, yLabel diff --git a/dist/helpers/compass.js b/dist/helpers/compass.js index e351fdaf..35e06342 100644 --- a/dist/helpers/compass.js +++ b/dist/helpers/compass.js @@ -145,7 +145,7 @@ const ClickCompass = (event, focus) => { focus.clickUiTargetAct(pt, onPeak); } } else { - focus.clickUiTargetAct(pt, false); + focus.clickUiTargetAct(pt, false, 0, focus.jcampIdx); } }; exports.ClickCompass = ClickCompass; diff --git a/dist/helpers/format.js b/dist/helpers/format.js index ac6c2239..b899ec24 100644 --- a/dist/helpers/format.js +++ b/dist/helpers/format.js @@ -159,13 +159,15 @@ const spectraOps = { tail: '.' } }; +const shiftAnchorX = selectedShift => { + if (!selectedShift) return null; + const x = selectedShift.ref?.value ?? selectedShift.peak?.x; + return x == null ? null : x; +}; 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; + if (!shift?.shifts) return peaks; + const refValue = shiftAnchorX(shift.shifts[atIndex]); + if (refValue == null) return peaks; return peaks.map(p => (0, _converter.IsSame)(p.x, refValue) ? null : p).filter(r => r != null); }; const formatedMS = (peaks, maxY, decimal = 2, isAscend = true) => { @@ -398,15 +400,9 @@ const formatedXRD = (peaks, isAscend = true, waveLength, temperature) => { }; 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; + if (!shift?.shifts) return peaks; + const rmShiftX = shiftAnchorX(shift.shifts[atIndex]); + if (rmShiftX == null) return peaks; const result = peaksXY.map(p => { const srcX = parseFloat(p[0]); const x = (0, _converter.IsSame)(srcX, rmShiftX) ? null : srcX; @@ -467,11 +463,8 @@ const peaksBody = ({ }; const peaksWrapper = (layout, shift, atIndex = 0) => { let solvTxt = ''; - const { - shifts - } = shift; - const selectedShift = shifts[atIndex]; - if (selectedShift.ref.label) { + const selectedShift = shift?.shifts ? shift.shifts[atIndex] : shift; + if (selectedShift?.ref?.label) { solvTxt = ` (${selectedShift.ref.label})`; } if (layout === _list_layout.LIST_LAYOUT.PLAIN || layout === _list_layout.LIST_LAYOUT.DLS_ACF) { diff --git a/dist/helpers/shift.js b/dist/helpers/shift.js index bffcc55e..5051a840 100644 --- a/dist/helpers/shift.js +++ b/dist/helpers/shift.js @@ -3,11 +3,35 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.shiftOffsetAtIndex = exports.VirtalPts = exports.RealPts = exports.FromManualToOffset = exports.CalcResidualX = void 0; +exports.shiftOffsetAtIndex = exports.shiftEntryAtIndex = exports.normalizeShiftForFormatting = exports.listEntryAtIndex = exports.defaultEmptyShift = 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 shiftNone = _list_shift.LIST_SHIFT_1H[0]; +const defaultEmptyShift = exports.defaultEmptyShift = { + ref: shiftNone, + peak: false, + enable: true +}; +const listEntryAtIndex = (list, index, fallback) => Array.isArray(list) && list[index] !== undefined ? list[index] : fallback; +exports.listEntryAtIndex = listEntryAtIndex; +const shiftEntryAtIndex = (shiftSt, atIndex = 0) => listEntryAtIndex(shiftSt?.shifts, atIndex, defaultEmptyShift); +exports.shiftEntryAtIndex = shiftEntryAtIndex; +const normalizeShiftForFormatting = (shift, atIndex = 0) => { + if (shift?.shifts) { + return { + shift, + atIndex + }; + } + return { + shift: { + shifts: [shift || defaultEmptyShift] + }, + atIndex: 0 + }; +}; +exports.normalizeShiftForFormatting = normalizeShiftForFormatting; const FromManualToOffset = (ref, peak) => { if (!peak || ref.name === shiftNone.name) return 0; const offset = peak.x - ref.value; @@ -34,13 +58,10 @@ const RealPts = (pts, resX) => pts.map(pt => Object.assign({ })); exports.RealPts = RealPts; const shiftOffsetAtIndex = (shiftSt, atIndex = 0) => { - if (!shiftSt || !shiftSt.shifts) return 0; - const selectedShift = shiftSt.shifts[atIndex]; - if (!selectedShift) return 0; const { ref, peak - } = selectedShift; + } = shiftEntryAtIndex(shiftSt, atIndex); return FromManualToOffset(ref, peak); }; exports.shiftOffsetAtIndex = shiftOffsetAtIndex; \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index 88f8ad09..c30607e6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -6,6 +6,7 @@ var _reactDom = _interopRequireDefault(require("react-dom")); var _material = require("@mui/material"); var _reactQuill = _interopRequireDefault(require("react-quill")); var _app = require("./app"); +var _shift = require("./helpers/shift"); 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")); @@ -58,17 +59,6 @@ const pickSelectedSpectrumFromPayload = payload => { 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); @@ -313,7 +303,7 @@ class DemoWriteIr extends _react.default.Component { maxY, minY }; - const shiftForFormatting = normalizeShiftForFormatting(shift); + const shiftForFormatting = (0, _shift.normalizeShiftForFormatting)(shift); const body = _app.FN.peaksBody({ peaks, layout: safeLayout, @@ -514,7 +504,7 @@ class DemoWriteIr extends _react.default.Component { maxY, minY }; - const shiftForFormatting = normalizeShiftForFormatting(shift); + const shiftForFormatting = (0, _shift.normalizeShiftForFormatting)(shift); const body = _app.FN.peaksBody({ peaks, layout: safeLayout, diff --git a/dist/reducers/reducer_shift.js b/dist/reducers/reducer_shift.js index 4f390e47..81dd2645 100644 --- a/dist/reducers/reducer_shift.js +++ b/dist/reducers/reducer_shift.js @@ -26,11 +26,6 @@ const initialState = { enable: true }] }; -const defaultEmptyShift = { - ref: shiftNone, - peak: false, - enable: true -}; const resetRef = payload => { const { shift, @@ -74,17 +69,17 @@ const resetShift = (state, action) => { const shifts = [...state.shifts]; let selectedShift = shifts[curveIdx]; if (selectedShift === false || selectedShift === undefined) { - selectedShift = defaultEmptyShift; + selectedShift = _shift.defaultEmptyShift; } if (isMultiCurve) { for (let idx = 0; idx < numberOfCurve; idx += 1) { const checkShift = shifts[idx]; if (!checkShift) { - shifts[idx] = defaultEmptyShift; + shifts[idx] = _shift.defaultEmptyShift; } } } - const newShift = Object.assign({}, defaultEmptyShift, { + const newShift = Object.assign({}, _shift.defaultEmptyShift, { ref: resetRef(payload), enable: resetEnable(payload) }); @@ -102,7 +97,7 @@ const updateShift = (state, action) => { } = state; let selectedShift = shifts[selectedIdx]; if (selectedShift === false || selectedShift === undefined) { - selectedShift = defaultEmptyShift; + selectedShift = _shift.defaultEmptyShift; } const newShift = Object.assign({}, selectedShift, { ref: false, @@ -127,7 +122,7 @@ const setRef = (state, action) => { } = state; let selectedShift = shifts[curveIdx]; if (selectedShift === false || selectedShift === undefined) { - selectedShift = defaultEmptyShift; + selectedShift = _shift.defaultEmptyShift; } const newShift = Object.assign({}, selectedShift, { ref: dataToSet, @@ -152,7 +147,7 @@ const setPeak = (state, action) => { } = state; let selectedShift = shifts[curveIdx]; if (selectedShift === false || selectedShift === undefined) { - selectedShift = defaultEmptyShift; + selectedShift = _shift.defaultEmptyShift; } const resX = (0, _shift.CalcResidualX)(selectedShift.ref, selectedShift.peak, dataToSet); const trueApex = (0, _shift.RealPts)([dataToSet], resX)[0]; @@ -176,7 +171,7 @@ const removePeak = (state, action) => { } = state; let selectedShift = shifts[selectedIdx]; if (selectedShift === false || selectedShift === undefined) { - selectedShift = defaultEmptyShift; + selectedShift = _shift.defaultEmptyShift; } const newShift = Object.assign({}, selectedShift, { peak: false, @@ -201,7 +196,7 @@ const addNegative = (state, action) => { } = state; let selectedShift = shifts[curveIdx]; if (selectedShift === false || selectedShift === undefined) { - selectedShift = defaultEmptyShift; + selectedShift = _shift.defaultEmptyShift; } const rmApex = selectedShift.peak.x === dataToAdd.x; if (!rmApex) { diff --git a/dist/sagas/saga_multi_entities.js b/dist/sagas/saga_multi_entities.js index 92d74fc2..9124f8d6 100644 --- a/dist/sagas/saga_multi_entities.js +++ b/dist/sagas/saga_multi_entities.js @@ -170,10 +170,6 @@ function* setCyclicVoltametryRef(action) { }); } function* setInitShifts() { - const layoutSt = yield (0, _effects.select)(getLayoutSt); - if (!_format.default.isNmrLayout(layoutSt)) { - return; - } const curveSt = yield (0, _effects.select)(getCurveSt); const { listCurves @@ -181,6 +177,7 @@ function* setInitShifts() { if (!listCurves || listCurves.length <= 1) { return; } + const layoutSt = yield (0, _effects.select)(getLayoutSt); const numberOfCurve = listCurves.length; for (let index = 0; index < listCurves.length; index += 1) { const { diff --git a/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js b/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js index 1a3042ec..f0f3c5c9 100644 --- a/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js +++ b/src/__tests__/units/components/cmd_bar/r05_submit_btn.test.js @@ -5,6 +5,7 @@ import '@testing-library/jest-dom'; import BtnSubmit, { computeCvYScaleFactor } from '../../../../components/cmd_bar/r05_submit_btn'; import Format from '../../../../helpers/format'; +import { defaultEmptyShift } from '../../../../helpers/shift'; jest.mock('../../../../helpers/extractPeaksEdit', () => ({ extractPeaksEdit: () => [{ x: 1, y: 2 }], @@ -93,6 +94,29 @@ describe('', () => { expect(payload.curveSt).toEqual({ curveIdx: 1 }); }); + it('sends a default shift entry when the curve index is missing', () => { + const operationValue = jest.fn(); + const state = buildBaseState({ + layout: 'HPLC_UVVIS', + shift: { shifts: [defaultEmptyShift] }, + curve: { + curveIdx: 1, + listCurves: [ + { feature: { xUnit: 'min', yUnit: 'mAU', scanAutoTarget: 1, thresRef: 3 } }, + { feature: { xUnit: 'min', yUnit: 'mAU', scanAutoTarget: 2, thresRef: 4 } }, + ], + }, + threshold: { list: [{ value: 10 }, { value: 20 }] }, + axesUnits: { axes: [{ xUnit: '', yUnit: '' }, { xUnit: '', yUnit: '' }] }, + }); + + renderBtnSubmit(state, operationValue); + + const { shift } = operationValue.mock.calls[0][0].spectra_list[1]; + expect(shift).toEqual(defaultEmptyShift); + expect(shift).not.toHaveProperty('shifts'); + }); + it('controls presence/absence of keepPred and simulatenmr', () => { const withFlagsCb = jest.fn(); const noFlagsCb = jest.fn(); diff --git a/src/__tests__/units/helpers/format.test.tsx b/src/__tests__/units/helpers/format.test.tsx index ec1b27db..b5f618ce 100644 --- a/src/__tests__/units/helpers/format.test.tsx +++ b/src/__tests__/units/helpers/format.test.tsx @@ -330,6 +330,12 @@ describe('Test format helper', () => { const removedPeaks = Format.rmRef(peaks, shift) expect(removedPeaks).toEqual([{x: 2.04, y: 2}]) }) + + it('Returns peaks unchanged when shift index is missing', () => { + const shift = { shifts: [{ ref: LIST_SHIFT_1H[1] }] } + const removedPeaks = Format.rmRef(peaks, shift, 1) + expect(removedPeaks).toEqual(peaks) + }) }) }) diff --git a/src/components/cmd_bar/r05_submit_btn.js b/src/components/cmd_bar/r05_submit_btn.js index 2e499c9e..7a35ce2d 100644 --- a/src/components/cmd_bar/r05_submit_btn.js +++ b/src/components/cmd_bar/r05_submit_btn.js @@ -22,6 +22,7 @@ import { getLcmsMzPageData, } from '../../helpers/extractPeaksEdit'; import Format from '../../helpers/format'; +import { shiftEntryAtIndex, listEntryAtIndex } from '../../helpers/shift'; const styles = () => ( Object.assign( @@ -97,9 +98,20 @@ const resolveLcmsIntegrationsExportForSubmit = (analysis, hplcMsSt) => { return 'percent'; }; -const pickFromList = (list, index, fallback = null) => ( - Array.isArray(list) && list[index] !== undefined ? list[index] : fallback -); +const emptyIntegration = { + stack: [], + refArea: 1, + refFactor: 1, + shift: 0, + edited: false, +}; + +const emptyMultiplicity = { + stack: [], + shift: 0, + smExtext: false, + edited: false, +}; const hasBoolean = (value) => typeof value === 'boolean'; @@ -142,9 +154,9 @@ const buildSpectrumPayload = ({ ); const scan = Convert2Scan(feature, scanSt); const thres = 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 shift = shiftEntryAtIndex(shiftSt, curveIdx); + const integration = listEntryAtIndex(integrationSt?.integrations, curveIdx, emptyIntegration); + const multiplicity = listEntryAtIndex(multiplicitySt?.multiplicities, curveIdx, emptyMultiplicity); const { xLabel, yLabel } = resolveAxisLabels( feature?.xUnit, feature?.yUnit, diff --git a/src/helpers/compass.js b/src/helpers/compass.js index 96f11e2d..a28d7c91 100644 --- a/src/helpers/compass.js +++ b/src/helpers/compass.js @@ -310,7 +310,7 @@ const ClickCompass = (event, focus) => { } else if (isLcmsTicGraph) { focus.clickUiTargetAct(pt, false, false, jcampIdx, false, 'lcms_tic'); } else { - focus.clickUiTargetAct(pt, false); + focus.clickUiTargetAct(pt, false, 0, focus.jcampIdx); } }; diff --git a/src/helpers/format.js b/src/helpers/format.js index 62353309..9f010a70 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.js @@ -111,11 +111,16 @@ const spectraOps = { [LIST_LAYOUT.LC_MS]: { head: 'HPLC UV/VIS', tail: '' }, }; +const shiftAnchorX = (selectedShift) => { + if (!selectedShift) return null; + const x = selectedShift.ref?.value ?? selectedShift.peak?.x; + return x == null ? null : x; +}; + 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; + if (!shift?.shifts) return peaks; + const refValue = shiftAnchorX(shift.shifts[atIndex]); + if (refValue == null) return peaks; return peaks.map( (p) => (IsSame(p.x, refValue) ? null : p), ).filter((r) => r != null); @@ -568,13 +573,9 @@ const formatedXRD = ( const rmShiftFromPeaks = (peaks, shift, atIndex = 0) => { const peaksXY = 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; + if (!shift?.shifts) return peaks; + const rmShiftX = shiftAnchorX(shift.shifts[atIndex]); + if (rmShiftX == null) return peaks; const result = peaksXY.map((p) => { const srcX = parseFloat(p[0]); const x = IsSame(srcX, rmShiftX) ? null : srcX; @@ -636,9 +637,8 @@ const peaksBody = ({ const peaksWrapper = (layout, shift, atIndex = 0) => { let solvTxt = ''; - const { shifts } = shift; - const selectedShift = shifts[atIndex]; - if (selectedShift.ref.label) { + const selectedShift = shift?.shifts ? shift.shifts[atIndex] : shift; + if (selectedShift?.ref?.label) { solvTxt = ` (${selectedShift.ref.label})`; } diff --git a/src/helpers/shift.js b/src/helpers/shift.js index 50a31a69..01af80f5 100644 --- a/src/helpers/shift.js +++ b/src/helpers/shift.js @@ -1,7 +1,31 @@ /* eslint-disable prefer-object-spread, default-param-last */ -import { LIST_SHIFT_13C } from '../constants/list_shift'; +import { LIST_SHIFT_1H } from '../constants/list_shift'; -const shiftNone = LIST_SHIFT_13C[0]; +const shiftNone = LIST_SHIFT_1H[0]; + +const defaultEmptyShift = { + ref: shiftNone, + peak: false, + enable: true, +}; + +const listEntryAtIndex = (list, index, fallback) => ( + Array.isArray(list) && list[index] !== undefined ? list[index] : fallback +); + +const shiftEntryAtIndex = (shiftSt, atIndex = 0) => ( + listEntryAtIndex(shiftSt?.shifts, atIndex, defaultEmptyShift) +); + +const normalizeShiftForFormatting = (shift, atIndex = 0) => { + if (shift?.shifts) { + return { shift, atIndex }; + } + return { + shift: { shifts: [shift || defaultEmptyShift] }, + atIndex: 0, + }; +}; const FromManualToOffset = (ref, peak) => { if (!peak || ref.name === shiftNone.name) return 0; @@ -41,13 +65,18 @@ const RealPts = (pts, resX) => ( ); const shiftOffsetAtIndex = (shiftSt, atIndex = 0) => { - if (!shiftSt || !shiftSt.shifts) return 0; - const selectedShift = shiftSt.shifts[atIndex]; - if (!selectedShift) return 0; - const { ref, peak } = selectedShift; + const { ref, peak } = shiftEntryAtIndex(shiftSt, atIndex); return FromManualToOffset(ref, peak); }; export { - FromManualToOffset, CalcResidualX, VirtalPts, RealPts, shiftOffsetAtIndex, + defaultEmptyShift, + listEntryAtIndex, + shiftEntryAtIndex, + normalizeShiftForFormatting, + FromManualToOffset, + CalcResidualX, + VirtalPts, + RealPts, + shiftOffsetAtIndex, }; diff --git a/src/index.js b/src/index.js index b789a2b4..4d7d76f0 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ import ReactQuill from 'react-quill'; import { SpectraEditor, FN, store } from './app'; import { getLcMsInfo } from './helpers/extractEntityLCMS'; import { snapRtToAxis } from './reducers/reducer_hplc_ms/utils'; +import { normalizeShiftForFormatting } from './helpers/shift'; import nmr1HJcamp from './__tests__/fixtures/nmr1h_jcamp'; import nmr1H2Jcamp from './__tests__/fixtures/nmr1h_2_jcamp'; import nmr13CDeptJcamp from './__tests__/fixtures/nmr13c_dept_jcamp'; @@ -70,14 +71,6 @@ const pickSelectedSpectrumFromPayload = (payload) => { 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 = FN.ExtractJcamp(nmr1HJcamp); const nmr1HEntity2 = FN.ExtractJcamp(nmr1H2Jcamp); const nmr13CEntity = FN.ExtractJcamp(nmr13CJcamp); diff --git a/src/reducers/reducer_shift.js b/src/reducers/reducer_shift.js index fae0c9d8..57924a68 100644 --- a/src/reducers/reducer_shift.js +++ b/src/reducers/reducer_shift.js @@ -3,7 +3,7 @@ import { SHIFT, EDITPEAK, MANAGER, LAYOUT, CURVE, } from '../constants/action_type'; import { getListShift, LIST_SHIFT_1H } from '../constants/list_shift'; -import { CalcResidualX, RealPts } from '../helpers/shift'; +import { CalcResidualX, RealPts, defaultEmptyShift } from '../helpers/shift'; const shiftNone = LIST_SHIFT_1H[0]; const normalizeShiftName = (input) => ( @@ -31,12 +31,6 @@ const initialState = { ], }; -const defaultEmptyShift = { - ref: shiftNone, - peak: false, - enable: true, -}; - const resetRef = (payload) => { const { shift, layout } = payload; if (!shift || !shift.solventName || !shift.solventValue) return shiftNone; diff --git a/src/sagas/saga_multi_entities.js b/src/sagas/saga_multi_entities.js index 5c664304..a87028bf 100644 --- a/src/sagas/saga_multi_entities.js +++ b/src/sagas/saga_multi_entities.js @@ -123,17 +123,13 @@ function* setCyclicVoltametryRef(action) { // eslint-disable-line } function* setInitShifts() { - const layoutSt = yield select(getLayoutSt); - if (!Format.isNmrLayout(layoutSt)) { - return; - } - const curveSt = yield select(getCurveSt); const { listCurves } = curveSt; if (!listCurves || listCurves.length <= 1) { return; } + const layoutSt = yield select(getLayoutSt); const numberOfCurve = listCurves.length; for (let index = 0; index < listCurves.length; index += 1) { const { feature } = listCurves[index]; From 919bd973d6e0389d90dda15bd50b60f5f03be70a Mon Sep 17 00:00:00 2001 From: Nicolass67 Date: Thu, 11 Jun 2026 15:12:59 +0200 Subject: [PATCH 6/7] fix: resolve ESLint errors blocking CI build --- dist/actions/ui.js | 6 ++--- dist/sagas/saga_multi_entities.js | 2 -- src/actions/ui.js | 30 +++++++++++------------- src/components/cmd_bar/r05_submit_btn.js | 8 +++++-- src/sagas/saga_multi_entities.js | 1 - 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/dist/actions/ui.js b/dist/actions/ui.js index d088011d..b2150c06 100644 --- a/dist/actions/ui.js +++ b/dist/actions/ui.js @@ -31,13 +31,13 @@ const restoreSweepExtent = payload => ({ payload }); exports.restoreSweepExtent = restoreSweepExtent; -const clickUiTarget = (payload, onPeak, voltammetryPeakIdx = 0, jcampIdx, onPecker = false) => { +const clickUiTarget = (payload, onPeak, voltammetryPeakIdx, jcampIdx, onPecker) => { const action = { type: _action_type.UI.CLICK_TARGET, payload, onPeak, - voltammetryPeakIdx, - onPecker + voltammetryPeakIdx: voltammetryPeakIdx ?? 0, + onPecker: onPecker ?? false }; if (Number.isFinite(jcampIdx)) { action.jcampIdx = jcampIdx; diff --git a/dist/sagas/saga_multi_entities.js b/dist/sagas/saga_multi_entities.js index 9124f8d6..16c89a4c 100644 --- a/dist/sagas/saga_multi_entities.js +++ b/dist/sagas/saga_multi_entities.js @@ -1,6 +1,5 @@ "use strict"; -var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); @@ -8,7 +7,6 @@ exports.default = void 0; var _effects = require("redux-saga/effects"); var _action_type = require("../constants/action_type"); var _list_layout = require("../constants/list_layout"); -var _format = _interopRequireDefault(require("../helpers/format")); /* eslint-disable no-plusplus */ const getLayoutSt = state => state.layout; diff --git a/src/actions/ui.js b/src/actions/ui.js index 55b97c92..75c111f3 100644 --- a/src/actions/ui.js +++ b/src/actions/ui.js @@ -55,22 +55,20 @@ const restoreSweepExtent = (payload) => ( } ); -const clickUiTarget = ( - payload, - onPeak, - voltammetryPeakIdx = 0, - jcampIdx = 0, - onPecker = false, - sourceHint = null, -) => ({ - type: UI.CLICK_TARGET, - payload, - onPeak, - voltammetryPeakIdx, - jcampIdx, - onPecker, - sourceHint, -}); +const clickUiTarget = (payload, onPeak, voltammetryPeakIdx, jcampIdx, onPecker, sourceHint) => { + const action = { + type: UI.CLICK_TARGET, + payload, + onPeak, + voltammetryPeakIdx: voltammetryPeakIdx ?? 0, + onPecker: onPecker ?? false, + sourceHint: sourceHint ?? null, + }; + if (Number.isFinite(jcampIdx)) { + action.jcampIdx = jcampIdx; + } + return action; +}; const displaySubViewerAt = (payload) => ({ type: UI.SUB_VIEWER.DISPLAY_VIEWER_AT, diff --git a/src/components/cmd_bar/r05_submit_btn.js b/src/components/cmd_bar/r05_submit_btn.js index 7a35ce2d..f864a10a 100644 --- a/src/components/cmd_bar/r05_submit_btn.js +++ b/src/components/cmd_bar/r05_submit_btn.js @@ -155,8 +155,12 @@ const buildSpectrumPayload = ({ const scan = Convert2Scan(feature, scanSt); const thres = Convert2Thres(feature, threshold); const shift = shiftEntryAtIndex(shiftSt, curveIdx); - const integration = listEntryAtIndex(integrationSt?.integrations, curveIdx, emptyIntegration); - const multiplicity = listEntryAtIndex(multiplicitySt?.multiplicities, curveIdx, emptyMultiplicity); + const integration = listEntryAtIndex( + integrationSt?.integrations, curveIdx, emptyIntegration, + ); + const multiplicity = listEntryAtIndex( + multiplicitySt?.multiplicities, curveIdx, emptyMultiplicity, + ); const { xLabel, yLabel } = resolveAxisLabels( feature?.xUnit, feature?.yUnit, diff --git a/src/sagas/saga_multi_entities.js b/src/sagas/saga_multi_entities.js index a87028bf..e2d3a7f6 100644 --- a/src/sagas/saga_multi_entities.js +++ b/src/sagas/saga_multi_entities.js @@ -6,7 +6,6 @@ import { } from '../constants/action_type'; import { LIST_LAYOUT } from '../constants/list_layout'; -import Format from '../helpers/format'; const getLayoutSt = (state) => state.layout; const getCurveSt = (state) => state.curve; From ac44db97298e608213c4bd55d7725644172ca96f Mon Sep 17 00:00:00 2001 From: Adrian Herrmann Date: Mon, 29 Jun 2026 15:17:26 +0200 Subject: [PATCH 7/7] fix after merge --- dist/actions/curve.js | 7 +- dist/actions/integration.js | 19 +- dist/actions/ui.js | 50 +- dist/app.js | 29 +- dist/components/cmd_bar/01_viewer.js | 12 +- dist/components/cmd_bar/03_peak.js | 39 +- dist/components/cmd_bar/04_integration.js | 127 ++++- dist/components/cmd_bar/common.js | 7 +- dist/components/cmd_bar/index.js | 94 +++- dist/components/cmd_bar/r01_layout.js | 6 + dist/components/cmd_bar/r02_scan.js | 26 +- dist/components/cmd_bar/r03_threshold.js | 22 +- dist/components/cmd_bar/r04_submit.js | 67 ++- dist/components/cmd_bar/r05_submit_btn.js | 60 +- dist/components/cmd_bar/r06_predict_btn.js | 8 +- dist/components/cmd_bar/r07_wavelength_btn.js | 19 +- dist/components/cmd_bar/r09_detector.js | 4 +- dist/components/cmd_bar/tri_btn.js | 5 +- dist/components/common/draw.js | 11 +- dist/components/d3_line/index.js | 85 ++- dist/components/d3_line/line_focus.js | 161 +++--- dist/components/d3_multi/index.js | 321 ++++++----- dist/components/d3_multi/multi_focus.js | 161 ++++-- dist/components/multi_jcamps_viewer.js | 24 +- dist/components/panel/compare.js | 146 ++--- .../components/panel/cyclic_voltamery_data.js | 24 +- dist/components/panel/graph_selection.js | 32 +- dist/components/panel/index.js | 48 +- dist/components/panel/info.js | 63 ++- dist/constants/action_type.js | 25 +- dist/constants/list_layout.js | 3 +- dist/constants/list_ui.js | 7 +- dist/fn.js | 5 +- dist/helpers/brush.js | 93 +++- dist/helpers/calc.js | 6 +- dist/helpers/cfg.js | 9 +- dist/helpers/chem.js | 519 +++++++++++++++--- dist/helpers/compass.js | 191 ++++++- dist/helpers/extractParams.js | 151 +++-- dist/helpers/extractPeaksEdit.js | 38 +- dist/helpers/format.js | 178 +++++- dist/helpers/integration.js | 147 ++++- dist/helpers/mount.js | 9 +- dist/index.js | 310 ++++++++++- dist/layer_content.js | 20 +- dist/layer_init.js | 123 ++++- dist/layer_prism.js | 36 +- dist/reducers/index.js | 4 +- dist/reducers/reducer_curve.js | 92 ++-- dist/reducers/reducer_integration.js | 269 ++++++++- dist/reducers/reducer_layout.js | 2 +- dist/reducers/reducer_submit.js | 3 +- dist/reducers/reducer_ui.js | 162 +++++- dist/reducers/undo_redo_config.js | 4 +- dist/sagas/saga_ui.js | 249 ++++++--- dist/setupTests.js | 10 +- src/components/cmd_bar/03_peak.js | 2 +- src/components/panel/info.js | 5 +- src/helpers/chem.js | 1 - 59 files changed, 3421 insertions(+), 929 deletions(-) diff --git a/dist/actions/curve.js b/dist/actions/curve.js index 85bd0062..07877ece 100644 --- a/dist/actions/curve.js +++ b/dist/actions/curve.js @@ -10,9 +10,12 @@ const selectCurve = payload => ({ payload }); exports.selectCurve = selectCurve; -const setAllCurves = payload => ({ +const setAllCurves = (payload, meta) => ({ type: _action_type.CURVE.SET_ALL_CURVES, - payload + payload, + ...(meta && typeof meta === 'object' ? { + meta + } : {}) }); exports.setAllCurves = setAllCurves; const toggleShowAllCurves = payload => ({ diff --git a/dist/actions/integration.js b/dist/actions/integration.js index f81706c4..be96499c 100644 --- a/dist/actions/integration.js +++ b/dist/actions/integration.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.sweepIntegration = exports.setIntegrationFkr = exports.clearIntegrationAll = void 0; +exports.sweepIntegration = exports.splitIntegration = exports.setIntegrationFkr = exports.removeVisualSplitLine = exports.clearIntegrationAll = exports.addVisualSplitLine = void 0; var _action_type = require("../constants/action_type"); const sweepIntegration = payload => ({ type: _action_type.INTEGRATION.SWEEP, @@ -19,6 +19,21 @@ const clearIntegrationAll = payload => ({ type: _action_type.INTEGRATION.CLEAR_ALL, payload }); +exports.clearIntegrationAll = clearIntegrationAll; +const splitIntegration = payload => ({ + type: _action_type.INTEGRATION.SPLIT, + payload +}); +exports.splitIntegration = splitIntegration; +const addVisualSplitLine = payload => ({ + type: _action_type.INTEGRATION.ADD_VISUAL_SPLIT, + payload +}); +exports.addVisualSplitLine = addVisualSplitLine; +const removeVisualSplitLine = payload => ({ + type: _action_type.INTEGRATION.RM_VISUAL_SPLIT, + payload +}); // eslint-disable-line -exports.clearIntegrationAll = clearIntegrationAll; \ No newline at end of file +exports.removeVisualSplitLine = removeVisualSplitLine; \ No newline at end of file diff --git a/dist/actions/ui.js b/dist/actions/ui.js index b2150c06..88a2ab61 100644 --- a/dist/actions/ui.js +++ b/dist/actions/ui.js @@ -3,18 +3,37 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.setUiViewerType = exports.setUiSweepType = exports.selectUiSweep = exports.scrollUiWheel = exports.restoreSweepExtent = exports.clickUiTarget = void 0; +exports.setUiViewerType = exports.setUiSweepType = exports.selectUiSweep = exports.scrollUiWheel = exports.restoreSweepExtent = exports.displaySubViewerAt = exports.clickUiTarget = void 0; var _action_type = require("../constants/action_type"); -const setUiViewerType = payload => ({ - type: _action_type.UI.VIEWER.SET_TYPE, - payload -}); -exports.setUiViewerType = setUiViewerType; -const setUiSweepType = (payload, jcampIdx = 0) => ({ +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, + 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, @@ -31,17 +50,26 @@ const restoreSweepExtent = payload => ({ payload }); exports.restoreSweepExtent = restoreSweepExtent; -const clickUiTarget = (payload, onPeak, voltammetryPeakIdx, jcampIdx, onPecker) => { +const clickUiTarget = (payload, onPeak, voltammetryPeakIdx, jcampIdx, onPecker, sourceHint) => { const action = { type: _action_type.UI.CLICK_TARGET, payload, onPeak, voltammetryPeakIdx: voltammetryPeakIdx ?? 0, - onPecker: onPecker ?? false + onPecker: onPecker ?? false, + sourceHint: sourceHint ?? null }; if (Number.isFinite(jcampIdx)) { action.jcampIdx = jcampIdx; } return action; }; -exports.clickUiTarget = clickUiTarget; \ No newline at end of file +exports.clickUiTarget = clickUiTarget; +const displaySubViewerAt = payload => ({ + type: _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT, + payload: payload == null ? { + x: null, + y: null + } : payload +}); +exports.displaySubViewerAt = displaySubViewerAt; \ No newline at end of file diff --git a/dist/app.js b/dist/app.js index 9821f72f..4c4217b1 100644 --- a/dist/app.js +++ b/dist/app.js @@ -10,7 +10,7 @@ Object.defineProperty(exports, "FN", { return _fn.default; } }); -exports.SpectraEditor = void 0; +exports.store = exports.SpectraEditor = void 0; var _react = _interopRequireDefault(require("react")); var _reactRedux = require("react-redux"); var _redux = require("redux"); @@ -33,8 +33,13 @@ var _jsxRuntime = require("react/jsx-runtime"); 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); +const store = exports.store = (0, _redux.compose)((0, _redux.applyMiddleware)(...middlewares))(_redux.createStore)(_index.default); +try { + sagaMiddleware.run(_index2.default); +} catch (error) { + // Keep startup failure visible without crashing silently. + console.error('[SpectraEditor] Failed to start sagas', error); // eslint-disable-line no-console +} // - - - helper - - - const ensureQuillDelta = descs => { @@ -45,6 +50,10 @@ const ensureQuillDelta = descs => { }; // - - - React - - - +// LC/MS: when `onLcmsPageRequest` is set, the host (e.g. ELN) must reload `multiEntities` +// with MS data for the requested RT/polarity. Triggers include `user_click`, `initial`, +// and `tic_polarity` (TIC polarity dropdown). The standalone demo in `src/index.js` +// implements a local mock via `buildLcmsStandaloneMultiEntities`. const SpectraEditor = ({ entity, others, @@ -64,7 +73,8 @@ const SpectraEditor = ({ entityFileNames, userManualLink, curveIdx, - sweepExtent + sweepExtent, + onLcmsPageRequest }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactRedux.Provider, { store: store, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.StyledEngineProvider, { @@ -88,7 +98,8 @@ const SpectraEditor = ({ editorOnly: editorOnly, exactMass: exactMass, canChangeDescription: canChangeDescription, - onDescriptionChanged: onDescriptionChanged + onDescriptionChanged: onDescriptionChanged, + onLcmsPageRequest: onLcmsPageRequest }) }) }); @@ -111,6 +122,7 @@ SpectraEditor.propTypes = { editorOnly: _propTypes.default.bool, canChangeDescription: _propTypes.default.bool, onDescriptionChanged: _propTypes.default.func, + onLcmsPageRequest: _propTypes.default.func, userManualLink: _propTypes.default.object, exactMass: _propTypes.default.string }; @@ -119,8 +131,8 @@ SpectraEditor.defaultProps = { others: [], addOthersCb: false }, - multiEntities: false, - entityFileNames: false, + multiEntities: [], + entityFileNames: [], cLabel: '', xLabel: '', yLabel: '', @@ -132,5 +144,6 @@ SpectraEditor.defaultProps = { multiMolSvgs: [], editorOnly: false, canChangeDescription: false, - userManualLink: {} + userManualLink: {}, + onLcmsPageRequest: null }; \ No newline at end of file diff --git a/dist/components/cmd_bar/01_viewer.js b/dist/components/cmd_bar/01_viewer.js index 2f77ca2c..c7c6adb0 100644 --- a/dist/components/cmd_bar/01_viewer.js +++ b/dist/components/cmd_bar/01_viewer.js @@ -40,11 +40,13 @@ const Viewer = ({ 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 + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + 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 || disableCmdAnaViewerSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { diff --git a/dist/components/cmd_bar/03_peak.js b/dist/components/cmd_bar/03_peak.js index e446428f..a15b2862 100644 --- a/dist/components/cmd_bar/03_peak.js +++ b/dist/components/cmd_bar/03_peak.js @@ -20,6 +20,8 @@ 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 _hplc_ms = require("../../actions/hplc_ms"); +var _list_layout = require("../../constants/list_layout"); 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, @@ -36,27 +38,32 @@ const Peak = ({ isFocusSetRefSt, disableSetRefSt, isHandleMaxAndMinPeaksSt, - cyclicVotaSt, + cyclicVoltaState, curveSt, clearAllPeaksAct, feature, editPeakSt, thresSt, shiftSt, - layoutSt + layoutSt, + clearAllPeaksHplcMsAct }) => { let onSweepPeakAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD); - let onSweepPeakDELETE = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.PEAK_DELETE); + 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 (layoutSt === _list_layout.LIST_LAYOUT.LC_MS) { + clearAllPeaksHplcMsAct(); + } else { + const dataPeaks = (0, _extractPeaksEdit.extractAutoPeaks)(feature, thresSt, shiftSt, layoutSt); + clearAllPeaksAct({ + curveIdx, + dataPeaks + }); + } }; const showAddPeak = !disableAddPeakSt; const showRmPeak = !disableRmPeakSt; @@ -68,7 +75,7 @@ const Peak = ({ if (isHandleMaxAndMinPeaksSt) { const { spectraList - } = cyclicVotaSt; + } = cyclicVoltaState; const spectra = spectraList[curveIdx]; if (spectra) { const { @@ -76,10 +83,10 @@ const Peak = ({ } = 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); + 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); + 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); } @@ -157,7 +164,7 @@ const mapStateToProps = (state, props) => ( 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, + cyclicVoltaState: state.cyclicvolta, curveSt: state.curve, editPeakSt: state.editPeak.present, thresSt: state.threshold.list[state.curve.curveIdx], @@ -166,7 +173,8 @@ const mapStateToProps = (state, props) => ( }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ setUiSweepTypeAct: _ui.setUiSweepType, - clearAllPeaksAct: _edit_peak.clearAllPeaks + clearAllPeaksAct: _edit_peak.clearAllPeaks, + clearAllPeaksHplcMsAct: _hplc_ms.clearAllPeaksHplcMs }, dispatch); Peak.propTypes = { classes: _propTypes.default.object.isRequired, @@ -178,13 +186,14 @@ Peak.propTypes = { disableSetRefSt: _propTypes.default.bool.isRequired, setUiSweepTypeAct: _propTypes.default.func.isRequired, isHandleMaxAndMinPeaksSt: _propTypes.default.bool.isRequired, - cyclicVotaSt: _propTypes.default.object.isRequired, + cyclicVoltaState: _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 + shiftSt: _propTypes.default.object.isRequired, + clearAllPeaksHplcMsAct: _propTypes.default.func.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 index 1fc83521..e4408c36 100644 --- a/dist/components/cmd_bar/04_integration.js +++ b/dist/components/cmd_bar/04_integration.js @@ -16,22 +16,34 @@ var _TextField = _interopRequireDefault(require("@mui/material/TextField")); var _react2 = _interopRequireDefault(require("@mdi/react")); var _js = require("@mdi/js"); var _integration = require("../../actions/integration"); +var _hplc_ms = require("../../actions/hplc_ms"); 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 _list_layout = require("../../constants/list_layout"); 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: {} + txtIcon: {}, + cancelBtn: { + borderColor: '#d32f2f', + color: '#d32f2f', + '&:hover': { + backgroundColor: '#ffebee' + } + } }, _common.commonStyle); const iconSize = '16px'; const setFactor = (classes, integrationSt, setIntegrationFkrAct, curveIdx) => { @@ -81,25 +93,58 @@ const iconColor = criteria => criteria ? '#fff' : '#000'; const Integration = ({ classes, ignoreRef, + showIntegSplitToolsSt, isDisableSt, isFocusAddIntgSt, isFocusRmIntgSt, isFocusSetRefSt, + isFocusSplitIntgSt, + isFocusVisualSplitIntgSt, setUiSweepTypeAct, setIntegrationFkrAct, clearIntegrationAllAct, curveSt, - integrationSt + integrationSt, + clearIntegrationAllHplcMsAct, + layoutSt }) => { - const onSweepIntegtAdd = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD); - const onSweepIntegtRm = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_RM); - const onSweepIntegtSR = () => setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SET_REF); const { curveIdx } = curveSt; - const onClearAll = () => clearIntegrationAllAct({ - curveIdx - }); + 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 onClearAll = () => { + if (layoutSt === _list_layout.LIST_LAYOUT.LC_MS) { + clearIntegrationAllHplcMsAct(); + } else { + clearIntegrationAllAct({ + curveIdx + }); + } + }; + const onSweepIntegtSplit = () => { + if (isFocusSplitIntgSt) { + onCancelTool(); + return; + } + setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, curveIdx); + }; + const onSweepIntegtVisualSplit = () => { + if (isFocusVisualSplitIntgSt) { + onCancelTool(); + return; + } + setUiSweepTypeAct(_list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, curveIdx); + }; if (isDisableSt) { return null; } @@ -112,14 +157,14 @@ const Integration = ({ }), children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_common.MuButton, { - className: (0, _classnames.default)((0, _common.focusStyle)(isFocusAddIntgSt, classes), 'btn-add-inter'), + className: (0, _classnames.default)(isFocusAddIntgSt ? classes.cancelBtn : (0, _common.focusStyle)(false, classes), 'btn-add-inter'), onClick: onSweepIntegtAdd, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, { - path: _js.mdiMathIntegral, + path: isFocusAddIntgSt ? _js.mdiClose : _js.mdiMathIntegral, size: iconSize, color: iconColor(isFocusAddIntgSt), className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-addint') - }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + }), isFocusAddIntgSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-addint'), children: "+" })] @@ -162,7 +207,49 @@ const Integration = ({ }) }) }) - }), !ignoreRef ? setFactor(classes, integrationSt, setIntegrationFkrAct, curveIdx) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { + }), showIntegSplitToolsSt ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { + children: [/*#__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'), + onClick: onSweepIntegtSplit, + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, { + path: isFocusSplitIntgSt ? _js.mdiClose : _js.mdiMathIntegral, + size: iconSize, + color: isFocusSplitIntgSt ? '#d32f2f' : iconColor(false), + 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: "/" + })] + }) + }) + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, { + title: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: "txt-sv-tp", + children: "Visual Split Integration" + }), + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_common.MuButton, { + className: (0, _classnames.default)(isFocusVisualSplitIntgSt ? classes.cancelBtn : (0, _common.focusStyle)(false, classes), 'btn-visual-split-inter'), + onClick: onSweepIntegtVisualSplit, + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, { + path: isFocusVisualSplitIntgSt ? _js.mdiClose : _js.mdiMathIntegral, + size: iconSize, + color: isFocusVisualSplitIntgSt ? '#d32f2f' : iconColor(false), + className: (0, _classnames.default)(classes.iconMdi, 'icon-sv-bar-visualsplitint') + }), isFocusVisualSplitIntgSt ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: (0, _classnames.default)(classes.txt, classes.txtIcon, 'txt-sv-bar-visualsplitint'), + children: "|" + })] + }) + }) + })] + }) : null, !ignoreRef ? setFactor(classes, integrationSt, setIntegrationFkrAct, curveIdx) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_tri_btn.default, { content: { tp: 'Clear All Integration' }, @@ -186,14 +273,19 @@ const mapStateToProps = (state, props) => ( 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, + isFocusVisualSplitIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, ignoreRef: _format.default.isHplcUvVisLayout(state.layout), + showIntegSplitToolsSt: _cfg.default.showIntegSplitTools(state.layout), curveSt: state.curve, - integrationSt: state.integration.present + integrationSt: state.integration.present, + layoutSt: state.layout }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ setUiSweepTypeAct: _ui.setUiSweepType, setIntegrationFkrAct: _integration.setIntegrationFkr, - clearIntegrationAllAct: _integration.clearIntegrationAll + clearIntegrationAllAct: _integration.clearIntegrationAll, + clearIntegrationAllHplcMsAct: _hplc_ms.clearIntegrationAllHplcMs }, dispatch); Integration.propTypes = { classes: _propTypes.default.object.isRequired, @@ -201,11 +293,16 @@ Integration.propTypes = { isFocusAddIntgSt: _propTypes.default.bool.isRequired, isFocusRmIntgSt: _propTypes.default.bool.isRequired, isFocusSetRefSt: _propTypes.default.bool.isRequired, + isFocusSplitIntgSt: _propTypes.default.bool.isRequired, + isFocusVisualSplitIntgSt: _propTypes.default.bool.isRequired, ignoreRef: _propTypes.default.bool.isRequired, + showIntegSplitToolsSt: _propTypes.default.bool.isRequired, setUiSweepTypeAct: _propTypes.default.func.isRequired, setIntegrationFkrAct: _propTypes.default.func.isRequired, clearIntegrationAllAct: _propTypes.default.func.isRequired, + clearIntegrationAllHplcMsAct: _propTypes.default.func.isRequired, curveSt: _propTypes.default.object.isRequired, - integrationSt: _propTypes.default.object.isRequired + integrationSt: _propTypes.default.object.isRequired, + layoutSt: _propTypes.default.string.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/common.js b/dist/components/cmd_bar/common.js index f99639f0..b851c116 100644 --- a/dist/components/cmd_bar/common.js +++ b/dist/components/cmd_bar/common.js @@ -26,18 +26,19 @@ const useStyles = (0, _styles.makeStyles)(theme => ({ color: 'black' } })); -const MuButton = props => { +const MuButton = exports.MuButton = /*#__PURE__*/_react.default.forwardRef((props, ref) => { const classes = useStyles(); const { className, ...other } = props; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, { + ref: ref, className: (0, _classnames.default)(classes.muiBtn, className), ...other }); -}; -exports.MuButton = MuButton; +}); +MuButton.displayName = 'MuButton'; const commonStyle = exports.commonStyle = { card: { margin: '0 0 5px 52px', diff --git a/dist/components/cmd_bar/index.js b/dist/components/cmd_bar/index.js index 95ac6cd4..260e9bd1 100644 --- a/dist/components/cmd_bar/index.js +++ b/dist/components/cmd_bar/index.js @@ -31,7 +31,39 @@ 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 styles = () => Object.assign({}, { + cardFlex: { + display: 'flex', + flexWrap: 'wrap', + alignItems: 'center', + justifyContent: 'space-between', + columnGap: 8, + rowGap: 4 + }, + lcMsToolbarLeft: { + display: 'flex', + flexWrap: 'wrap', + alignItems: 'center', + columnGap: 4, + rowGap: 4, + flex: '1 1 auto', + minWidth: 0 + }, + lcMsToolbarRight: { + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + flex: '0 1 auto', + minWidth: 0 + }, + lcMsToolbarRightCluster: { + display: 'flex', + flexWrap: 'wrap', + alignItems: 'center', + columnGap: 8, + rowGap: 4 + } +}, _common.commonStyle); const CmdBar = ({ classes, feature, @@ -41,21 +73,18 @@ const CmdBar = ({ editorOnly, jcampIdx, hideThreshold, - layoutSt + hideMainEditTools, + layoutSt, + prependLcMsToolbar }) => { const isCvLayout = _format.default.isCyclicVoltaLayout(layoutSt); const hideIntegration = isCvLayout || _cfg.default.btnCmdIntg(layoutSt); const hideMultiplicity = isCvLayout || _cfg.default.btnCmdMpy(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 - }), hideIntegration ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_integration.default, {}), hideMultiplicity ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_undo_redo.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r04_submit.default, { + const rightCluster = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_r01_layout.default, { + feature: feature, + hasEdit: hasEdit + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_r04_submit.default, { operations: operations, feature: feature, forecast: forecast, @@ -65,18 +94,42 @@ const CmdBar = ({ }), 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, {})] }); + if (prependLcMsToolbar) { + return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { + className: `${classes.card} ${classes.cardFlex}`, + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", { + className: classes.lcMsToolbarLeft, + children: prependLcMsToolbar + }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { + className: classes.lcMsToolbarRight, + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { + className: classes.lcMsToolbarRightCluster, + children: rightCluster + }) + })] + }); + } + return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { + className: classes.card, + children: [hideMainEditTools ? null : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { + 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 + }), hideIntegration ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_integration.default, {}), hideMultiplicity ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_undo_redo.default, {})] + }), rightCluster] + }); }; 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, @@ -86,6 +139,11 @@ CmdBar.propTypes = { editorOnly: _propTypes.default.bool.isRequired, layoutSt: _propTypes.default.string.isRequired, jcampIdx: _propTypes.default.any, - hideThreshold: _propTypes.default.bool + hideThreshold: _propTypes.default.bool, + hideMainEditTools: _propTypes.default.bool, + prependLcMsToolbar: _propTypes.default.node +}; +CmdBar.defaultProps = { + prependLcMsToolbar: null }; -var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _withStyles.default)(styles))(CmdBar); \ No newline at end of file +var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, null), (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 index 9c52d9b7..148f45e1 100644 --- a/dist/components/cmd_bar/r01_layout.js +++ b/dist/components/cmd_bar/r01_layout.js @@ -226,6 +226,12 @@ const layoutSelect = (classes, layoutSt, updateLayoutAct) => { className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'), children: "MS" }) + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { + value: _list_layout.LIST_LAYOUT.LC_MS, + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: (0, _classnames.default)(classes.txtOpt, 'option-sv-bar-layout'), + children: "LC/MS" + }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { value: _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { diff --git a/dist/components/cmd_bar/r02_scan.js b/dist/components/cmd_bar/r02_scan.js index 89c5b7a3..e684e9c0 100644 --- a/dist/components/cmd_bar/r02_scan.js +++ b/dist/components/cmd_bar/r02_scan.js @@ -37,11 +37,13 @@ const btnRestore = (classes, hasEdit, isEdit, toggleEditAct) => /*#__PURE__*/(0, 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) + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + 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, { @@ -49,12 +51,14 @@ const btnRrfresh = (classes, disabled, refreshAct) => /*#__PURE__*/(0, _jsxRunti 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 + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + 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 + }) }) }) }); diff --git a/dist/components/cmd_bar/r03_threshold.js b/dist/components/cmd_bar/r03_threshold.js index 1bbbd04e..c1016f8d 100644 --- a/dist/components/cmd_bar/r03_threshold.js +++ b/dist/components/cmd_bar/r03_threshold.js @@ -16,6 +16,7 @@ var _CloudDoneOutlined = _interopRequireDefault(require("@mui/icons-material/Clo var _HowToRegOutlined = _interopRequireDefault(require("@mui/icons-material/HowToRegOutlined")); var _RefreshOutlined = _interopRequireDefault(require("@mui/icons-material/RefreshOutlined")); var _cfg = _interopRequireDefault(require("../../helpers/cfg")); +var _format = _interopRequireDefault(require("../../helpers/format")); var _threshold = require("../../actions/threshold"); var _common = require("./common"); var _jsxRuntime = require("react/jsx-runtime"); @@ -95,11 +96,19 @@ const Threshold = ({ thresValSt, isEditSt, curveSt, + hplcMsSt, + layoutSt, updateThresholdValueAct, resetThresholdValueAct, toggleThresholdIsEditAct }) => { - const thresVal = thresValSt || feature.thresRef; + const isLcMs = _format.default.isLCMsLayout(layoutSt); + let thresVal; + if (isLcMs) { + thresVal = hplcMsSt?.threshold?.value != null ? hplcMsSt.threshold.value : feature?.thresRef ?? thresValSt ?? 5; + } else { + thresVal = thresValSt || (feature ? feature.thresRef : hplcMsSt?.threshold?.value); + } const { curveIdx } = curveSt; @@ -149,7 +158,9 @@ const mapStateToProps = (state, props) => ( 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 + curveSt: state.curve, + hplcMsSt: state.hplcMs, + layoutSt: state.layout }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ updateThresholdValueAct: _threshold.updateThresholdValue, @@ -166,6 +177,11 @@ Threshold.propTypes = { curveSt: _propTypes.default.object.isRequired, updateThresholdValueAct: _propTypes.default.func.isRequired, resetThresholdValueAct: _propTypes.default.func.isRequired, - toggleThresholdIsEditAct: _propTypes.default.func.isRequired + toggleThresholdIsEditAct: _propTypes.default.func.isRequired, + hplcMsSt: _propTypes.default.object.isRequired, + layoutSt: _propTypes.default.string +}; +Threshold.defaultProps = { + layoutSt: undefined }; 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 index 3a9431f9..5b1303ac 100644 --- a/dist/components/cmd_bar/r04_submit.js +++ b/dist/components/cmd_bar/r04_submit.js @@ -13,10 +13,12 @@ var _redux = require("redux"); var _material = require("@mui/material"); var _styles = require("@mui/styles"); var _submit = require("../../actions/submit"); +var _hplc_ms = require("../../actions/hplc_ms"); 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 _list_layout = require("../../constants/list_layout"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, function-paren-newline, react/function-component-definition */ @@ -31,6 +33,10 @@ const styles = () => Object.assign({ fieldDecimal: { width: 80 }, + fieldLcmsIntegrationsExport: { + width: 148, + minWidth: 148 + }, fieldOpertaion: { width: 120 } @@ -142,6 +148,44 @@ const decimalSelect = (classes, hideSwitch, decimalSt, updateDecimalAct) => { })] }); }; +const lcmsIntegrationsExportSelect = (classes, layoutSt, value, onChange) => { + if (layoutSt !== _list_layout.LIST_LAYOUT.LC_MS) return null; + const v = ['percent', 'area', 'both'].includes(value) ? value : 'percent'; + return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, { + className: (0, _classnames.default)(classes.fieldLcmsIntegrationsExport), + variant: "outlined", + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.InputLabel, { + id: "select-lcms-intg-export-label", + className: (0, _classnames.default)(classes.selectLabel, 'select-sv-bar-label'), + children: "Integrations text" + }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Select, { + labelId: "select-lcms-intg-export-label", + label: "Integrations text", + value: v, + onChange: onChange, + className: (0, _classnames.default)(classes.selectInput, 'input-sv-bar-lcms-intg-export'), + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { + value: "percent", + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: (0, _classnames.default)(classes.txtOpt), + children: "Percent only" + }) + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { + value: "area", + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: (0, _classnames.default)(classes.txtOpt), + children: "Area (AUC) only" + }) + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { + value: "both", + children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { + className: (0, _classnames.default)(classes.txtOpt), + children: "Percent and area" + }) + })] + })] + }); +}; const operationSelect = (classes, operations, operation, onChangeSelect) => { const options = operations.map(o => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, { value: o.name, @@ -150,7 +194,8 @@ const operationSelect = (classes, operations, operation, onChangeSelect) => { children: o.name }) }, o.name)); - const selectedValue = operation.name || operations[0].name; + const operationNames = operations.map(o => o.name); + const selectedValue = operationNames.includes(operation?.name) ? operation.name : operations[0].name; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, { className: (0, _classnames.default)(classes.fieldOpertaion), variant: "outlined", @@ -199,16 +244,20 @@ const Submit = ({ operationSt, decimalSt, isEmWaveSt, + layoutSt, + lcmsIntegrationsExportSt, toggleIsAscendAct, toggleIsIntensityAct, updateOperationAct, - updateDecimalAct + updateDecimalAct, + setLcmsIntegrationsExportAct }) => { const onChangeSelect = e => selectOperation(e.target.value, operations, updateOperationAct); + const onLcmsIntegrationsExport = e => setLcmsIntegrationsExportAct(e.target.value); 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, { + children: [ascendSelect(classes, hideSwitch, isAscendSt, toggleIsAscendAct), intensitySelect(classes, hideSwitch || !isEmWaveSt, isIntensitySt, toggleIsIntensityAct), decimalSelect(classes, hideSwitch, decimalSt, updateDecimalAct), lcmsIntegrationsExportSelect(classes, layoutSt, lcmsIntegrationsExportSt, onLcmsIntegrationsExport), 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, { @@ -223,17 +272,20 @@ const Submit = ({ const mapStateToProps = (state, props) => ( // eslint-disable-line { + layoutSt: state.layout, isEmWaveSt: _format.default.isEmWaveLayout(state.layout), isAscendSt: state.submit.isAscend, isIntensitySt: state.submit.isIntensity, decimalSt: state.submit.decimal, - operationSt: state.submit.operation + operationSt: state.submit.operation, + lcmsIntegrationsExportSt: state.hplcMs?.lcmsIntegrationsExport || 'percent' }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ toggleIsAscendAct: _submit.toggleIsAscend, toggleIsIntensityAct: _submit.toggleIsIntensity, updateOperationAct: _submit.updateOperation, - updateDecimalAct: _submit.updateDecimal + updateDecimalAct: _submit.updateDecimal, + setLcmsIntegrationsExportAct: _hplc_ms.setLcmsIntegrationsExport }, dispatch); Submit.propTypes = { classes: _propTypes.default.object.isRequired, @@ -251,6 +303,9 @@ Submit.propTypes = { toggleIsAscendAct: _propTypes.default.func.isRequired, toggleIsIntensityAct: _propTypes.default.func.isRequired, updateOperationAct: _propTypes.default.func.isRequired, - updateDecimalAct: _propTypes.default.func.isRequired + updateDecimalAct: _propTypes.default.func.isRequired, + layoutSt: _propTypes.default.string.isRequired, + lcmsIntegrationsExportSt: _propTypes.default.string.isRequired, + setLcmsIntegrationsExportAct: _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 index daff7d47..97767bc7 100644 --- a/dist/components/cmd_bar/r05_submit_btn.js +++ b/dist/components/cmd_bar/r05_submit_btn.js @@ -77,6 +77,20 @@ const defaultThreshold = { upper: false, lower: false }; +const LCMS_INTEGRATIONS_EXPORT_MODES = ['percent', 'area', 'both']; +const isLcmsIntegrationsExportMode = v => LCMS_INTEGRATIONS_EXPORT_MODES.includes(v); +const resolveLcmsIntegrationsExportForSubmit = (analysis, hplcMsSt) => { + if (isLcmsIntegrationsExportMode(analysis?.lcmsIntegrationsExport)) { + return analysis.lcmsIntegrationsExport; + } + if (analysis?.lcmsIncludeIntegrationArea === true) { + return 'both'; + } + if (isLcmsIntegrationsExportMode(hplcMsSt?.lcmsIntegrationsExport)) { + return hplcMsSt.lcmsIntegrationsExport; + } + return 'percent'; +}; const emptyIntegration = { stack: [], refArea: 1, @@ -171,17 +185,36 @@ const buildSpectrumPayload = ({ ...optionalBooleanFlags }; }; -const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, analysis, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaSt, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature, sweepExtentSt) => () => { +const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, analysis, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaSt, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature, hplcMsSt, sweepExtentSt) => () => { const defaultCurves = feature ? [{ feature }] : []; - const curves = Array.isArray(curveList) && curveList.length > 0 ? curveList : defaultCurves; + let curves = Array.isArray(curveList) && curveList.length > 0 ? curveList : defaultCurves; + if (layoutSt === 'LC/MS') { + curves = curves.filter(c => c.lcmsKind === 'uvvis'); + if (curves.length === 0) curves = defaultCurves; + } const fallbackIdx = Number.isFinite(curveSt?.curveIdx) ? curveSt.curveIdx : 0; const indicesToSend = curves.length > 0 ? curves.map((_, index) => index) : [fallbackIdx]; + let lcmsGlobalFields = null; + if (layoutSt === 'LC/MS') { + const lcmsIntegrationsExport = resolveLcmsIntegrationsExportForSubmit(analysis, hplcMsSt); + lcmsGlobalFields = { + lcms_peaks: (0, _extractPeaksEdit.formatLcmsPeaksForBackend)(hplcMsSt), + lcms_integrals: (0, _extractPeaksEdit.formatLcmsIntegralsForBackend)(hplcMsSt), + lcms_integrations_export: lcmsIntegrationsExport, + lcms_peaks_text: _format.default.formatedLCMS(hplcMsSt, isAscend, decimalSt, { + lcmsIntegrationsExport + }), + lcms_uvvis_wavelength: hplcMsSt?.uvvis?.selectedWaveLength ?? null, + lcms_mz_page: hplcMsSt?.tic?.currentPageValue ?? null, + lcms_mz_page_data: (0, _extractPeaksEdit.getLcmsMzPageData)(hplcMsSt) + }; + } const spectraList = indicesToSend.map(curveIdx => { const curve = curves[curveIdx] || {}; const curveFeature = curve.feature || feature; - return buildSpectrumPayload({ + const spectrumPayload = buildSpectrumPayload({ feature: curveFeature, curveIdx, editPeakSt, @@ -201,6 +234,13 @@ const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, ana analysis, decimalSt }); + if (lcmsGlobalFields && curve.lcmsKind === 'uvvis') { + return { + ...spectrumPayload, + ...lcmsGlobalFields + }; + } + return spectrumPayload; }); const selectedIdx = Number.isFinite(curveSt?.curveIdx) ? curveSt.curveIdx : 0; const selectedSpectrumPayload = spectraList[selectedIdx] || spectraList[0] || {}; @@ -208,6 +248,9 @@ const onClickCb = (operationValue, isAscend, isIntensity, layoutSt, shiftSt, ana ...selectedSpectrumPayload, spectra_list: spectraList }; + if (lcmsGlobalFields) { + Object.assign(payload, lcmsGlobalFields); + } if (Number.isFinite(curveSt?.curveIdx)) { payload.curveSt = { curveIdx: curveSt.curveIdx @@ -240,6 +283,7 @@ const BtnSubmit = ({ axesUnitsSt, detectorSt, metaSt, + hplcMsSt, sweepExtentSt, disabled, className, @@ -278,7 +322,7 @@ const BtnSubmit = ({ className: (0, _classnames.default)('btn-sv-bar-submit', className), color: "primary", disabled: disabled, - onClick: onClickCb(operation.value, isAscend, isIntensity, layoutSt, shiftSt, forecastSt.predictions, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaPayload, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature, sweepExtentSt), + onClick: onClickCb(operation.value, isAscend, isIntensity, layoutSt, shiftSt, forecastSt.predictions, decimalSt, integrationSt, multiplicitySt, waveLengthSt, cyclicvoltaPayload, curveSt, axesUnitsSt, detectorSt, dscMetaData, curveList, editPeakSt, thresList, scanSt, feature, hplcMsSt, sweepExtentSt), children: children || /*#__PURE__*/(0, _jsxRuntime.jsx)(_PlayCircleOutline.default, { className: classes.icon }) @@ -304,9 +348,9 @@ const mapStateToProps = (state, props) => ( axesUnitsSt: state.axesUnits, detectorSt: state.detector, metaSt: state.meta, + hplcMsSt: state.hplcMs, sweepExtentSt: state.ui.sweepExtent }); -const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch); BtnSubmit.propTypes = { classes: _propTypes.default.object.isRequired, feature: _propTypes.default.object.isRequired, @@ -329,9 +373,13 @@ BtnSubmit.propTypes = { axesUnitsSt: _propTypes.default.object.isRequired, detectorSt: _propTypes.default.object.isRequired, metaSt: _propTypes.default.object.isRequired, + hplcMsSt: _propTypes.default.object, sweepExtentSt: _propTypes.default.object, disabled: _propTypes.default.bool, className: _propTypes.default.string, children: _propTypes.default.node }; -var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _styles.withStyles)(styles))(BtnSubmit); \ No newline at end of file +BtnSubmit.defaultProps = { + hplcMsSt: {} +}; +var _default = exports.default = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, null), (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 index 0a6b1163..3ee28c82 100644 --- a/dist/components/cmd_bar/r06_predict_btn.js +++ b/dist/components/cmd_bar/r06_predict_btn.js @@ -82,7 +82,7 @@ const onClickReady = (forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analy }); }; }; -const onClicUnknown = (feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analysis, integrationSt, multiplicitySt, curveSt) => { +const onClickUnknown = (feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, analysis, integrationSt, multiplicitySt, curveSt) => { const { refreshCb } = forecast; @@ -170,7 +170,7 @@ const BtnPredict = ({ 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 scan = _format.default.isMsLayout(layoutSt) ? (0, _chem.Convert2Scan)(feature, scanSt) : 0; const thres = (0, _chem.Convert2Thres)(feature, thresSt); const simuCount = simulationSt.nmrSimPeaks.length; const uniqCount = [...new Set(simulationSt.nmrSimPeaks)].length; @@ -191,7 +191,7 @@ const BtnPredict = ({ realCount = stack.length; } if (is13Cor1H && simuCount === 0) { - const onClickUnknownCb = onClicUnknown(feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, forecast.predictions, integrationSt, multiplicitySt, curveSt); + const onClickUnknownCb = onClickUnknown(feature, forecast, peaksEdit, layoutSt, scan, shiftSt, thres, forecast.predictions, integrationSt, multiplicitySt, curveSt); return renderBtnUnknown(classes, onClickUnknownCb); } const predictable = isIr || simuCount >= realCount && realCount > 0; @@ -221,7 +221,7 @@ BtnPredict.propTypes = { feature: _propTypes.default.object.isRequired, forecast: _propTypes.default.object.isRequired, layoutSt: _propTypes.default.string.isRequired, - simulationSt: _propTypes.default.array.isRequired, + simulationSt: _propTypes.default.object.isRequired, editPeakSt: _propTypes.default.object.isRequired, scanSt: _propTypes.default.object.isRequired, shiftSt: _propTypes.default.object.isRequired, diff --git a/dist/components/cmd_bar/r07_wavelength_btn.js b/dist/components/cmd_bar/r07_wavelength_btn.js index 734760e1..183029cd 100644 --- a/dist/components/cmd_bar/r07_wavelength_btn.js +++ b/dist/components/cmd_bar/r07_wavelength_btn.js @@ -28,33 +28,34 @@ const styles = () => Object.assign({ width: 100 } }, _common.commonStyle); -const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWaveLengthAct) => { +const wavelengthSelect = (classes, waveLengthSt, layoutSt, updateWavelengthAct) => { if (!_format.default.isXRDLayout(layoutSt)) { return null; } - const onChange = e => updateWaveLengthAct(e.target.value); + 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" + children: "Wavelength (nm)" }), /*#__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 => { + children: _list_wavelength.LIST_WAVE_LENGTH.map((item, idx) => { // eslint-disable-line + const itemKey = `${item.label}-${item.value}-${item.unit}-${idx}`; 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, ")"] }) - }); + }, itemKey); }) })] }); @@ -63,12 +64,12 @@ const Wavelength = ({ classes, waveLengthSt, layoutSt, - updateWaveLengthAct + updateWavelengthAct }) => { if (!_format.default.isXRDLayout(layoutSt)) return null; return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: classes.groupRight, - children: wavelengthSelect(classes, waveLengthSt, layoutSt, updateWaveLengthAct) + children: wavelengthSelect(classes, waveLengthSt, layoutSt, updateWavelengthAct) }); }; const mapStateToProps = (state, props) => ( @@ -78,12 +79,12 @@ const mapStateToProps = (state, props) => ( layoutSt: state.layout }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ - updateWaveLengthAct: _wavelength.updateWaveLength + 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 + 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/r09_detector.js b/dist/components/cmd_bar/r09_detector.js index e40b4e68..1ad7948c 100644 --- a/dist/components/cmd_bar/r09_detector.js +++ b/dist/components/cmd_bar/r09_detector.js @@ -64,13 +64,13 @@ const detectorSelect = (classes, detectorSt, curveSt, layoutSt, updateDetectorAc 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, { + }, "detector-empty"), _list_detectors.LIST_DETECTORS.map((item, idx) => /*#__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 }) - }))] + }, item?.name || item?.id || `detector-${idx}`))] })] }); }; diff --git a/dist/components/cmd_bar/tri_btn.js b/dist/components/cmd_bar/tri_btn.js index 64800f48..30641cdc 100644 --- a/dist/components/cmd_bar/tri_btn.js +++ b/dist/components/cmd_bar/tri_btn.js @@ -126,6 +126,9 @@ TriBtn.propTypes = { content: _propTypes.default.object.isRequired, cb: _propTypes.default.func.isRequired, children: _propTypes.default.node.isRequired, - isClearAllDisabled: _propTypes.default.bool.isRequired + isClearAllDisabled: _propTypes.default.bool +}; +TriBtn.defaultProps = { + isClearAllDisabled: false }; 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/draw.js b/dist/components/common/draw.js index 16d930f8..0ae7d0c3 100644 --- a/dist/components/common/draw.js +++ b/dist/components/common/draw.js @@ -5,16 +5,17 @@ Object.defineProperty(exports, "__esModule", { }); 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}`); +const { + LIST_BRUSH_SVG_GRAPH +} = require('../../constants/list_graph'); +const drawMain = (klass, w, h, d3svgClass = LIST_BRUSH_SVG_GRAPH.LINE) => { + d3.select(klass).append('svg').attr('class', d3svgClass).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); - } + d3.select(klass).selectAll('.mark-text').text(cLabel || ''); }; exports.drawLabel = drawLabel; const drawDisplay = (klass, isHidden) => { diff --git a/dist/components/d3_line/index.js b/dist/components/d3_line/index.js index d9648444..9b0acfac 100644 --- a/dist/components/d3_line/index.js +++ b/dist/components/d3_line/index.js @@ -12,9 +12,12 @@ 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 _list_graph = require("../../constants/list_graph"); +var _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable no-mixed-operators */ @@ -28,17 +31,24 @@ class ViewerLine extends _react.default.Component { const { clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct + scrollUiWheelAct, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct } = props; - this.rootKlass = '.d3Line'; + this.rootKlass = `.${_list_graph.LIST_ROOT_SVG_GRAPH.LINE}`; this.focus = new _line_focus.default({ W, H, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct + scrollUiWheelAct, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct }); this.normChange = this.normChange.bind(this); + this.syncFocusActions = this.syncFocusActions.bind(this); } componentDidMount() { const { @@ -54,16 +64,20 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integationSt, + integrationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, wavelength, axesUnitsSt, - resetAllAct + resetAllAct, + uiSt } = this.props; + this.syncFocusActions(); (0, _draw.drawDestroy)(this.rootKlass); resetAllAct(feature); let xxLabel = xLabel; @@ -91,12 +105,15 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integationSt, + integrationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, - wavelength + wavelength, + uiSt }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); @@ -114,15 +131,19 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integationSt, + integrationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, wavelength, - axesUnitsSt + axesUnitsSt, + uiSt } = this.props; + this.syncFocusActions(); this.normChange(prevProps); let xxLabel = xLabel; let yyLabel = yLabel; @@ -148,12 +169,15 @@ class ViewerLine extends _react.default.Component { tSfPeaks, editPeakSt, layoutSt, - integationSt, + integrationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, - wavelength + wavelength, + uiSt }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); @@ -161,6 +185,25 @@ class ViewerLine extends _react.default.Component { componentWillUnmount() { (0, _draw.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, @@ -173,7 +216,7 @@ class ViewerLine extends _react.default.Component { } render() { return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: "d3Line" + className: _list_graph.LIST_ROOT_SVG_GRAPH.LINE }); } } @@ -186,19 +229,25 @@ const mapStateToProps = (state, props) => ({ tSfPeaks: (0, _chem.ToShiftPeaks)(state, props), editPeakSt: state.editPeak.present, layoutSt: state.layout, - integationSt: state.integration.present, + integrationSt: state.integration.present, mtplySt: state.multiplicity.present, sweepExtentSt: state.ui.sweepExtent, isUiAddIntgSt: state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD, + isUiSplitIntgSt: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, + isUiVisualSplitIntgSt: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0, wavelength: state.wavelength, - axesUnitsSt: state.axesUnits + axesUnitsSt: state.axesUnits, + uiSt: state.ui }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ resetAllAct: _manager.resetAll, clickUiTargetAct: _ui.clickUiTarget, selectUiSweepAct: _ui.selectUiSweep, scrollUiWheelAct: _ui.scrollUiWheel, + splitIntegrationAct: _integration.splitIntegration, + addVisualSplitLineAct: _integration.addVisualSplitLine, + removeVisualSplitLineAct: _integration.removeVisualSplitLine, addNewCylicVoltaPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak, addCylicVoltaMaxPeakAct: _cyclic_voltammetry.addCylicVoltaMaxPeak, addCylicVoltaMinPeakAct: _cyclic_voltammetry.addCylicVoltaMinPeak @@ -208,6 +257,7 @@ ViewerLine.propTypes = { peak: _propTypes.default.array.isRequired, freq: _propTypes.default.oneOfType([_propTypes.default.bool, _propTypes.default.number]).isRequired, comparisons: _propTypes.default.array.isRequired, + uiSt: _propTypes.default.object.isRequired, cLabel: _propTypes.default.string.isRequired, xLabel: _propTypes.default.string.isRequired, yLabel: _propTypes.default.string.isRequired, @@ -216,15 +266,20 @@ ViewerLine.propTypes = { tSfPeaks: _propTypes.default.array.isRequired, editPeakSt: _propTypes.default.object.isRequired, layoutSt: _propTypes.default.string.isRequired, - integationSt: _propTypes.default.object.isRequired, + integrationSt: _propTypes.default.object.isRequired, mtplySt: _propTypes.default.object.isRequired, sweepExtentSt: _propTypes.default.object.isRequired, isUiAddIntgSt: _propTypes.default.bool.isRequired, + isUiSplitIntgSt: _propTypes.default.bool.isRequired, + isUiVisualSplitIntgSt: _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, + addVisualSplitLineAct: _propTypes.default.func.isRequired, + removeVisualSplitLineAct: _propTypes.default.func.isRequired, isHidden: _propTypes.default.bool.isRequired, wavelength: _propTypes.default.object.isRequired, axesUnitsSt: _propTypes.default.object.isRequired diff --git a/dist/components/d3_line/line_focus.js b/dist/components/d3_line/line_focus.js index 922a2379..35aac661 100644 --- a/dist/components/d3_line/line_focus.js +++ b/dist/components/d3_line/line_focus.js @@ -9,6 +9,8 @@ var _init = require("../../helpers/init"); var _mount = require("../../helpers/mount"); var _brush = _interopRequireDefault(require("../../helpers/brush")); var _compass = require("../../helpers/compass"); +var _integration_focus = require("../../helpers/integration_focus"); +var _integration_split = require("../../helpers/integration_split"); var _converter = require("../../helpers/converter"); var _focus = require("../../helpers/focus"); var _integration = require("../../helpers/integration"); @@ -16,7 +18,6 @@ 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"); -var _calc = require("../../helpers/calc"); /* eslint-disable prefer-object-spread, no-mixed-operators */ const d3 = require('d3'); @@ -27,7 +28,11 @@ class LineFocus { H, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct + scrollUiWheelAct, + uiSt, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct } = props; this.jcampIdx = 0; this.rootKlass = '.d3Line'; @@ -37,11 +42,16 @@ class LineFocus { l: 60, r: 5 }; + this.uiSt = uiSt; + this.graphIndex = uiSt?.zoom?.graphIndex; 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.addVisualSplitLineAct = addVisualSplitLineAct; + this.removeVisualSplitLineAct = removeVisualSplitLineAct; this.brush = d3.brush(); this.brushX = d3.brushX(); this.axis = null; @@ -66,6 +76,11 @@ class LineFocus { this.shouldUpdate = {}; this.freq = false; this.layout = _list_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); this.setTip = this.setTip.bind(this); @@ -83,6 +98,10 @@ 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.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'; this.wavelength = null; @@ -111,7 +130,7 @@ class LineFocus { 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 sameSfPk = prevSfPk === this.tSfPeaks || Array.isArray(prevSfPk) && Array.isArray(this.tSfPeaks) && prevSfPk.length === this.tSfPeaks.length && prevSfPk.every((peak, idx) => peak === this.tSfPeaks[idx]); const sameData = prevData === this.data.length; const sameRef = prevEpSt.prevOffset === nextEpSt.prevOffset; this.shouldUpdate = Object.assign({}, this.shouldUpdate, { @@ -256,49 +275,28 @@ class LineFocus { const onPeak = true; this.clickUiTargetAct(data, onPeak); } + clearSplitPreview() { + (0, _integration_split.clearIntegrationSplitPreview)(this); + } + onIntegrationMouseMove(event, data, shift, ignoreRef) { + (0, _integration_focus.handleIntegrationMouseMove)(this, event, data, shift, ignoreRef); + } + onClickIntegrationTarget(event, data) { + (0, _integration_focus.handleIntegrationClick)(this, event, data, (clickEvent, clickData) => { + this.onClickTarget(clickEvent, clickData); + }); + } + drawVisualSplitLines(stack, shift, ignoreRef) { + (0, _integration_focus.drawVisualSplitLinesForFocus)(this, stack, shift, ignoreRef); + } + drawAUC(stack, shift = 0) { + (0, _integration_focus.drawIntegrationAUC)(this, stack, shift); + } mergedPeaks(editPeakSt) { if (!editPeakSt) return this.dataPks; this.dataPks = (0, _converter.PksEdit)(this.dataPks, editPeakSt); return this.dataPks; } - drawAUC(stack) { - 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 = this.data.filter(d => d.x > xL && d.x < xU); - if (!ps[0]) return null; - const point1 = ps[0]; - const point2 = ps[ps.length - 1]; - const slope = (0, _calc.calcSlope)(point1.x, point1.y, point2.x, point2.y); - let lastDY = point1.y; - 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); - }).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); - }).on('click', (event, d) => this.onClickTarget(event, d)); - } drawPeaks(editPeakSt) { const { sameXY, @@ -361,7 +359,7 @@ class LineFocus { clearPeakLabels(); } } - drawInteg(integationSt) { + drawInteg(integrationState) { const { sameXY, sameLySt, @@ -385,7 +383,7 @@ class LineFocus { const { selectedIdx, integrations - } = integationSt; + } = integrationState; const selectedIntegration = integrations[selectedIdx]; if (selectedIntegration === false || selectedIntegration === undefined) { clearIntegralPaths(); @@ -401,9 +399,20 @@ class LineFocus { const isDisable = _cfg.default.btnCmdIntg(this.layout); const ignoreRef = _format.default.isHplcUvVisLayout(this.layout); const itgs = isDisable ? [] : stack; - const igbp = this.tags.igbPath.selectAll('path').data(itgs); + const { + showIntegSplit, + igBarData + } = (0, _integration_focus.buildIntegrationBarData)(this.layout, itgs); + Object.assign(this, { + integrationSplitTargets: { + stack: itgs, + shift, + ignoreRef + } + }); + const igbp = this.tags.igbPath.selectAll('path').data(igBarData); igbp.exit().attr('class', 'exit').remove(); - const igcp = this.tags.igcPath.selectAll('path').data(itgs); + const igcp = this.tags.igcPath.selectAll('path').data(igBarData); igcp.exit().attr('class', 'exit').remove(); const igtp = this.tags.igtPath.selectAll('text').data(itgs); igtp.exit().attr('class', 'exit').remove(); @@ -414,7 +423,7 @@ class LineFocus { } if (ignoreRef) { clearIntegralPaths(); - this.drawAUC(stack); + this.drawAUC(stack, shift); } else { clearAUC(); // rescale for zoom @@ -431,7 +440,8 @@ class LineFocus { 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'); - }).on('click', (event, d) => this.onClickTarget(event, d)); + if (showIntegSplit) this.clearSplitPreview(); + }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); const integCurve = border => { const { xL, @@ -455,7 +465,8 @@ class LineFocus { 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'); - }).on('click', (event, d) => this.onClickTarget(event, d)); + if (showIntegSplit) this.clearSplitPreview(); + }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).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'); @@ -464,8 +475,10 @@ class LineFocus { 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'); - }).on('click', (event, d) => this.onClickTarget(event, d)); + if (showIntegSplit) this.clearSplitPreview(); + }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); } + this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); } drawMtply(mtplySt) { const { @@ -476,14 +489,17 @@ class LineFocus { if (sameXY && sameLySt && sameMySt) return; const { selectedIdx, - multiplicities - } = mtplySt; - const selectedMulti = multiplicities[selectedIdx]; + multiplicities = [] + } = mtplySt || {}; + const selectedMulti = multiplicities[selectedIdx] || {}; const isDisable = _cfg.default.btnCmdMpy(this.layout); const hasMpy = !isDisable && selectedMulti?.stack?.length > 0; const mpys = hasMpy ? selectedMulti.stack : []; const smExtext = hasMpy ? selectedMulti.smExtext : false; const shift = hasMpy ? selectedMulti.shift : 0; + const hasValidExtent = extent => extent && Number.isFinite(extent.xL) && Number.isFinite(extent.xU); + if (mpys.length === 0 || isDisable) return; + const activeExtent = hasValidExtent(smExtext) ? smExtext : mpys[0].xExtent; // rescale for zoom const { xt @@ -499,7 +515,8 @@ class LineFocus { peaks, xExtent } = m; - return peaks.map(p => Object.assign({}, p, { + const safePeaks = Array.isArray(peaks) ? peaks : []; + return safePeaks.filter(p => Number.isFinite(p?.x) && Number.isFinite(p?.y)).map(p => Object.assign({}, p, { xExtent })); }); @@ -514,7 +531,7 @@ class LineFocus { xL, xU } = d.xExtent; - return smExtext.xL === xL && smExtext.xU === xU ? 'purple' : '#DA70D6'; + return activeExtent.xL === xL && activeExtent.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'); @@ -628,13 +645,18 @@ class LineFocus { comparisons, editPeakSt, layoutSt, - integationSt, + integrationSt, mtplySt, sweepExtentSt, isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, - wavelength + wavelength, + uiSt }) { + this.uiSt = uiSt; + this.graphIndex = uiSt?.zoom?.graphIndex; this.svg = d3.select('.d3Svg'); (0, _mount.MountMainFrame)(this, 'focus'); (0, _mount.MountClip)(this); @@ -642,6 +664,11 @@ class LineFocus { this.scales = (0, _init.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(); (0, _compass.MountCompass)(this); this.axis = (0, _mount.MountAxis)(this); this.path = (0, _mount.MountPath)(this, 'steelblue'); @@ -658,12 +685,12 @@ class LineFocus { this.drawGrid(); this.drawRef(); this.drawPeaks(editPeakSt); - this.drawInteg(integationSt); + this.drawInteg(integrationSt); this.drawMtply(mtplySt); this.drawComparisons(comparisons); } (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt); - this.resetShouldUpdate(editPeakSt, integationSt, mtplySt); + this.resetShouldUpdate(editPeakSt, integrationSt, mtplySt); } update({ filterSeed, @@ -674,30 +701,40 @@ class LineFocus { comparisons, editPeakSt, layoutSt, - integationSt, + integrationSt, mtplySt, + uiSt, sweepExtentSt, isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, wavelength }) { + this.uiSt = uiSt; + this.graphIndex = uiSt?.zoom?.graphIndex; 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, + isUiVisualSplitIntgSt + }); + if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview(); if (this.data && this.data.length > 0) { this.setConfig(sweepExtentSt); - this.getShouldUpdate(editPeakSt, integationSt, mtplySt); + this.getShouldUpdate(editPeakSt, integrationSt, mtplySt); this.drawLine(); this.drawThres(); this.drawGrid(); this.drawRef(); this.drawPeaks(editPeakSt); - this.drawInteg(integationSt); + this.drawInteg(integrationSt); this.drawMtply(mtplySt); this.drawComparisons(comparisons); } (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt); - this.resetShouldUpdate(editPeakSt, integationSt, mtplySt); + this.resetShouldUpdate(editPeakSt, integrationSt, 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 index 3f28c98a..98da6326 100644 --- a/dist/components/d3_multi/index.js +++ b/dist/components/d3_multi/index.js @@ -11,9 +11,12 @@ var _redux = require("redux"); var _propTypes = _interopRequireDefault(require("prop-types")); var _chem = require("../../helpers/chem"); var _format = _interopRequireDefault(require("../../helpers/format")); +var _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _manager = require("../../actions/manager"); var _ui = require("../../actions/ui"); +var _integration = require("../../actions/integration"); var _list_ui = require("../../constants/list_ui"); +var _list_graph = require("../../constants/list_graph"); var _cyclic_voltammetry = require("../../actions/cyclic_voltammetry"); var _multi_focus = _interopRequireDefault(require("./multi_focus")); var _draw = require("../common/draw"); @@ -41,9 +44,12 @@ class ViewerMulti extends _react.default.Component { entities, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct + scrollUiWheelAct, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct } = this.props; - this.rootKlass = '.d3Line'; + this.rootKlass = `.${_list_graph.LIST_ROOT_SVG_GRAPH.LINE}`; this.containerRef = /*#__PURE__*/_react.default.createRef(); this.currentSize = null; this.resizeObserver = null; @@ -53,89 +59,18 @@ class ViewerMulti extends _react.default.Component { entities, clickUiTargetAct, selectUiSweepAct, - scrollUiWheelAct + scrollUiWheelAct, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct }); this.normChange = this.normChange.bind(this); this.handleResize = this.handleResize.bind(this); + this.syncFocusActions = this.syncFocusActions.bind(this); } componentDidMount() { - this.renderChart(this.props, true); this.setupResizeObserver(); - const { - curveSt, - seed, - peak, - cLabel, - xLabel, - yLabel, - feature, - tTrEndPts, - tSfPeaks, - editPeakSt, - layoutSt, - sweepExtentSt, - isUiNoBrushSt, - isHidden, - resetAllAct, - cyclicvoltaSt, - shiftSt, - integationSt, - mtplySt, - axesUnitsSt - } = this.props; - (0, _draw.drawDestroy)(this.rootKlass); - if (!canSkipReset(sweepExtentSt, layoutSt, feature)) { - resetAllAct(buildResetPayload(feature, curveSt)); - } - 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, - isUiNoBrushSt, - cyclicvoltaSt, - shiftSt, - integationSt, - mtplySt - }); - (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); - (0, _draw.drawDisplay)(this.rootKlass, isHidden); - (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden); + this.mountChart(this.props, true); } componentDidUpdate(prevProps) { const { @@ -151,67 +86,52 @@ class ViewerMulti extends _react.default.Component { editPeakSt, layoutSt, sweepExtentSt, + isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, cyclicvoltaSt, shiftSt, - integationSt, + integrationSt, mtplySt, - axesUnitsSt + axesUnitsSt, + uiSt } = this.props; + this.syncFocusActions(); 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(); } + const hasRelevantChange = prevProps.entities !== entities || prevProps.curveSt !== curveSt || prevProps.seed !== seed || prevProps.peak !== peak || prevProps.tTrEndPts !== tTrEndPts || prevProps.tSfPeaks !== tSfPeaks || prevProps.editPeakSt !== editPeakSt || prevProps.layoutSt !== layoutSt || prevProps.sweepExtentSt !== sweepExtentSt || prevProps.isUiNoBrushSt !== isUiNoBrushSt || prevProps.isHidden !== isHidden || prevProps.cyclicvoltaSt !== cyclicvoltaSt || prevProps.integrationSt !== integrationSt || prevProps.mtplySt !== mtplySt || prevProps.axesUnitsSt !== axesUnitsSt || prevProps.uiSt !== uiSt || prevProps.cLabel !== cLabel || prevProps.xLabel !== xLabel || prevProps.yLabel !== yLabel; + if (!hasRelevantChange) return; + const { + xxLabel, + yyLabel + } = this.resolveAxisLabels(this.props); this.focus.update({ entities, curveSt, - filterSeed, - filterPeak, + filterSeed: seed, + filterPeak: peak, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, + isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, shiftSt, - integationSt, - mtplySt + integrationSt, + mtplySt, + uiSt }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); - (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden); + (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden || !_format.default.isAIFLayout(layoutSt)); } componentWillUnmount() { (0, _draw.drawDestroy)(this.rootKlass); @@ -225,7 +145,7 @@ class ViewerMulti extends _react.default.Component { 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); + this.mountChart(this.props, false); } } getContainerSize() { @@ -257,12 +177,69 @@ class ViewerMulti extends _react.default.Component { this.resizeObserver = new ResizeObserver(this.handleResize); 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(); this.resizeObserver = null; } } + resolveAxisLabels(props) { + const { + curveSt, + xLabel, + yLabel, + axesUnitsSt, + cyclicvoltaSt + } = props; + let xxLabel = xLabel; + let yyLabel = yLabel; + if (axesUnitsSt) { + const { + curveIdx + } = curveSt; + const { + axes + } = axesUnitsSt; + const selectedAxes = axes[curveIdx] || { + 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}`; + } + return { + xxLabel, + yyLabel + }; + } normChange(prevProps) { const { feature, @@ -275,32 +252,51 @@ class ViewerMulti extends _react.default.Component { resetAllAct(buildResetPayload(feature, curveSt)); } } - renderChart(props, shouldReset) { + createMultiFocus(size, props) { + const { + entities, + clickUiTargetAct, + selectUiSweepAct, + scrollUiWheelAct, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct + } = props; + return new _multi_focus.default({ + W: size.width, + H: size.height, + entities, + clickUiTargetAct, + selectUiSweepAct, + scrollUiWheelAct, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct + }); + } + mountChart(props, shouldReset = false) { const { curveSt, seed, peak, cLabel, - xLabel, - yLabel, feature, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, + isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, isHidden, resetAllAct, cyclicvoltaSt, shiftSt, - integationSt, + integrationSt, mtplySt, - axesUnitsSt, - entities, - clickUiTargetAct, - selectUiSweepAct, - scrollUiWheelAct + uiSt } = props; const size = this.getTargetSize(layoutSt); this.currentSize = size; @@ -308,58 +304,35 @@ class ViewerMulti extends _react.default.Component { if (shouldReset && !canSkipReset(sweepExtentSt, layoutSt, feature)) { resetAllAct(buildResetPayload(feature, curveSt)); } - 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 - }); + const { + xxLabel, + yyLabel + } = this.resolveAxisLabels(props); + this.focus = this.createMultiFocus(size, props); + this.syncFocusActions(); (0, _draw.drawMain)(this.rootKlass, size.width, size.height); this.focus.create({ curveSt, - filterSeed, - filterPeak, + filterSeed: seed, + filterPeak: peak, tTrEndPts, tSfPeaks, editPeakSt, layoutSt, sweepExtentSt, + isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, shiftSt, - integationSt, - mtplySt + integrationSt, + mtplySt, + uiSt }); (0, _draw.drawLabel)(this.rootKlass, cLabel, xxLabel, yyLabel); (0, _draw.drawDisplay)(this.rootKlass, isHidden); - (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden); + (0, _draw.drawArrowOnCurve)(this.rootKlass, isHidden || !_format.default.isAIFLayout(layoutSt)); } render() { const { @@ -367,7 +340,7 @@ class ViewerMulti extends _react.default.Component { } = this.props; const isCyclicVolta = _format.default.isCyclicVoltaLayout(layoutSt); return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { - className: "d3Line", + className: _list_graph.LIST_ROOT_SVG_GRAPH.LINE, ref: this.containerRef, style: isCyclicVolta ? { height: '100%' @@ -377,6 +350,7 @@ class ViewerMulti extends _react.default.Component { } const mapStateToProps = (state, props) => ({ curveSt: state.curve, + uiSt: state.ui, seed: (0, _chem.Topic2Seed)(state, props), peak: (0, _chem.Feature2Peak)(state, props), tTrEndPts: (0, _chem.ToThresEndPts)(state, props), @@ -384,11 +358,14 @@ const mapStateToProps = (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: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_SPLIT, + isUiVisualSplitIntgSt: _cfg.default.showIntegSplitTools(state.layout) && state.ui.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_VISUAL_SPLIT, isUiNoBrushSt: _list_ui.LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0, cyclicvoltaSt: state.cyclicvolta, shiftSt: state.shift, maxminPeakSt: (0, _chem.Feature2MaxMinPeak)(state, props), - integationSt: state.integration.present, + integrationSt: state.integration.present, mtplySt: state.multiplicity.present, axesUnitsSt: state.axesUnits }); @@ -397,12 +374,16 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ clickUiTargetAct: _ui.clickUiTarget, selectUiSweepAct: _ui.selectUiSweep, scrollUiWheelAct: _ui.scrollUiWheel, + splitIntegrationAct: _integration.splitIntegration, + addVisualSplitLineAct: _integration.addVisualSplitLine, + removeVisualSplitLineAct: _integration.removeVisualSplitLine, addNewCylicVoltaPairPeakAct: _cyclic_voltammetry.addNewCylicVoltaPairPeak, addCylicVoltaMaxPeakAct: _cyclic_voltammetry.addCylicVoltaMaxPeak, addCylicVoltaMinPeakAct: _cyclic_voltammetry.addCylicVoltaMinPeak }, dispatch); ViewerMulti.propTypes = { curveSt: _propTypes.default.object.isRequired, + uiSt: _propTypes.default.object.isRequired, entities: _propTypes.default.array.isRequired, seed: _propTypes.default.array.isRequired, peak: _propTypes.default.array.isRequired, @@ -413,14 +394,20 @@ ViewerMulti.propTypes = { tSfPeaks: _propTypes.default.array.isRequired, editPeakSt: _propTypes.default.object.isRequired, layoutSt: _propTypes.default.string.isRequired, - integationSt: _propTypes.default.object.isRequired, + integrationSt: _propTypes.default.object.isRequired, mtplySt: _propTypes.default.object.isRequired, sweepExtentSt: _propTypes.default.object.isRequired, + isUiAddIntgSt: _propTypes.default.bool.isRequired, + isUiSplitIntgSt: _propTypes.default.bool.isRequired, + isUiVisualSplitIntgSt: _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, + addVisualSplitLineAct: _propTypes.default.func.isRequired, + removeVisualSplitLineAct: _propTypes.default.func.isRequired, isHidden: _propTypes.default.bool, cyclicvoltaSt: _propTypes.default.object.isRequired, shiftSt: _propTypes.default.object.isRequired, diff --git a/dist/components/d3_multi/multi_focus.js b/dist/components/d3_multi/multi_focus.js index f229f8ab..b6d54581 100644 --- a/dist/components/d3_multi/multi_focus.js +++ b/dist/components/d3_multi/multi_focus.js @@ -10,6 +10,8 @@ var _mount = require("../../helpers/mount"); var _converter = require("../../helpers/converter"); var _brush = _interopRequireDefault(require("../../helpers/brush")); var _compass = require("../../helpers/compass"); +var _integration_focus = require("../../helpers/integration_focus"); +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"); @@ -18,7 +20,6 @@ var _cfg = _interopRequireDefault(require("../../helpers/cfg")); var _focus = require("../../helpers/focus"); var _integration = require("../../helpers/integration"); var _multiplicity_calc = require("../../helpers/multiplicity_calc"); -var _calc = require("../../helpers/calc"); /* eslint-disable no-unused-vars, prefer-object-spread, no-mixed-operators, no-unneeded-ternary, arrow-body-style, max-len */ @@ -31,8 +32,14 @@ class MultiFocus { clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, - entities + entities, + uiSt, + splitIntegrationAct, + addVisualSplitLineAct, + removeVisualSplitLineAct } = props; + this.uiSt = uiSt; + this.graphIndex = uiSt?.zoom?.graphIndex; this.entities = entities; this.jcampIdx = 0; this.isShowAllCurves = false; @@ -48,6 +55,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(); this.axis = null; @@ -74,6 +84,11 @@ class MultiFocus { this.shouldUpdate = {}; // this.freq = false; this.layout = _list_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); this.setTip = this.setTip.bind(this); @@ -91,6 +106,10 @@ 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.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); @@ -121,7 +140,7 @@ class MultiFocus { 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 sameSfPk = prevSfPk === this.tSfPeaks || Array.isArray(prevSfPk) && Array.isArray(this.tSfPeaks) && prevSfPk.length === this.tSfPeaks.length && prevSfPk.every((peak, idx) => peak === this.tSfPeaks[idx]); const sameData = prevData === this.data.length; const sameYFactor = prevYFactor === this.yTransformFactor; const sameJcampIdx = prevJcampIdx === this.jcampIdx; @@ -304,6 +323,8 @@ class MultiFocus { this.path.style('stroke', this.pathColor); if (this.layout === _list_layout.LIST_LAYOUT.AIF) { this.path.attr('marker-mid', 'url(#arrow-left)'); + } else { + this.path.attr('marker-mid', null); } } drawThres() { @@ -336,6 +357,8 @@ class MultiFocus { path.attr('d', this.pathCall(data)); if (this.layout === _list_layout.LIST_LAYOUT.AIF && this.isShowAllCurves === true) { path.attr('marker-mid', 'url(#arrow-left)'); + } else { + path.attr('marker-mid', null); } }); return null; @@ -364,6 +387,23 @@ class MultiFocus { this.clickUiTargetAct(data, onPeak, false, this.jcampIdx); } } + clearSplitPreview() { + (0, _integration_split.clearIntegrationSplitPreview)(this); + } + onIntegrationMouseMove(event, data, shift, ignoreRef) { + (0, _integration_focus.handleIntegrationMouseMove)(this, event, data, shift, ignoreRef); + } + onClickIntegrationTarget(event, data) { + (0, _integration_focus.handleIntegrationClick)(this, event, data, (clickEvent, clickData) => { + this.onClickTarget(clickEvent, clickData); + }); + } + drawVisualSplitLines(stack, shift, ignoreRef) { + (0, _integration_focus.drawVisualSplitLinesForFocus)(this, stack, shift, ignoreRef); + } + drawAUC(stack, shift = 0) { + (0, _integration_focus.drawIntegrationAUC)(this, stack, shift); + } onClickPecker(event, data) { event.stopPropagation(); event.preventDefault(); @@ -402,44 +442,6 @@ class MultiFocus { } return this.dataPeckers; } - drawAUC(stack) { - 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 = this.data.filter(d => d.x > xL && d.x < xU); - if (!ps[0]) return null; - const point1 = ps[0]; - const point2 = ps[ps.length - 1]; - const slope = (0, _calc.calcSlope)(point1.x, point1.y, point2.x, point2.y); - let lastDY = point1.y; - 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); - }).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); - }).on('click', (event, d) => this.onClickTarget(event, d)); - } drawPeaks(editPeakSt) { const { sameXY, @@ -603,7 +605,7 @@ class MultiFocus { this.tip.hide(tipParams, event.target); }).on('click', (event, d) => this.onClickPecker(event, d)); } - drawInteg(integationSt) { + drawInteg(integrationState) { const { sameXY, sameLySt, @@ -627,7 +629,7 @@ class MultiFocus { }; const { integrations - } = integationSt; + } = integrationState; const selectedIntegration = integrations[this.jcampIdx]; if (selectedIntegration === false || selectedIntegration === undefined) { clearIntegralPaths(); @@ -643,9 +645,20 @@ class MultiFocus { const isDisable = _cfg.default.btnCmdIntg(this.layout); const ignoreRef = _format.default.isHplcUvVisLayout(this.layout); const itgs = isDisable ? [] : stack; - const igbp = this.tags.igbPath.selectAll('path').data(itgs); + const { + showIntegSplit, + igBarData + } = (0, _integration_focus.buildIntegrationBarData)(this.layout, itgs); + Object.assign(this, { + integrationSplitTargets: { + stack: itgs, + shift, + ignoreRef + } + }); + const igbp = this.tags.igbPath.selectAll('path').data(igBarData); igbp.exit().attr('class', 'exit').remove(); - const igcp = this.tags.igcPath.selectAll('path').data(itgs); + const igcp = this.tags.igcPath.selectAll('path').data(igBarData); igcp.exit().attr('class', 'exit').remove(); const igtp = this.tags.igtPath.selectAll('text').data(itgs); igtp.exit().attr('class', 'exit').remove(); @@ -656,7 +669,7 @@ class MultiFocus { } if (ignoreRef) { clearIntegralPaths(); - this.drawAUC(stack); + this.drawAUC(stack, shift); } else { clearAUC(); // rescale for zoom @@ -673,7 +686,8 @@ class MultiFocus { 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'); - }).on('click', (event, d) => this.onClickTarget(event, d)); + if (showIntegSplit) this.clearSplitPreview(); + }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); const integCurve = border => { const { xL, @@ -697,7 +711,8 @@ class MultiFocus { 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'); - }).on('click', (event, d) => this.onClickTarget(event, d)); + if (showIntegSplit) this.clearSplitPreview(); + }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).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'); @@ -706,8 +721,10 @@ class MultiFocus { 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'); - }).on('click', (event, d) => this.onClickTarget(event, d)); + if (showIntegSplit) this.clearSplitPreview(); + }).on('mousemove', showIntegSplit ? (event, d) => this.onIntegrationMouseMove(event, d, shift, ignoreRef) : null).on('click', (event, d) => this.onClickIntegrationTarget(event, d)); } + this.drawVisualSplitLines(showIntegSplit ? itgs : [], shift, ignoreRef); } drawMtply(mtplySt) { const { @@ -726,6 +743,9 @@ class MultiFocus { const mpys = hasMpy ? selectedMulti.stack : []; const smExtext = hasMpy ? selectedMulti.smExtext : false; const shift = hasMpy ? selectedMulti.shift : 0; + const hasValidExtent = extent => extent && Number.isFinite(extent.xL) && Number.isFinite(extent.xU); + if (mpys.length === 0 || isDisable) return; + const activeExtent = hasValidExtent(smExtext) ? smExtext : mpys[0].xExtent; // rescale for zoom const { xt @@ -741,7 +761,8 @@ class MultiFocus { peaks, xExtent } = m; - return peaks.map(p => Object.assign({}, p, { + const safePeaks = Array.isArray(peaks) ? peaks : []; + return safePeaks.filter(p => Number.isFinite(p?.x) && Number.isFinite(p?.y)).map(p => Object.assign({}, p, { xExtent })); }); @@ -756,7 +777,7 @@ class MultiFocus { xL, xU } = d.xExtent; - return smExtext.xL === xL && smExtext.xU === xU ? 'purple' : '#DA70D6'; + return activeExtent.xL === xL && activeExtent.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'); @@ -860,12 +881,18 @@ class MultiFocus { editPeakSt, layoutSt, sweepExtentSt, + isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, shiftSt, - integationSt, - mtplySt + integrationSt, + mtplySt, + uiSt }) { + this.uiSt = uiSt; + this.graphIndex = uiSt?.zoom?.graphIndex; this.svg = d3.select(this.rootKlass).select('.d3Svg'); (0, _mount.MountMainFrame)(this, 'focus'); (0, _mount.MountClip)(this); @@ -879,6 +906,11 @@ class MultiFocus { this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt)); this.setTip(); this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, shiftSt, jcampIdx); + Object.assign(this, { + isUiSplitIntgSt, + isUiVisualSplitIntgSt + }); + if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview(); (0, _compass.MountCompass)(this); this.axis = (0, _mount.MountAxis)(this); this.path = (0, _mount.MountPath)(this, this.pathColor); @@ -897,10 +929,10 @@ class MultiFocus { this.drawPeaks(editPeakSt); this.drawRef(); this.drawPeckers(); - this.drawInteg(integationSt); + this.drawInteg(integrationSt); this.drawMtply(mtplySt); } - (0, _brush.default)(this, false, isUiNoBrushSt); + (0, _brush.default)(this, isUiAddIntgSt, isUiNoBrushSt); this.resetShouldUpdate(editPeakSt); } update({ @@ -913,14 +945,20 @@ class MultiFocus { editPeakSt, layoutSt, sweepExtentSt, + isUiAddIntgSt, + isUiSplitIntgSt, + isUiVisualSplitIntgSt, isUiNoBrushSt, cyclicvoltaSt, shiftSt, - integationSt, - mtplySt + integrationSt, + mtplySt, + uiSt }) { + this.uiSt = uiSt; this.root = d3.select(this.rootKlass).selectAll('.focus-main'); this.scales = (0, _init.InitScale)(this, this.reverseXAxis(layoutSt)); + this.graphIndex = uiSt?.zoom?.graphIndex; const { curveIdx, isShowAllCurve @@ -929,6 +967,11 @@ class MultiFocus { this.isShowAllCurves = isShowAllCurve; this.entities = entities; this.setDataParams(filterSeed, filterPeak, tTrEndPts, tSfPeaks, layoutSt, cyclicvoltaSt, shiftSt, jcampIdx); + Object.assign(this, { + isUiSplitIntgSt, + isUiVisualSplitIntgSt + }); + if (!isUiSplitIntgSt && !isUiVisualSplitIntgSt) this.clearSplitPreview(); if (this.data && this.data.length > 0) { this.setConfig(sweepExtentSt); this.getShouldUpdate(editPeakSt); @@ -939,10 +982,10 @@ class MultiFocus { this.drawPeaks(editPeakSt); this.drawRef(); this.drawPeckers(); - this.drawInteg(integationSt); + this.drawInteg(integrationSt); this.drawMtply(mtplySt); } - (0, _brush.default)(this, false, isUiNoBrushSt); + (0, _brush.default)(this, false, isUiNoBrushSt, this.uiSt, this.graphIndex); this.resetShouldUpdate(editPeakSt); } } diff --git a/dist/components/multi_jcamps_viewer.js b/dist/components/multi_jcamps_viewer.js index 68e39783..0cd897f7 100644 --- a/dist/components/multi_jcamps_viewer.js +++ b/dist/components/multi_jcamps_viewer.js @@ -97,7 +97,9 @@ class MultiJcampsViewer extends _react.default.Component { integrationSt, descriptions, canChangeDescription, - onDescriptionChanged + onDescriptionChanged, + forecast, + editorOnly } = this.props; if (!entities || entities.length === 0) return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {}); const separateCondition = _format.default.isGCLayout(layoutSt) ? 'yUnit' : 'xUnit'; @@ -114,14 +116,19 @@ class MultiJcampsViewer extends _react.default.Component { integrations } = integrationSt; const currentIntegration = integrations[curveIdx]; + const hasEdit = !!feature?.data?.[0]?.x?.length; + const xLabel = feature?.xUnit || ''; + const yLabel = feature?.yUnit || ''; const isCyclicVolta = _format.default.isCyclicVoltaLayout(layoutSt); return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: classes.root, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.default, { feature: feature, - hasEdit: entity.hasEdit, + hasEdit: hasEdit, + forecast: forecast || {}, operations: operations, - editorOnly: true + editorOnly: editorOnly, + 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, { @@ -136,8 +143,8 @@ class MultiJcampsViewer extends _react.default.Component { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.default, { entities: entities, topic: topic, - xLabel: feature.xUnit, - yLabel: feature.yUnit, + xLabel: xLabel, + yLabel: yLabel, feature: feature }) }), isCyclicVolta ? /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { @@ -162,6 +169,7 @@ class MultiJcampsViewer extends _react.default.Component { subLayoutsInfo: seperatedSubLayouts, integration: currentIntegration, descriptions: descriptions, + editorOnly: editorOnly, canChangeDescription: canChangeDescription, onDescriptionChanged: onDescriptionChanged, hideCyclicVolta: isCyclicVolta @@ -199,7 +207,9 @@ MultiJcampsViewer.propTypes = { addNewCylicVoltaPairPeakAct: _propTypes.default.func.isRequired, addCylicVoltaMaxPeakAct: _propTypes.default.func.isRequired, addCylicVoltaMinPeakAct: _propTypes.default.func.isRequired, - operations: _propTypes.default.func.isRequired, + operations: _propTypes.default.array.isRequired, + forecast: _propTypes.default.object, + editorOnly: _propTypes.default.bool, userManualLink: _propTypes.default.object, entities: _propTypes.default.array, layoutSt: _propTypes.default.string.isRequired, @@ -217,6 +227,8 @@ MultiJcampsViewer.defaultProps = { xLabel: '', yLabel: '', entities: [], + forecast: {}, + editorOnly: false, descriptions: [], canChangeDescription: false }; diff --git a/dist/components/panel/compare.js b/dist/components/panel/compare.js index 391903d6..82949ccc 100644 --- a/dist/components/panel/compare.js +++ b/dist/components/panel/compare.js @@ -10,7 +10,6 @@ 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")); @@ -130,38 +129,35 @@ const content = (classes, desc) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.T 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 inputOthers = (classes, desc, onDropFiles, onFileChange, inputRef) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { + className: (0, _classnames.default)(classes.baseDD), + role: "button", + tabIndex: 0, + onClick: () => inputRef.current?.click(), + onKeyDown: event => { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + inputRef.current?.click(); + } + }, + onDragOver: event => { + event.preventDefault(); + }, + onDrop: event => { + event.preventDefault(); + onDropFiles(event.dataTransfer?.files); + }, + children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("input", { + ref: inputRef, + type: "file", + multiple: true, + accept: ".dx,.jdx,.jcamp,.JCAMP", + style: { + display: 'none' + }, + onChange: onFileChange + }), content(classes, desc)] +}); const compareList = (classes, jcampSt, rmOthersOneAct, toggleShowAct) => { const { selectedIdx, @@ -221,37 +217,63 @@ const ComparePanel = ({ 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' +}) => { + const inputRef = _react.default.useRef(null); + const { + selectedIdx, + jcamps + } = jcampSt; + const selectedJcamp = jcamps[selectedIdx]; + const { + addOthersCb + } = selectedJcamp; + const desc = msgDefault; + const onDropFiles = filesLike => { + if (!addOthersCb) return; + const droppedFiles = Array.from(filesLike || []); + if (droppedFiles.length === 0) return; + addOthersCb({ + jcamps: droppedFiles + }); + }; + const onFileChange = event => { + onDropFiles(event.target.files); + if (inputRef.current) { + inputRef.current.value = ''; } - }, - 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" + }; + 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: "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) - })] -}); + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), inputOthers(classes, desc, onDropFiles, onFileChange, inputRef), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { + className: (0, _classnames.default)(classes.panelDetail), + children: compareList(classes, jcampSt, rmOthersOneAct, toggleShowAct) + })] + }); +}; const mapStateToProps = (state, props) => ( // eslint-disable-line { diff --git a/dist/components/panel/cyclic_voltamery_data.js b/dist/components/panel/cyclic_voltamery_data.js index 9024bda0..96718fd8 100644 --- a/dist/components/panel/cyclic_voltamery_data.js +++ b/dist/components/panel/cyclic_voltamery_data.js @@ -146,7 +146,7 @@ const styles = () => ({ }); const CyclicVoltammetryPanel = ({ classes, - cyclicVotaSt, + cyclicVoltaState, feature, addNewPairPeakAct, setWorkWithMaxPeakAct, @@ -161,18 +161,18 @@ const CyclicVoltammetryPanel = ({ const [isExpanded, setIsExpanded] = (0, _react.useState)(false); const { spectraList - } = cyclicVotaSt; + } = cyclicVoltaState; const spectra = spectraList[jcampIdx]; let list = []; if (spectra !== undefined) { list = spectra.list; } - const formatCurrent = (y, feature, cyclicVotaSt) => { + const formatCurrent = (y, feature, cyclicVoltaState) => { 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 useDensity = cyclicVoltaState && cyclicVoltaState.useCurrentDensity; + const rawArea = (cyclicVoltaState && cyclicVoltaState.areaValue === '' ? 1.0 : cyclicVoltaState?.areaValue) || 1.0; + const areaUnit = cyclicVoltaState && cyclicVoltaState.areaUnit ? cyclicVoltaState.areaUnit : 'cm²'; const safeArea = rawArea > 0 ? rawArea : 1.0; let val = y; let unit = isMilli ? 'mA' : 'A'; @@ -226,9 +226,9 @@ const CyclicVoltammetryPanel = ({ }; 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', + max: o.max ? `E: ${_format.default.strNumberFixedLength(parseFloat(o.max.x), 3)} V,\nI: ${formatCurrent(o.max.y, feature, cyclicVoltaState)}` : 'nd', + min: o.min ? `E: ${_format.default.strNumberFixedLength(parseFloat(o.min.x), 3)} V,\nI: ${formatCurrent(o.min.y, feature, cyclicVoltaState)}` : 'nd', + pecker: o.pecker ? `${formatCurrent(o.pecker.y, feature, cyclicVoltaState)}` : 'nd', delta: `${getDelta(o)} mV`, ratio: getRatio(feature, o), e12: typeof o.e12 === 'number' ? `${_format.default.strNumberFixedLength(o.e12, 3)} V` : 'nd', @@ -262,7 +262,7 @@ const CyclicVoltammetryPanel = ({ 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'] + children: ["Mode: ", cyclicVoltaState.useCurrentDensity ? 'Current Density' : 'Current'] }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: classes.cvModeWarning, children: "WE-ECSA must be set when switching to Current Density." @@ -436,7 +436,7 @@ const CyclicVoltammetryPanel = ({ const mapStateToProps = (state, props) => ( // eslint-disable-line { - cyclicVotaSt: state.cyclicvolta, + cyclicVoltaState: state.cyclicvolta, sweepTypeSt: state.ui.sweepType }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ @@ -450,7 +450,7 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ CyclicVoltammetryPanel.propTypes = { classes: _propTypes.default.object.isRequired, feature: _propTypes.default.object.isRequired, - cyclicVotaSt: _propTypes.default.object.isRequired, + cyclicVoltaState: _propTypes.default.object.isRequired, addNewPairPeakAct: _propTypes.default.func.isRequired, setWorkWithMaxPeakAct: _propTypes.default.func.isRequired, selectPairPeakAct: _propTypes.default.func.isRequired, diff --git a/dist/components/panel/graph_selection.js b/dist/components/panel/graph_selection.js index 4a1536ce..7165b25e 100644 --- a/dist/components/panel/graph_selection.js +++ b/dist/components/panel/graph_selection.js @@ -97,10 +97,12 @@ const GraphSelectionPanel = ({ if (subLayoutsInfo) { subLayoutValues = Object.keys(subLayoutsInfo); } + const subLayoutKey = subLayoutValues.join('|'); const [selectedSubLayout, setSelectedSublayout] = (0, _react.useState)(subLayoutValues[0]); + const resolvedSelectedSubLayout = subLayoutValues.includes(selectedSubLayout) ? selectedSubLayout : subLayoutValues[0] || false; (0, _react.useEffect)(() => { setSelectedSublayout(subLayoutValues[0]); - }, subLayoutValues); + }, [subLayoutKey]); if (!curveSt) { return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {}); } @@ -123,9 +125,9 @@ const GraphSelectionPanel = ({ }; let itemsSubLayout = []; if (selectedSubLayout && subLayoutValues.length > 1) { - const subLayout = subLayoutsInfo[selectedSubLayout]; - if (subLayout) { - itemsSubLayout = subLayout.map((spectra, idx) => { + const subLayout = subLayoutsInfo?.[resolvedSelectedSubLayout]; + try { + itemsSubLayout = Array.isArray(subLayout) ? subLayout.map((spectra, idx) => { const spectraIdx = spectra.curveIdx; const { color @@ -136,7 +138,9 @@ const GraphSelectionPanel = ({ color, label: displayName(spectra, spectraIdx, entityFileNames) }; - }); + }) : []; + } catch (e) { + console.log(e); //eslint-disable-line } } const items = listCurves.map((spectra, idx) => { @@ -170,7 +174,7 @@ const GraphSelectionPanel = ({ className: "txt-panel-header", children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.txtBadge, 'txt-sv-panel-title'), - children: "Graph selection" + children: "Graph selections" }) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Divider, {}), layoutSt === _list_layout.LIST_LAYOUT.AIF ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControlLabel, { @@ -181,9 +185,9 @@ const GraphSelectionPanel = ({ label: "Show all curves" }) : null, subLayoutValues && subLayoutValues.length > 1 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tabs, { - value: selectedSubLayout, + value: resolvedSelectedSubLayout, onChange: onChangeTabSubLayout, - children: subLayoutValues.map((subLayout, i) => { + children: subLayoutValues.map(subLayout => { let subLayoutName = ''; switch (subLayout.toUpperCase()) { case 'G/MOL': @@ -204,7 +208,7 @@ const GraphSelectionPanel = ({ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tab, { value: subLayout, label: subLayoutName - }, i); + }, subLayout); }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.List, { children: itemsSubLayout.map(item => renderCurveItem(classes, item, curveIdx, onChange)) @@ -226,13 +230,17 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ }, dispatch); GraphSelectionPanel.propTypes = { classes: _propTypes.default.object.isRequired, - expand: _propTypes.default.bool.isRequired, + expand: _propTypes.default.bool, layoutSt: _propTypes.default.string.isRequired, - onExapnd: _propTypes.default.func.isRequired, + onExapnd: _propTypes.default.func, + onExpand: _propTypes.default.func, curveSt: _propTypes.default.object.isRequired, selectCurveAct: _propTypes.default.func.isRequired, - entityFileNames: _propTypes.default.array.isRequired, + entityFileNames: _propTypes.default.array, subLayoutsInfo: _propTypes.default.object, toggleShowAllCurveAct: _propTypes.default.func.isRequired }; +GraphSelectionPanel.defaultProps = { + entityFileNames: [] +}; 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 index 84b9eec7..9904b37e 100644 --- a/dist/components/panel/index.js +++ b/dist/components/panel/index.js @@ -9,7 +9,6 @@ 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")); @@ -19,8 +18,9 @@ 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 _format = _interopRequireDefault(require("../../helpers/format")); var _jsxRuntime = require("react/jsx-runtime"); -/* eslint-disable react/prop-types, react/require-default-props */ +/* eslint-disable react/prop-types, react/require-default-props, max-len */ const theme = (0, _styles.createTheme)({ typography: { @@ -50,7 +50,7 @@ class PanelViewer extends _react.default.Component { this.state = { expand: ['info', 'graph'] }; - this.onExapnd = this.onExapnd.bind(this); + this.onToggleExpand = this.onToggleExpand.bind(this); this.handleDescriptionChanged = this.handleDescriptionChanged.bind(this); } handleDescriptionChanged(content, delta, source, editor) { @@ -59,7 +59,7 @@ class PanelViewer extends _react.default.Component { this.props.onDescriptionChanged(contentChanged); // eslint-disable-line } } - onExapnd(input) { + onToggleExpand(input) { const { expand } = this.state; @@ -87,19 +87,21 @@ class PanelViewer extends _react.default.Component { userManualLink, subLayoutsInfo, exactMass, + entities, 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 onExpandInfo = () => this.onToggleExpand('info'); + const onExpandPeak = () => this.onToggleExpand('peak'); + const onExpandMpy = () => this.onToggleExpand('mpy'); + const onExpandCompare = () => this.onToggleExpand('compare'); + const onExpandCyclicVolta = () => this.onToggleExpand('cyclicvolta'); + const onExpandGraphSelection = () => this.onToggleExpand('graph'); const isExpanded = name => expand.includes(name); const { listCurves } = curveSt; - const hideGraphSelection = !Array.isArray(listCurves); + const curveCount = Array.isArray(listCurves) ? listCurves.length : 0; + const hideGraphSelection = curveCount <= 1 || _format.default.isLCMsLayout(layoutSt); return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: (0, _classnames.default)(classes.panels), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.StyledEngineProvider, { @@ -110,33 +112,34 @@ class PanelViewer extends _react.default.Component { jcampIdx: jcampIdx, entityFileNames: entityFileNames, expand: isExpanded('graph'), - onExapnd: onExapndGraphSelection, + onExapnd: onExpandGraphSelection, subLayoutsInfo: subLayoutsInfo }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_info.default, { + entities: entities, feature: feature, integration: integration, editorOnly: editorOnly, expand: isExpanded('info'), molSvg: molSvg, exactMass: exactMass, - onExapnd: onExapndInfo, + onExpand: onExpandInfo, descriptions: descriptions, canChangeDescription: canChangeDescription, onDescriptionChanged: this.handleDescriptionChanged }), _cfg.default.hidePanelPeak(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_peaks.default, { expand: isExpanded('peak'), - onExapnd: onExapndPeak + onExapnd: onExpandPeak }), _cfg.default.hidePanelMpy(layoutSt) ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_multiplicity.default, { expand: isExpanded('mpy'), - onExapnd: onExapndMpy + onExapnd: onExpandMpy }), _cfg.default.hidePanelCompare(layoutSt) || !listCurves || listCurves.length > 1 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_compare.default, { expand: isExpanded('compare'), - onExapnd: onExapndCompare + onExapnd: onExpandCompare }), _cfg.default.hidePanelCyclicVolta(layoutSt) || hideCyclicVolta ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(_cyclic_voltamery_data.default, { jcampIdx: jcampIdx, feature: feature, expand: isExpanded('cyclicvolta'), - onExapnd: onExapndCyclicVolta, + onExapnd: onExpandCyclicVolta, userManualLink: userManualLink ? userManualLink.cv : undefined })] }) @@ -150,11 +153,10 @@ const mapStateToProps = (state, _) => ( 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, + integration: _propTypes.default.object, editorOnly: _propTypes.default.bool.isRequired, molSvg: _propTypes.default.string.isRequired, descriptions: _propTypes.default.array.isRequired, @@ -166,8 +168,12 @@ PanelViewer.propTypes = { curveSt: _propTypes.default.object.isRequired, subLayoutsInfo: _propTypes.default.object, exactMass: _propTypes.default.string, - hideCyclicVolta: _propTypes.default.bool + hideCyclicVolta: _propTypes.default.bool, + entities: _propTypes.default.array +}; +PanelViewer.defaultProps = { + integration: {} }; 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 +mapStateToProps, null)((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 index 166dbcb6..72c13c62 100644 --- a/dist/components/panel/info.js +++ b/dist/components/panel/info.js @@ -232,8 +232,11 @@ const SECData = ({ SECData.propTypes = { classes: _propTypes.default.object.isRequired, layout: _propTypes.default.string.isRequired, - detector: _propTypes.default.object.isRequired, - secData: _propTypes.default.object.isRequired + detector: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]), + secData: _propTypes.default.object +}; +SECData.defaultProps = { + detector: '' }; const DSCData = ({ classes, @@ -291,7 +294,7 @@ const DSCData = ({ DSCData.propTypes = { classes: _propTypes.default.object.isRequired, layout: _propTypes.default.string.isRequired, - dscMetaData: _propTypes.default.object.isRequired, + dscMetaData: _propTypes.default.object, updateAction: _propTypes.default.func.isRequired }; const InfoPanel = ({ @@ -307,12 +310,14 @@ const InfoPanel = ({ shiftSt, curveSt, exactMass, - onExapnd, + onExpand, canChangeDescription, onDescriptionChanged, detectorSt, metaSt, - updateDSCMetaDataAct + updateDSCMetaDataAct, + hplcMsSt, + entities }) => { if (!feature) return null; const msExactMass = _format.default.isMsLayout(layoutSt) && exactMass ? formatMsExactMass(exactMass) : null; @@ -329,11 +334,14 @@ const InfoPanel = ({ curveIdx } = curveSt; const { - curves - } = detectorSt; + curves = [] + } = detectorSt || {}; + const currentEntity = Array.isArray(entities) ? entities[curveIdx] : null; + const entityTitle = currentEntity?.entity?.title || currentEntity?.title || currentEntity?.spectra?.[0]?.title || currentEntity?.entity?.spectra?.[0]?.title || ''; + const displayTitle = title || entityTitle; const getSelectedDetectorForCurve = (_detectorSt, targetCurveIdx) => { const targetCurve = curves.find(curve => curve.curveIdx === targetCurveIdx); - return targetCurve ? targetCurve.selectedDetector.name : ''; + return targetCurve?.selectedDetector?.name || ''; }; let selectedDetector = getSelectedDetectorForCurve(detectorSt, curveIdx); @@ -358,7 +366,7 @@ const InfoPanel = ({ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Accordion, { "data-testid": "PanelInfo", expanded: expand, - onChange: onExapnd, + onChange: onExpand, disableGutters: true, sx: { '&.MuiAccordion-root.Mui-expanded': { @@ -391,7 +399,7 @@ const InfoPanel = ({ children: "Title : " }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _classnames.default)(classes.tTxt, 'txt-sv-panel-txt'), - children: title + children: displayTitle })] }), _format.default.isNmrLayout(layoutSt) ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: (0, _classnames.default)(classes.rowRoot, classes.rowEven), @@ -472,7 +480,25 @@ const InfoPanel = ({ }) })] }) : null] - })] + }), _format.default.isLCMsLayout(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)("div", { + className: (0, _classnames.default)(classes.tTxt, classes.tTxtSim, 'txt-sv-panel-txt'), + style: { + maxHeight: '80px', + overflowY: 'auto', + overflowX: 'hidden', + wordBreak: 'break-word', + marginBottom: '100px' + }, + children: aucValue(integration, hplcMsSt).split('\n').map((line, idx) => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { + children: line + }, idx)) + })] + }) : null] }); }; const mapStateToProps = (state, props) => ( @@ -483,7 +509,8 @@ const mapStateToProps = (state, props) => ( shiftSt: state.shift, curveSt: state.curve, detectorSt: state.detector, - metaSt: state.meta + metaSt: state.meta, + hplcMsSt: state.hplcMs }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ updateDSCMetaDataAct: _meta.updateDSCMetaData @@ -491,22 +518,24 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ InfoPanel.propTypes = { classes: _propTypes.default.object.isRequired, expand: _propTypes.default.bool.isRequired, - feature: _propTypes.default.object.isRequired, - integration: _propTypes.default.object.isRequired, + feature: _propTypes.default.object, + integration: _propTypes.default.object, 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, + simulationSt: _propTypes.default.object.isRequired, shiftSt: _propTypes.default.object.isRequired, curveSt: _propTypes.default.object.isRequired, - onExapnd: _propTypes.default.func.isRequired, + onExpand: _propTypes.default.func, 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 + updateDSCMetaDataAct: _propTypes.default.func.isRequired, + hplcMsSt: _propTypes.default.object.isRequired, + entities: _propTypes.default.array }; var _default = exports.default = (0, _reactRedux.connect)( // eslint-disable-line diff --git a/dist/constants/action_type.js b/dist/constants/action_type.js index cee58bf1..ba7e4384 100644 --- a/dist/constants/action_type.js +++ b/dist/constants/action_type.js @@ -3,7 +3,7 @@ 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; +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.HPLC_MS = 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', @@ -56,6 +56,7 @@ const UI = exports.UI = { SET_TYPE: 'UI_SWEEP_SET_TYPE', SELECT: 'UI_SWEEP_SELECT', SELECT_ZOOMIN: 'UI_SWEEP_SELECT_ZOOMIN', + SELECT_ZOOMIN_SUBVIEW: 'UI_SWEEP_SELECT_ZOOMIN', SELECT_ZOOMRESET: 'UI_SWEEP_SELECT_ZOOMRESET', SELECT_INTEGRATION: 'UI_SWEEP_SELECT_INTEGRATION', SELECT_MULTIPLICITY: 'UI_SWEEP_SELECT_MULTIPLICITY', @@ -63,6 +64,9 @@ const UI = exports.UI = { }, WHEEL: { SCROLL: 'UI_WHEEL_SCROLL' + }, + SUB_VIEWER: { + DISPLAY_VIEWER_AT: 'DISPLAY_VIEWER_AT' } }; const FORECAST = exports.FORECAST = { @@ -83,7 +87,10 @@ const INTEGRATION = exports.INTEGRATION = { SET_FKR: 'INTEGRATION_SET_FKR', RESET_ALL_RDC: 'INTEGRATION_RESET_ALL_RDC', CLEAR_ALL: 'INTEGRATION_CLEAR_ALL', - SWEEP: 'INTEGRATION_SWEEP' + SWEEP: 'INTEGRATION_SWEEP', + SPLIT: 'INTEGRATION_SPLIT', + ADD_VISUAL_SPLIT: 'INTEGRATION_ADD_VISUAL_SPLIT', + RM_VISUAL_SPLIT: 'INTEGRATION_RM_VISUAL_SPLIT' }; const SIMULATION = exports.SIMULATION = { RESET_ALL_RDC: 'SIMULATION_RESET_ALL_RDC' @@ -150,4 +157,18 @@ const AXES = exports.AXES = { }; const SEC = exports.SEC = { UPDATE_DETECTOR: 'UPDATE_DETECTOR' +}; +const HPLC_MS = exports.HPLC_MS = { + SET_LCMS_INTEGRATIONS_EXPORT: 'HPLC_MS_SET_LCMS_INTEGRATIONS_EXPORT', + UPDATE_UVVIS_WAVE_LENGTH: 'UPDATE_UVVIS_WAVE_LENGTH', + SELECT_TIC_CURVE: 'SELECT_TIC_CURVE', + UPDATE_HPLCMS_INTEGRATIONS: 'UPDATE_HPLCMS_INTEGRATIONS', + UPDATE_CURRENT_PAGE_VALUE: 'UPDATE_CURRENT_PAGE_VALUE', + UVVIS_UNDO: 'HPLC_MS_UVVIS_UNDO', + UVVIS_REDO: 'HPLC_MS_UVVIS_REDO', + UPDATE_HPLCMS_PEAKS: 'UPDATE_HPLCMS_PEAKS', + REMOVE_HPLCMS_PEAK: 'REMOVE_HPLCMS_PEAK', + CLEAR_INTEGRATION_ALL_HPLCMS: 'CLEAR_INTEGRATION_ALL_HPLCMS', + CLEAR_ALL_PEAKS_HPLCMS: 'CLEAR_ALL_PEAKS_HPLCMS', + CLEAR_STATE: 'HPLC_MS_CLEAR_STATE' }; \ No newline at end of file diff --git a/dist/constants/list_layout.js b/dist/constants/list_layout.js index cf5830ed..829cb69f 100644 --- a/dist/constants/list_layout.js +++ b/dist/constants/list_layout.js @@ -27,5 +27,6 @@ const LIST_LAYOUT = exports.LIST_LAYOUT = { DLS_ACF: 'DLS ACF', DLS_INTENSITY: 'DLS intensity', DSC: 'DIFFERENTIAL SCANNING CALORIMETRY', - GC: 'GAS CHROMATOGRAPHY' + GC: 'GAS CHROMATOGRAPHY', + LC_MS: 'LC/MS' }; \ No newline at end of file diff --git a/dist/constants/list_ui.js b/dist/constants/list_ui.js index ad219334..6348a679 100644 --- a/dist/constants/list_ui.js +++ b/dist/constants/list_ui.js @@ -15,6 +15,8 @@ const LIST_UI_SWEEP_TYPE = exports.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', @@ -30,6 +32,7 @@ const LIST_UI_SWEEP_TYPE = exports.LIST_UI_SWEEP_TYPE = { 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' + CYCLIC_VOLTA_SET_REF: 'cyclic voltammetry set ref', + PEAK_GROUP_SELECT: 'peak group select' }; -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.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 +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.INTEGRATION_VISUAL_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, LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT]; \ No newline at end of file diff --git a/dist/fn.js b/dist/fn.js index 348a8fe8..3b4ece75 100644 --- a/dist/fn.js +++ b/dist/fn.js @@ -10,14 +10,17 @@ var _chem = require("./helpers/chem"); var _converter = require("./helpers/converter"); var _multiplicity_calc = require("./helpers/multiplicity_calc"); var _carbonFeatures = require("./helpers/carbonFeatures"); +var _integration_jcamp = require("./helpers/integration_jcamp"); var _list_layout = require("./constants/list_layout"); /* eslint-disable prefer-object-spread */ const FN = Object.assign({}, _format.default, { ExtractJcamp: _chem.ExtractJcamp, + buildLcmsMsPageJcamp: _chem.buildLcmsMsPageJcamp, ToXY: _converter.ToXY, LIST_LAYOUT: _list_layout.LIST_LAYOUT, CalcMpyCenter: _multiplicity_calc.calcMpyCenter, - CarbonFeatures: _carbonFeatures.carbonFeatures + CarbonFeatures: _carbonFeatures.carbonFeatures, + serializeIntegrationRecords: _integration_jcamp.serializeIntegrationRecords }); var _default = exports.default = FN; \ No newline at end of file diff --git a/dist/helpers/brush.js b/dist/helpers/brush.js index 309f49d7..d23a6946 100644 --- a/dist/helpers/brush.js +++ b/dist/helpers/brush.js @@ -1,31 +1,43 @@ "use strict"; +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); 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"); +var _list_ui = require("../constants/list_ui"); +var _cfg = _interopRequireDefault(require("./cfg")); /* eslint-disable prefer-object-spread */ +// eslint-disable-line import/extensions +// eslint-disable-line import/extensions + const d3 = require('d3'); const wheeled = (focus, event) => { const { currentExtent, - scrollUiWheelAct + scrollUiWheelAct, + brushClass } = 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 + direction, + brushClass })); }; -const brushed = (focus, isUiAddIntgSt, event) => { +const usesTwoClickIntegAdd = (focus, isUiAddIntgSt) => isUiAddIntgSt && _cfg.default.showIntegSplitTools(focus.layout); +const brushed = (focus, xOnly, event, brushedClass = '.d3Svg') => { const { selectUiSweepAct, data, dataPks, brush, + brushX, w, h, scales @@ -42,7 +54,15 @@ const brushed = (focus, isUiAddIntgSt, event) => { yL: yes[0], yU: yes[1] }; - if (isUiAddIntgSt) { + if (xOnly) { + if (focus.isUiAddIntgSt) { + const payload = (0, _sweep.buildSweepPayloadFromXBounds)(focus, scales.x.invert(selection[0]), scales.x.invert(selection[1])); + selectUiSweepAct(payload); + if (brushX) { + focus.svg.selectAll('.brushX').call(brushX.move, null); + } + return; + } xes = selection.map(scales.x.invert).sort((a, b) => a - b); xExtent = { xL: xes[0], @@ -67,34 +87,69 @@ const brushed = (focus, isUiAddIntgSt, event) => { data, dataPks }); - d3.select('.d3Svg').selectAll('.brush').call(brush.move, null); + let svgSel = null; + if (focus?.svg && typeof focus.svg.selectAll === 'function') { + svgSel = focus.svg; + } else if (typeof brushedClass === 'string') { + svgSel = d3.select(brushedClass); + } + if (svgSel && typeof svgSel.selectAll === 'function' && !svgSel.empty()) { + const brushSelection = xOnly ? svgSel.selectAll('.brushX') : svgSel.selectAll('.brush'); + if (!brushSelection.empty()) { + if (xOnly && brushX) { + brushSelection.call(brushX.move, null); + } else if (brush) { + brushSelection.call(brush.move, null); + } + } + } }; -const MountBrush = (focus, isUiAddIntgSt, isUiNoBrushSt) => { +const MountBrush = (focus, isUiAddIntgSt, isUiNoBrushSt, brushedClass = '.d3Svg') => { const { root, svg, brush, brushX, w, - h + h, + uiSt, + graphIndex } = focus; - svg.selectAll('.brush').remove(); - svg.selectAll('.brushX').remove(); - const brushedCb = event => brushed(focus, isUiAddIntgSt, event); + Object.assign(focus, { + isUiAddIntgSt + }); + const twoClickIntegAdd = usesTwoClickIntegAdd(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); + } + if (!root || !svg || typeof svg.selectAll !== 'function') return; + svg.selectAll('.brush, .brushX').remove(); + const isZoomInSubview = uiSt?.zoom?.sweepTypes?.[graphIndex] === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN; + const isZoomInGlobal = uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN; + const isIntegrationAdd = uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.INTEGRATION_ADD; + const isMultiplicitySweepAdd = uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_SWEEP_ADD; + const isZoomIn = isZoomInSubview || isZoomInGlobal; + if (graphIndex !== undefined && !(graphIndex === 0 && isIntegrationAdd) && !isZoomIn && !isMultiplicitySweepAdd) return; + const isXAxisOnly = focus?.xOnlyBrush === true; + const xOnly = isUiAddIntgSt || isXAxisOnly && !isZoomIn; + const brushedCb = event => brushed(focus, xOnly, event, brushedClass); const wheeledCb = event => wheeled(focus, event); - if (isUiNoBrushSt) { + if (isUiNoBrushSt && !twoClickIntegAdd) { const target = isUiAddIntgSt ? brushX : brush; target.handleSize(10).extent([[0, 0], [w, h]]).on('end', brushedCb); - - // append brush components const klass = isUiAddIntgSt ? 'brushX' : 'brush'; root.append('g').attr('class', klass).on('mousemove', event => (0, _compass.MouseMove)(event, focus)).call(target); } svg.on('wheel', wheeledCb); }; -var _default = exports.default = MountBrush; // const resetedCb = () => reseted(main); -// main.svg.on('dblclick', resetedCb); -// const reseted = (main) => { -// const { selectUiSweepAct } = main; -// selectUiSweepAct({ xExtent: false, yExtent: false }); -// }; \ No newline at end of file +var _default = exports.default = MountBrush; \ No newline at end of file diff --git a/dist/helpers/calc.js b/dist/helpers/calc.js index 664ffdf8..ed9fe07a 100644 --- a/dist/helpers/calc.js +++ b/dist/helpers/calc.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.calcSlope = exports.almostEqual = void 0; +exports.findClosest = 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) => { @@ -12,4 +12,6 @@ const calcSlope = (x1, y1, x2, y2) => { } return (y2 - y1) / (x2 - x1); }; -exports.calcSlope = calcSlope; \ No newline at end of file +exports.calcSlope = calcSlope; +const findClosest = (arr, target) => arr.reduce((prev, curr) => Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev); // eslint-disable-line +exports.findClosest = findClosest; \ No newline at end of file diff --git a/dist/helpers/cfg.js b/dist/helpers/cfg.js index 4cc3b51c..b8754dcc 100644 --- a/dist/helpers/cfg.js +++ b/dist/helpers/cfg.js @@ -6,14 +6,14 @@ Object.defineProperty(exports, "__esModule", { }); 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 btnCmdAnaViewer = layoutSt => _format.default.isMsLayout(layoutSt) || _format.default.isLCMsLayout(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 btnCmdSetRef = layoutSt => !_format.default.isNmrLayout(layoutSt); +const btnCmdIntg = layoutSt => !(_format.default.isNmrLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt) || _format.default.isLCMsLayout(layoutSt)); // eslint-disable-line +const showIntegSplitTools = layoutSt => _format.default.isHplcUvVisLayout(layoutSt); const btnCmdMpy = layoutSt => !_format.default.isNmrLayout(layoutSt); const btnCmdMpyPeak = (layoutSt, mpySt, curveIdx = 0) => { const { @@ -50,6 +50,7 @@ const Config = { btnCmdRmPeak, btnCmdSetRef, btnCmdIntg, + showIntegSplitTools, btnCmdMpy, btnCmdMpyPeak, hideCmdThres, diff --git a/dist/helpers/chem.js b/dist/helpers/chem.js index 77eb83ef..acae5ec5 100644 --- a/dist/helpers/chem.js +++ b/dist/helpers/chem.js @@ -4,7 +4,14 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau 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; +exports.buildIntegFeature = 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; +Object.defineProperty(exports, "buildLcmsMsPageJcamp", { + enumerable: true, + get: function get() { + return _parsing.buildLcmsMsPageJcamp; + } +}); +exports.convertTopic = exports.convertThresEndPts = void 0; var _jcampconverter = _interopRequireDefault(require("jcampconverter")); var _reselect = require("reselect"); var _shift = require("./shift"); @@ -12,11 +19,13 @@ var _cfg = _interopRequireDefault(require("./cfg")); var _format = _interopRequireDefault(require("./format")); var _list_layout = require("../constants/list_layout"); var _integration = require("./integration"); +var _parsing = require("../features/lc-ms/parsing"); /* eslint-disable no-mixed-operators, react/function-component-definition, prefer-object-spread, camelcase, no-plusplus, prefer-destructuring, max-len */ +const canIntegrate = layoutSt => !(_format.default.isNmrLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt) || _format.default.isLCMsLayout(layoutSt)); const getTopic = (_, props) => props.topic; const getFeature = (_, props) => props.feature; const getLayout = (state, _) => state.layout; // eslint-disable-line @@ -90,12 +99,13 @@ const calcXY = (xs, ys, maxY, offset) => { return sp; }; const convertTopic = (topic, layout, feature, offset) => { + if (!feature || !topic) return []; const { maxY - } = feature; - const xs = topic.x; - const ys = topic.y; - const isItgDisable = _cfg.default.btnCmdIntg(layout); + } = feature || {}; + const xs = topic.x || []; + const ys = topic.y || []; + const isItgDisable = canIntegrate(layout); if (!isItgDisable) return calcXYK(xs, ys, maxY, offset); return calcXY(xs, ys, maxY, offset); }; @@ -140,7 +150,7 @@ const convertComparisons = (layout, comparisons, feature) => { }; 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; + if (!_format.default.isNmrLayout(layout)) return false; const { observeFrequency } = feature; @@ -150,6 +160,27 @@ const convertFrequency = (layout, feature) => { 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) => { + if (feature?.operation?.layout === 'LC/MS') { + const data = feature.data[0]; + if (!data) return []; + const { + x, + y + } = data; + const peaks = []; + const maxIntensity = Math.max(...y); + const thresholdValue = threshold || 0; + for (let i = 1; i < y.length - 1; i++) { + const intensity = y[i] / maxIntensity * 100; + if (intensity >= thresholdValue && y[i] > y[i - 1] && y[i] > y[i + 1]) { + peaks.push({ + x: x[i], + y: y[i] + }); + } + } + return peaks; + } const peak = []; if (!feature || !feature.data) return peak; const data = feature.data[0]; @@ -165,8 +196,12 @@ const Convert2Peak = (feature, threshold, offset, upThreshold = false, lowThresh const { layout } = operation; - - // if (!Format.isSECLayout(layout) && (upperThres || lowerThres)) { + if (_format.default.isLCMsLayout(layout) && feature.peaks) { + return feature.peaks.map(p => ({ + x: p.x - (offset || 0), + y: p.y + })); + } if ((_format.default.isCyclicVoltaLayout(layout) || _format.default.isCDSLayout(layout)) && (upperThres || lowerThres)) { let upperThresVal = upThreshold || upperThres; if (!upperThresVal) { @@ -277,6 +312,7 @@ const convertThresEndPts = (feature, threshold) => { }]; return endPts; }; +exports.convertThresEndPts = convertThresEndPts; const ToThresEndPts = exports.ToThresEndPts = (0, _reselect.createSelector)(getFeature, getThreshold, convertThresEndPts); const getShiftPeak = state => { const { @@ -308,14 +344,20 @@ const ToShiftPeaks = exports.ToShiftPeaks = (0, _reselect.createSelector)(getShi // ExtractJcamp // - - - - - - - - - - - - - - - - - - - - - - const readLayout = jcamp => { + if (jcamp.dataType?.toUpperCase?.() === 'LC/MS') { + return _list_layout.LIST_LAYOUT.LC_MS; + } const { xType, spectra } = jcamp; if (xType && _format.default.isNmrLayout(xType)) return xType; + if (!spectra || !Array.isArray(spectra) || spectra.length === 0) { + return false; + } const { dataType - } = spectra[0]; + } = spectra[0] || {}; if (dataType) { if (dataType.includes('INFRARED SPECTRUM')) { return _list_layout.LIST_LAYOUT.IR; @@ -365,6 +407,9 @@ const readLayout = jcamp => { if (dataType.includes('DLS intensity')) { return _list_layout.LIST_LAYOUT.DLS_INTENSITY; } + if (dataType.includes('LC/MS')) { + return _list_layout.LIST_LAYOUT.LC_MS; + } } return false; }; @@ -372,30 +417,217 @@ 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(','); + const csCategories = [].concat(jcamp?.info?.$CSCATEGORY || []).map(c => String(c).toUpperCase()); + const hasUvvisCategory = csCategories.some(c => c.includes('UVVIS')); + const hasUvvisDataType = jcamp?.spectra?.some(s => { + const dt = String(s?.dataType || '').toUpperCase(); + return dt.includes('UV-VIS') || dt.includes('UVVIS') || dt.includes('HPLC UV'); + }); + const jcampDataType = String(jcamp?.dataType || '').toUpperCase(); + const hasUvvisJcampDataType = jcampDataType.includes('UV-VIS') || jcampDataType.includes('UVVIS') || jcampDataType.includes('HPLC UV'); + const isUvvisData = hasUvvisCategory || hasUvvisDataType || hasUvvisJcampDataType; + const hasTicCategory = csCategories.some(c => c.includes('TIC')); + const hasTicDataType = jcamp?.spectra?.some(s => { + const dt = String(s?.dataType || '').toUpperCase(); + return dt.includes('MASS TIC') || dt.includes('TIC'); + }); + const hasTicJcampDataType = jcampDataType.includes('MASS TIC') || jcampDataType.includes('TIC'); + const isTicData = hasTicCategory || hasTicDataType || hasTicJcampDataType; + const getCategory = idx => csCategories[idx] || ''; + const finalSpectra = []; + const parseIntegralsString = raw => { + if (raw == null) return []; + let text = raw; + if (Array.isArray(text)) text = text.join(' '); + text = String(text).trim(); + const groups = text.match(/\(([^)]+)\)/g) || []; + const out = []; + groups.forEach(g => { + const nums = g.replace(/[()]/g, '').split(/[,\s;]+/).map(s => Number(s)).filter(Number.isFinite); + if (nums.length >= 3) { + const [xL, xU, area, absMaybe] = nums; + out.push({ + xL, + xU, + area, + absoluteArea: Number.isFinite(absMaybe) ? absMaybe : Math.abs(area), + xExtent: { + xL, + xU + } + }); + } + }); + return out; + }; + const pickIntegralsForPair = (raw, idx) => { + if (raw == null) return ''; + if (Array.isArray(raw)) return raw[idx] ?? ''; + if (typeof raw === 'string') return idx === 0 ? raw : ''; + return ''; + }; + if (isUvvisData) { + const spectraList = jcamp.spectra || []; + const uvvisSpectra = []; + const peakTablesByPage = new Map(); + const hasPeakData = table => { + const data = table?.data?.[0]; + if (!data) return false; + if (Array.isArray(data)) return data.length >= 2; + if (data?.x && data?.y) return data.x.length > 0 && data.y.length > 0; + return false; + }; + const buildPeaks = source => { + if (!source) return []; + if (Array.isArray(source)) { + const peaks = []; + for (let i = 0; i < source.length - 1; i += 2) { + const x = Number(source[i]); + const y = Number(source[i + 1]); + if (Number.isFinite(x) && Number.isFinite(y)) peaks.push({ + x, + y + }); + } + return peaks; + } + if (source?.x && source?.y) { + const len = Math.min(source.x.length, source.y.length); + const peaks = new Array(len); + for (let j = 0; j < len; j++) peaks[j] = { + x: source.x[j], + y: source.y[j] + }; + return peaks; + } + return []; + }; + spectraList.forEach((s, idx) => { + if (!s) return; + const sDataType = String(s.dataType || '').toUpperCase(); + const isUvvisSpectrum = s.dataType === 'LC/MS' && getCategory(idx).includes('UVVIS') || sDataType.includes('UV-VIS') || sDataType.includes('UVVIS') || sDataType.includes('HPLC UV'); + if (isUvvisSpectrum) { + uvvisSpectra.push({ + spectrum: s, + idx + }); + } + if (s.dataType?.includes('PEAKTABLE')) { + const pageKey = s.pageValue ?? s.page; + if (pageKey == null) return; + const entry = peakTablesByPage.get(pageKey) || {}; + const cat = getCategory(idx); + if (cat.includes('AUTO_PEAK')) entry.auto = s;else if (cat.includes('EDIT_PEAK')) entry.edit = s;else entry.other = s; + peakTablesByPage.set(pageKey, entry); + } + }); + const container = jcamp?.info?.$OBSERVEDINTEGRALS ?? null; + const jcampUnitsField = String(jcamp?.info?.UNITS || '').toUpperCase(); + const jcampUnitsIndicatesMinutes = jcampUnitsField.includes('MINUTE'); + const jcampUnitsIndicatesSeconds = jcampUnitsField.includes('SECOND'); + const getMaxAbsX = data => { + const xs = data?.[0]?.x; + if (!Array.isArray(xs) || xs.length === 0) return 0; + return xs.reduce((max, value) => { + const abs = Math.abs(Number(value)); + return Number.isFinite(abs) && abs > max ? abs : max; + }, 0); + }; + uvvisSpectra.forEach(({ + spectrum + }, pairIdx) => { + const xUnitUpper = String(spectrum?.xUnit || '').toUpperCase(); + const isExplicitMinutes = xUnitUpper.includes('MINUTE') || jcampUnitsIndicatesMinutes; + const isExplicitSeconds = xUnitUpper.includes('SECOND') || jcampUnitsIndicatesSeconds; + const isTimeAxis = xUnitUpper.includes('TIME') || xUnitUpper.includes('SECOND'); + const dataLooksLikeSeconds = getMaxAbsX(spectrum?.data) > 60; + const needsSecToMin = isTimeAxis && !isExplicitMinutes && (isExplicitSeconds || dataLooksLikeSeconds); + const scaleX = value => needsSecToMin ? value / 60 : value; + const pageKey = spectrum.pageValue ?? spectrum.page; + const peakTable = peakTablesByPage.get(pageKey); + let selectedPeakTable = null; + if (hasPeakData(peakTable?.edit)) { + selectedPeakTable = peakTable.edit; + } else if (hasPeakData(peakTable?.auto)) { + selectedPeakTable = peakTable.auto; + } else if (hasPeakData(peakTable?.other)) { + selectedPeakTable = peakTable.other; + } else { + selectedPeakTable = peakTable?.edit || peakTable?.auto || peakTable?.other || null; + } + const originalData = spectrum?.data?.[0]; + let normalizedData = spectrum.data; + if (needsSecToMin && originalData?.x) { + normalizedData = [{ + ...originalData, + x: originalData.x.map(scaleX) + }]; + } + const mainSpectrum = { + ...spectrum, + data: normalizedData, + peaks: [], + integrations: [], + csCategory: 'UVVIS PEAK TABLE' + }; + const peakSource = selectedPeakTable?.data?.[0] || spectrum?.data?.[0]; + const peaks = buildPeaks(peakSource).map(p => ({ + ...p, + x: scaleX(p.x) + })); + if (peaks.length) mainSpectrum.peaks = peaks; + const rawText = pickIntegralsForPair(container, pairIdx); + const integrals = parseIntegralsString(rawText).map(integ => ({ + ...integ, + xL: scaleX(integ.xL), + xU: scaleX(integ.xU), + xExtent: { + xL: scaleX(integ.xL), + xU: scaleX(integ.xU) + } + })); + if (integrals.length) mainSpectrum.integrations = integrals; + finalSpectra.push(mainSpectrum); + }); + } else if (isTicData) { + (jcamp.spectra || []).forEach(s => { + const hasPoints = s?.data?.[0]?.x?.length > 0; + if (hasPoints) { + finalSpectra.push({ + ...s, + csCategory: (0, _parsing.inferLcMsCategory)(s, jcamp) + }); + } + }); + } else { + (jcamp.spectra || []).forEach(s => { + const hasPoints = s?.data?.[0]?.x?.length > 0; + if (hasPoints) { + finalSpectra.push({ + ...s, + csCategory: (0, _parsing.inferLcMsCategory)(s, jcamp) + }); + } + }); + } + let spectra = extrSpectraShare(finalSpectra, layout) || []; + const info = jcamp?.info || {}; + if (info.UNITS && info.SYMBOL) { + const unitsString = Array.isArray(info.UNITS) ? info.UNITS[0] : info.UNITS; + const symbolString = Array.isArray(info.SYMBOL) ? info.SYMBOL[0] : info.SYMBOL; + const units = String(unitsString).split(','); + const symbols = String(symbolString).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(); - } + symbols.forEach((sym, idx) => { + const curr = String(sym).replace(' ', '').toLowerCase(); + if (curr === 'x') xUnit = units[idx]?.trim?.() || null; + if (curr === 'y') yUnit = units[idx]?.trim?.() || null; }); spectra = spectra.map(sp => { const spectrum = sp; - if (xUnit) { - spectrum.xUnit = xUnit; - } - if (yUnit) { - spectrum.yUnit = yUnit; - } + if (xUnit) spectrum.xUnit = xUnit; + if (yUnit) spectrum.yUnit = yUnit; return spectrum; }); } @@ -408,21 +640,33 @@ const extrSpectraNi = (jcamp, layout) => { return [spectrum] || [jcamp.spectra[0]]; }; const calcThresRef = (s, peakUp) => { - const ys = s && s.data[0].y; - if (!ys) return null; + if (!s || !s.data || !Array.isArray(s.data) || !s.data[0] || !s.data[0].y) { + return null; + } + const ys = s.data[0].y; + if (!ys || !Array.isArray(ys) || ys.length === 0) return null; const ref = peakUp ? Math.min(...ys.map(a => Math.abs(a))) : Math.max(...ys); + if (!s.maxY || s.maxY === 0) return null; 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; + if (!s || !s.data || !Array.isArray(s.data) || !s.data[0] || !s.data[0].y) { + return null; + } + const ys = s.data[0].y; + if (!ys || !Array.isArray(ys) || ys.length === 0) return null; const ref = Math.max(...ys); + if (!s.maxY || s.maxY === 0) return null; return Math.floor(ref * 100 * 100 / s.maxY) / 100; }; const calcLowerThres = s => { - const ys = s && s.data[0].y; - if (!ys) return null; + if (!s || !s.data || !Array.isArray(s.data) || !s.data[0] || !s.data[0].y) { + return null; + } + const ys = s.data[0].y; + if (!ys || !Array.isArray(ys) || ys.length === 0) return null; const ref = Math.min(...ys); + if (!s.minY || s.minY === 0) return null; return Math.ceil(ref * 100 * 100 / s.minY) / 100; }; const extractShift = (s, jcamp) => { @@ -478,13 +722,12 @@ const extractVoltammetryData = jcamp => { 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({ + const baseFeature = { typ: s.dataType + subTyp, peakUp, thresRef, @@ -504,8 +747,14 @@ const buildPeakFeature = (jcamp, layout, peakUp, s, thresRef, upperThres = false scanRate: +info.$CSSCANRATE || 0.1, weAreaValue: info.$CSWEAREAVALUE || '', weAreaUnit: info.$CSWEAREAUNIT || '', - currentMode: info.$CSCURRENTMODE || '' - }, s); + currentMode: info.$CSCURRENTMODE || '', + csCategory: info.$CSCATEGORY || s.csCategory + }; + if (layout === 'LC/MS') { + if (s.peaks) baseFeature.peaks = s.peaks; + if (s.integrations) baseFeature.integrations = s.integrations; + } + return Object.assign({}, baseFeature, s); }; const maxArray = arr => { let len = arr.length; @@ -533,23 +782,43 @@ const calcIntgRefArea = (spectra, stack) => { 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 + $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]; } @@ -588,7 +857,7 @@ const range = (head, tail, length) => { ); }; */ - +exports.buildIntegFeature = buildIntegFeature; const buildSimFeature = jcamp => { const { $CSSIMULATIONPEAKS @@ -766,32 +1035,15 @@ const extrFeaturesCylicVolta = (jcamp, layout, peakUp) => { }).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 extrFeaturesMs = (jcamp, layout, peakUp, spectra) => { const thresRef = jcamp.info && jcamp.info.$CSTHRESHOLD * 100 || 5; - const base = jcamp.spectra[0]; - const features = jcamp.spectra.map(s => { + const features = spectra.map(s => { + if (!s.data || !s.data[0] || !s.data[0].x || !s.data[0].y) { + return null; + } const cpo = buildPeakFeature(jcamp, layout, peakUp, s, +thresRef.toFixed(4)); const bnd = getBoundary(s); - return Object.assign({}, base, cpo, bnd); + return Object.assign({}, cpo, bnd); }).filter(r => r != null); return features; }; @@ -805,17 +1057,135 @@ const extractTemperature = jcamp => { } return 'xxx'; }; +const normalizeXyData = raw => { + if (!raw) return null; + if (Array.isArray(raw)) { + if (raw.length === 0) return null; + const first = raw[0]; + if (first && typeof first === 'object' && !Array.isArray(first)) { + const x = Array.isArray(first.x) ? first.x : []; + const y = Array.isArray(first.y) ? first.y : []; + if (x.length || y.length) return { + x, + y + }; + } + if (Array.isArray(first)) { + if (raw.length === 2 && Array.isArray(raw[0]) && Array.isArray(raw[1])) { + return { + x: raw[0], + y: raw[1] + }; + } + const x = []; + const y = []; + raw.forEach(pair => { + if (!Array.isArray(pair) || pair.length < 2) return; + const xVal = Number(pair[0]); + const yVal = Number(pair[1]); + if (Number.isFinite(xVal) && Number.isFinite(yVal)) { + x.push(xVal); + y.push(yVal); + } + }); + if (x.length || y.length) return { + x, + y + }; + } + } else if (typeof raw === 'object') { + const x = Array.isArray(raw.x) ? raw.x : []; + const y = Array.isArray(raw.y) ? raw.y : []; + if (x.length || y.length) return { + x, + y + }; + } + return null; +}; +const ensureSpectrumData = (spectrum, source) => { + if (!spectrum) return spectrum; + const result = { + ...spectrum + }; + let normalized = normalizeXyData(result.data); + if (!normalized && source) { + normalized = normalizeXyData({ + x: source.x, + y: source.y + }) || normalizeXyData(source.data); + } + if (normalized) { + result.data = [{ + x: normalized.x || [], + y: normalized.y || [] + }]; + } + return result; +}; 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 + 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|\$CSLCMSMZPAGE|SCAN_MODE|SCANMODE|TYPE|SOFTWARE|DATATYPE)/ // eslint-disable-line }); - const layout = readLayout(jcamp); + const isChemstation = (0, _parsing.isChemstationLcms)(source, jcamp); + const parsedPages = (0, _parsing.parseChemstationPages)(source, jcamp); + const spectraCount = Array.isArray(jcamp.spectra) ? jcamp.spectra.length : 0; + if (parsedPages.length > 1 && spectraCount < parsedPages.length) { + jcamp.spectra = parsedPages; + } + const hasNtuples = jcamp.ntuples && Array.isArray(jcamp.ntuples) && jcamp.ntuples.length > 0; + const hasSpectra = jcamp.spectra && Array.isArray(jcamp.spectra) && jcamp.spectra.length > 0; + const hasNtupleData = hasNtuples && jcamp.ntuples.some(ntuple => !!normalizeXyData(ntuple?.data) || !!normalizeXyData({ + x: ntuple?.x, + y: ntuple?.y + })); + const hasSpectraData = hasSpectra && jcamp.spectra.some(spectrum => !!normalizeXyData(spectrum?.data) || !!normalizeXyData({ + x: spectrum?.x, + y: spectrum?.y + })); + if (hasNtuples && hasNtupleData) { + if (hasSpectra && jcamp.spectra.length === 1 && jcamp.ntuples.length > 1) { + const singleSpectrum = jcamp.spectra[0]; + jcamp.spectra = jcamp.ntuples.map(ntuple => { + const spectrum = { + ...singleSpectrum, + ...ntuple, + dataType: singleSpectrum.dataType || jcamp.dataType || ntuple.dataType, + xUnit: ntuple.xUnit || singleSpectrum.xUnit || jcamp.info?.XUNITS, + yUnit: ntuple.yUnit || singleSpectrum.yUnit || jcamp.info?.YUNITS, + pageValue: ntuple.pageValue || ntuple.page, + page: ntuple.page || ntuple.pageValue, + pageSymbol: ntuple.pageSymbol || ntuple.pageValue || ntuple.page + }; + ensureSpectrumData(spectrum, ntuple); + return spectrum; + }); + } else if (!hasSpectra || !hasSpectraData || jcamp.spectra.length < jcamp.ntuples.length) { + jcamp.spectra = jcamp.ntuples.map(ntuple => { + const spectrum = { + ...ntuple, + dataType: jcamp.dataType || ntuple.dataType, + xUnit: ntuple.xUnit || jcamp.info?.XUNITS, + yUnit: ntuple.yUnit || jcamp.info?.YUNITS, + pageValue: ntuple.pageValue || ntuple.page, + page: ntuple.page || ntuple.pageValue, + pageSymbol: ntuple.pageSymbol || ntuple.pageValue || ntuple.page + }; + ensureSpectrumData(spectrum, ntuple); + return spectrum; + }); + } + } + let layout = readLayout(jcamp); + if (isChemstation) { + layout = _list_layout.LIST_LAYOUT.LC_MS; + } const peakUp = !_format.default.isIrLayout(layout); - const spectra = _format.default.isMsLayout(layout) ? extrSpectraMs(jcamp, layout) : extrSpectraNi(jcamp, layout); + const spectra = _format.default.isMsLayout(layout) || _format.default.isLCMsLayout(layout) ? extrSpectraMs(jcamp, layout) : extrSpectraNi(jcamp, layout); let features = {}; - if (_format.default.isMsLayout(layout)) { - features = extrFeaturesMs(jcamp, layout, peakUp); + if (_format.default.isMsLayout(layout) || _format.default.isLCMsLayout(layout)) { + features = extrFeaturesMs(jcamp, layout, peakUp, spectra); } else if (_format.default.isXRDLayout(layout)) { features = extrFeaturesXrd(jcamp, layout, peakUp); const temperature = extractTemperature(jcamp); @@ -851,6 +1221,15 @@ const ExtractJcamp = source => { // : ((Format.isXRDLayout(layout) || Format.isCyclicVoltaLayout(layout)) // ? extrFeaturesXrd(jcamp, layout, peakUp) : extrFeaturesNi(jcamp, layout, peakUp, spectra)); + const lcmsMzPageFromInfo = _format.default.isLCMsLayout(layout) ? (0, _parsing.readLcmsMzPageFromJcampInfo)(jcamp.info) : null; + if (lcmsMzPageFromInfo != null) { + return { + spectra, + features, + layout, + lcms_mz_page: lcmsMzPageFromInfo + }; + } return { spectra, features, diff --git a/dist/helpers/compass.js b/dist/helpers/compass.js index 35e06342..c82f6da0 100644 --- a/dist/helpers/compass.js +++ b/dist/helpers/compass.js @@ -4,9 +4,18 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau Object.defineProperty(exports, "__esModule", { value: true }); -exports.TfRescale = exports.MouseMove = exports.MountCompass = exports.ClickCompass = void 0; +exports.getCurvePointFromEvent = exports.clearIntegrationPreview = exports.TfRescale = exports.MouseMove = exports.MountCompass = exports.ClickCompass = void 0; var _format = _interopRequireDefault(require("./format")); var _chem = require("./chem"); +var _list_ui = require("../constants/list_ui"); +var _cfg = _interopRequireDefault(require("./cfg")); +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; @@ -18,25 +27,16 @@ const TfRescale = focus => { }; exports.TfRescale = TfRescale; 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); @@ -58,6 +58,69 @@ const fetchFreePt = (event, focus, xt, yt) => { }); 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; + if (!_cfg.default.showIntegSplitTools(focus.layout)) 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 + } = (0, _integration_split.getIntegrationSplitTargetFromEvent)(event, focus); + if (!target) { + (0, _integration_split.clearIntegrationSplitPreview)(focus); + return; + } + if (focus.isUiVisualSplitIntgSt && (0, _integration_split.isAlreadyVisuallySplit)(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, @@ -116,21 +179,111 @@ const MouseMove = (event, focus) => { } } } + 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(); - const { - xt, - yt - } = TfRescale(focus); - let pt = fetchPt(event, focus, xt); + if (focus.isUiAddIntgSt && _cfg.default.showIntegSplitTools(focus.layout)) { + 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; + } + if (focus.isUiVisualSplitIntgSt) { + const { + splitX, + target + } = (0, _integration_split.getIntegrationSplitTargetFromEvent)(event, focus); + if (!target) return; + const { + stack = [], + shift = 0 + } = focus.integrationSplitTargets || {}; + const existingSplitX = (0, _integration_split.getVisualSplitLineAtX)(focus, stack, splitX, shift); + (0, _integration_split.clearIntegrationSplitPreview)(focus); + if (Number.isFinite(existingSplitX)) { + if (typeof focus.removeVisualSplitLineAct !== 'function') return; + focus.removeVisualSplitLineAct({ + curveIdx: focus.jcampIdx, + splitX: existingSplitX, + data: focus.data + }); + return; + } + if ((0, _integration_split.isAlreadyVisuallySplit)(target)) return; + if (typeof focus.addVisualSplitLineAct !== 'function') return; + focus.addVisualSplitLineAct({ + curveIdx: focus.jcampIdx, + target, + splitX, + data: focus.data + }); + return; + } const { layout, cyclicvoltaSt, jcampIdx } = focus; + const isPeakGroupSelect = focus.uiSt?.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT; + const isMsGraph = focus.graphIndex === 2; + const isUvvisGraph = focus.graphIndex === 0; + const isLcmsTicGraph = _format.default.isLCMsLayout(layout) && focus.graphIndex === 1; + if (isPeakGroupSelect && isMsGraph) return; + if (isPeakGroupSelect && _format.default.isLCMsLayout(layout) && isUvvisGraph) return; + const { + xt, + yt + } = TfRescale(focus); + let pt = fetchPt(event, focus, xt); if (_format.default.isCyclicVoltaLayout(layout)) { pt = fetchFreePt(event, focus, xt, yt); const onPeak = false; @@ -144,6 +297,8 @@ const ClickCompass = (event, focus) => { } else { focus.clickUiTargetAct(pt, onPeak); } + } else if (isLcmsTicGraph) { + focus.clickUiTargetAct(pt, false, false, jcampIdx, false, 'lcms_tic'); } else { focus.clickUiTargetAct(pt, false, 0, focus.jcampIdx); } @@ -157,11 +312,13 @@ const MountCompass = focus => { } = 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/extractParams.js b/dist/helpers/extractParams.js index cbb4f86a..c7cbe90f 100644 --- a/dist/helpers/extractParams.js +++ b/dist/helpers/extractParams.js @@ -6,35 +6,33 @@ Object.defineProperty(exports, "__esModule", { }); exports.extractParams = void 0; var _format = _interopRequireDefault(require("./format")); -const getScanIdx = (entity, scanSt) => { +var _extractEntityLCMS = require("./extractEntityLCMS"); +const getScanIdx = (entity, scanState) => { const { target, isAuto - } = scanSt; + } = scanState || {}; const { - features, - spectra - } = entity; - const defaultFeat = features.editPeak || features.autoPeak || features[0]; - const hasEdit = !!defaultFeat.scanEditTarget; - const defaultIdx = isAuto || !hasEdit ? defaultFeat.scanAutoTarget : defaultFeat.scanEditTarget; + features = {}, + spectra = [] + } = entity || {}; + const defaultFeature = features.editPeak || features.autoPeak || features[0] || {}; + const hasEdit = !!defaultFeature?.scanEditTarget; + const defaultIdx = isAuto || !hasEdit ? defaultFeature?.scanAutoTarget : defaultFeature?.scanEditTarget; const defaultCount = +spectra.length; let idx = +(target || defaultIdx || 0); - if (idx > defaultCount) { - idx = defaultCount; - } - return idx - 1; + if (idx > defaultCount) idx = defaultCount; + return Math.max(idx - 1, 0); }; -const extrShare = (entity, thresSt, scanIdx = 0) => { +const extractSharedParams = (entity, thresholdState, 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; + spectra = [], + features = {} + } = entity || {}; + const autoPeak = features.autoPeak || features[scanIdx] || features[0] || {}; + const editPeak = features.editPeak || features[scanIdx] || features[0] || {}; + const hasEdit = !!editPeak?.data?.[0]?.x?.length; + const feature = hasEdit && thresholdState?.isEdit ? editPeak : autoPeak; const { integration, multiplicity @@ -47,21 +45,99 @@ const extrShare = (entity, thresSt, scanIdx = 0) => { multiplicity }; }; -const extrMs = (entity, thresSt, scanSt) => { - const scanIdx = getScanIdx(entity, scanSt); +const extractLcmsParams = entity => { + const { + features, + layout + } = entity; + let topicX = []; + let topicY = []; + const entityInfo = (0, _extractEntityLCMS.getLcMsInfo)(entity); + let featuresArray = []; + if (Array.isArray(features)) { + featuresArray = features; + } else if (features && typeof features === 'object') { + featuresArray = Object.values(features); + } + if (entityInfo.kind === 'tic') { + const ticFeature = featuresArray.find(spectrum => spectrum?.data?.[0]?.x?.length > 0); + if (ticFeature?.data?.[0]) { + const { + x, + y + } = ticFeature.data[0]; + topicX = x; + topicY = y; + } + } else { + featuresArray.forEach(spectrum => { + if (!spectrum?.data?.[0]) return; + const { + y + } = spectrum.data[0]; + const { + pageValue + } = spectrum; + topicX.push(pageValue); + topicY.push(Math.max(...y)); + }); + } + return { + topic: { + x: topicX, + y: topicY + }, + feature: { + maxY: topicY.length ? Math.max(...topicY) : 0, + operation: { + layout + }, + data: [{ + x: topicX, + y: topicY + }], + isPeaktable: false + } + }; +}; +const extractMsParams = (entity, thresholdState, scanState, forceLcms = false) => { + const { + layout + } = entity; + if (_format.default.isMsLayout(layout) && !forceLcms) { + const scanIdx = getScanIdx(entity, scanState); + const { + spectra, + feature, + hasEdit + } = extractSharedParams(entity, thresholdState, scanIdx); + const topic = spectra?.[scanIdx]?.data?.[0] || { + x: [], + y: [] + }; + return { + topic, + feature, + hasEdit + }; + } const { spectra, - feature, - hasEdit - } = extrShare(entity, thresSt, scanIdx); - const topic = spectra[scanIdx].data[0]; + features + } = entity; + const { + topic, + feature + } = extractLcmsParams(entity); return { + entity, + spectra, + features, topic, - feature, - hasEdit + feature }; }; -const extrNi = (entity, thresSt) => { +const extractNonMsParams = (entity, thresholdState) => { const scanIdx = 0; const { spectra, @@ -69,8 +145,11 @@ const extrNi = (entity, thresSt) => { hasEdit, integration, multiplicity - } = extrShare(entity, thresSt, scanIdx); - const topic = spectra[0].data[0]; + } = extractSharedParams(entity, thresholdState, scanIdx); + const topic = spectra?.[0]?.data?.[0] || { + x: [], + y: [] + }; return { topic, feature, @@ -79,7 +158,13 @@ const extrNi = (entity, thresSt) => { multiplicity }; }; -const extractParams = (entity, thresSt, scanSt) => _format.default.isMsLayout(entity.layout) ? extrMs(entity, thresSt, scanSt) : extrNi(entity, thresSt); +const extractParams = (entity, thresholdState, scanState, options = {}) => { + const { + forceLcms = false + } = options; + const shouldUseLcmsPath = forceLcms || _format.default.isLCMsLayout(entity.layout); + return _format.default.isMsLayout(entity.layout) || shouldUseLcmsPath ? extractMsParams(entity, thresholdState, scanState, shouldUseLcmsPath) : extractNonMsParams(entity, thresholdState); +}; // eslint-disable-line exports.extractParams = extractParams; \ No newline at end of file diff --git a/dist/helpers/extractPeaksEdit.js b/dist/helpers/extractPeaksEdit.js index e68864ec..5537003a 100644 --- a/dist/helpers/extractPeaksEdit.js +++ b/dist/helpers/extractPeaksEdit.js @@ -5,24 +5,44 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.extractPeaksEdit = exports.extractAutoPeaks = exports.extractAreaUnderCurve = void 0; -var _converter = require("./converter"); +Object.defineProperty(exports, "formatLcmsIntegralsForBackend", { + enumerable: true, + get: function get() { + return _submit.formatLcmsIntegralsForBackend; + } +}); +Object.defineProperty(exports, "formatLcmsPeaksForBackend", { + enumerable: true, + get: function get() { + return _submit.formatLcmsPeaksForBackend; + } +}); +Object.defineProperty(exports, "getLcmsMzPageData", { + enumerable: true, + get: function get() { + return _submit.getLcmsMzPageData; + } +}); var _chem = require("./chem"); +var _converter = require("./converter"); var _shift = require("./shift"); var _format = _interopRequireDefault(require("./format")); var _integration = require("./integration"); -const extractPeaksEdit = (feature, editPeakSt, thresSt, shiftSt, layoutSt, atIndex = 0) => { - const offset = _format.default.isMsLayout(layoutSt) ? 0 : (0, _shift.shiftOffsetAtIndex)(shiftSt, atIndex); - const peaks = (0, _chem.Convert2Peak)(feature, thresSt.value, offset); - const peaksEdit = (0, _converter.PksEdit)(peaks, editPeakSt); - return peaksEdit; -}; -exports.extractPeaksEdit = extractPeaksEdit; +var _submit = require("../features/lc-ms/submit"); +/* eslint-disable max-len */ + const extractAutoPeaks = (feature, thresSt, shiftSt, layoutSt, atIndex = 0) => { - const offset = _format.default.isMsLayout(layoutSt) ? 0 : (0, _shift.shiftOffsetAtIndex)(shiftSt, atIndex); + const offset = _format.default.isMsLayout(layoutSt) || _format.default.isLCMsLayout(layoutSt) ? 0 : (0, _shift.shiftOffsetAtIndex)(shiftSt, atIndex); const peaks = (0, _chem.Convert2Peak)(feature, thresSt.value, offset); return peaks; }; exports.extractAutoPeaks = extractAutoPeaks; +const extractPeaksEdit = (feature, editPeakSt, thresSt, shiftSt, layoutSt, atIndex = 0) => { + if (_format.default.isLCMsLayout(layoutSt)) return []; + const peaks = extractAutoPeaks(feature, thresSt, shiftSt, layoutSt, atIndex); + return (0, _converter.PksEdit)(peaks, editPeakSt); +}; +exports.extractPeaksEdit = extractPeaksEdit; const getAUCValue = (integrationSt, layoutSt) => { const { refArea, diff --git a/dist/helpers/format.js b/dist/helpers/format.js index b899ec24..109c814b 100644 --- a/dist/helpers/format.js +++ b/dist/helpers/format.js @@ -1,11 +1,9 @@ "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"); @@ -25,6 +23,7 @@ const spectraDigit = layout => { case _list_layout.LIST_LAYOUT.CDS: case _list_layout.LIST_LAYOUT.SEC: case _list_layout.LIST_LAYOUT.GC: + case _list_layout.LIST_LAYOUT.LC_MS: case _list_layout.LIST_LAYOUT.MS: return 0; case _list_layout.LIST_LAYOUT.C13: @@ -73,6 +72,28 @@ const toPeakStr = peaks => { const str = arr.join('#'); return str; }; +const extractUvvisLcmsPeaks = hplcMsSt => { + if (!hplcMsSt?.uvvis) { + return '{}'; + } + const { + listWaveLength = [], + spectraList = [] + } = hplcMsSt.uvvis; + const byWavelength = {}; + spectraList.forEach((spectrum, idx) => { + const wl = listWaveLength[idx]; + const wlKey = String(Math.round(wl)); + (spectrum.peaks || []).forEach((p, n) => { + if (!byWavelength[wlKey]) byWavelength[wlKey] = []; + byWavelength[wlKey].push({ + x: p.x, + y: p.y + }); + }); + }); + return JSON.stringify(byWavelength); +}; const spectraOps = { [_list_layout.LIST_LAYOUT.PLAIN]: { head: '', @@ -157,6 +178,10 @@ const spectraOps = { [_list_layout.LIST_LAYOUT.DLS_INTENSITY]: { head: 'DLS', tail: '.' + }, + [_list_layout.LIST_LAYOUT.LC_MS]: { + head: 'HPLC UV/VIS', + tail: '' } }; const shiftAnchorX = selectedShift => { @@ -170,6 +195,147 @@ const rmRef = (peaks, shift, atIndex = 0) => { if (refValue == null) return peaks; return peaks.map(p => (0, _converter.IsSame)(p.x, refValue) ? null : p).filter(r => r != null); }; +const isValidLcmsWavelengthLabel = wl => Number.isFinite(wl) && wl > 0; +const LCMS_INTEGRATION_EXPORT_MODES = ['percent', 'area', 'both']; +const isLcmsIntegrationExportMode = v => LCMS_INTEGRATION_EXPORT_MODES.includes(v); +const formatedLCMS = (hplcMsSt, isAscend, decimal, options = {}) => { + if (!hplcMsSt?.uvvis) { + return ''; + } + const { + lcmsIntegrationsExport: modeOpt, + includeIntegrationArea = false + } = options; + let lcmsIntegrationsExport = modeOpt; + if (!isLcmsIntegrationExportMode(lcmsIntegrationsExport)) { + lcmsIntegrationsExport = hplcMsSt?.lcmsIntegrationsExport; + } + if (!isLcmsIntegrationExportMode(lcmsIntegrationsExport)) { + lcmsIntegrationsExport = includeIntegrationArea ? 'both' : 'percent'; + } + let result = '\n'; + const sections = []; + const parsedDecimal = Number.isFinite(decimal) ? decimal : Number.parseInt(decimal, 10); + const resolvedDecimal = Number.isFinite(parsedDecimal) ? parsedDecimal : 3; + const { + listWaveLength = [], + spectraList = [] + } = hplcMsSt.uvvis || {}; + const ms = hplcMsSt.ms || {}; + const tic = hplcMsSt.tic; + const threshold = hplcMsSt.threshold; + listWaveLength.forEach((wavelength, idx) => { + const spectrum = spectraList[idx]; + if (!spectrum) { + return; + } + const peaks = spectrum.peaks || []; + const integrations = spectrum.integrations || []; + const stack = integrations?.[0]?.stack; + const hasStack = Array.isArray(stack) && stack.length > 0; + const hasList = !hasStack && Array.isArray(integrations) && integrations.length > 0; + const hasIntegrations = hasStack || hasList; + const hasPeaks = peaks.length > 0; + if (!hasPeaks && !hasIntegrations) { + return; + } + const lines = []; + if (isValidLcmsWavelengthLabel(wavelength)) { + lines.push(`Wavelength ${wavelength} nm:`); + } + if (hasPeaks) { + const sortedPeaks = [...peaks].sort((a, b) => b.y - a.y); + const maxIntensity = sortedPeaks[0].y || 1; + const peakLines = sortedPeaks.map(peak => { + const rt = peak.x.toFixed(resolvedDecimal); + const percent = (peak.y / maxIntensity * 100).toFixed(1); + return `${rt} min (${percent}%)`; + }); + lines.push(`Peaks: ${peakLines.join(', ')}`); + } + if (hasIntegrations) { + const entries = hasStack ? stack : integrations; + const refAreaCandidate = hasStack ? integrations?.[0]?.refArea : integrations?.[0]?.refArea ?? integrations?.[0]?.area; + const refArea = refAreaCandidate && refAreaCandidate > 0 ? refAreaCandidate : 1; + const sortedIntegrations = [...entries].sort((a, b) => a.xL - b.xL); + const integrationLines = sortedIntegrations.map(integ => { + const rt = integ.xL.toFixed(resolvedDecimal); + const area = integ.area || integ.absoluteArea || 0; + const percent = (area / refArea * 100).toFixed(1); + const areaStr = Number.isFinite(area) ? area.toExponential(3) : String(area); + if (lcmsIntegrationsExport === 'area') { + return `${rt} min (A=${areaStr})`; + } + if (lcmsIntegrationsExport === 'both') { + return `${rt} min (${percent}%, A=${areaStr})`; + } + return `${rt} min (${percent}%)`; + }); + lines.push(`Integrations: ${integrationLines.join(', ')}`); + } + sections.push(lines.join('\n')); + }); + if (sections.length > 0) { + result = `\n${sections.join('\n\n')}`; + } + const polarity = tic?.polarity || 'positive'; + let polarityKey = 'neutral'; + if (polarity === 'negative') { + polarityKey = 'negative'; + } else if (polarity === 'positive') { + polarityKey = 'positive'; + } + let polarityLabel = ''; + if (polarity === 'negative') { + polarityLabel = '−'; + } else if (polarity === 'positive') { + polarityLabel = '+'; + } + if (tic && ms[polarityKey]) { + const pageValues = Array.isArray(ms[polarityKey].pageValues) ? ms[polarityKey].pageValues : []; + const peaksByPage = Array.isArray(ms[polarityKey].peaks) ? ms[polarityKey].peaks : []; + let currentIndex = -1; + if (Number.isFinite(tic.currentPageValue) && pageValues.length > 0) { + currentIndex = pageValues.findIndex(value => Number.isFinite(value) && Math.abs(value - tic.currentPageValue) < 1e-6); + } + if (Array.isArray(tic[polarityKey]?.data?.x)) { + const fallbackIndex = tic[polarityKey].data.x.findIndex(x => Math.abs(x - tic.currentPageValue) < 1e-6); + if (currentIndex < 0) currentIndex = fallbackIndex; + } + if (currentIndex >= 0 && peaksByPage[currentIndex]) { + const peaks = peaksByPage[currentIndex]; + const maxIntensity = Math.max(...peaks.map(p => p.y)) || 1; + const thresholdValue = threshold?.value != null ? threshold.value : 5; + const filtered = peaks.filter(peak => peak.y / maxIntensity * 100 >= thresholdValue); + const sortedPeaks = [...filtered].sort((a, b) => { + if (isAscend) { + return parseFloat(a.x) - parseFloat(b.x); + } + return parseFloat(b.x) - parseFloat(a.x); + }); + const label = polarityLabel ? `${polarityLabel}ESI` : 'ESI'; + if (result) { + result += '\n\n'; + } + const rtPage = tic?.currentPageValue; + const rtDecimal = Math.max(resolvedDecimal, 3); + const rtPart = Number.isFinite(rtPage) ? `RT ${fixDigit(rtPage, rtDecimal)} min, ` : ''; + result += `MS (${label}), ${rtPart}m/z (≥${thresholdValue}%):\n`; + const lines = sortedPeaks.map(peak => { + const mass = fixDigit(peak.x, resolvedDecimal); + const percent = Math.round(peak.y / maxIntensity * 100); + return `${mass} (${percent}%)`; + }); + result += ` ${lines.join(', ')}`; + } else { + if (result) { + result += '\n\n'; + } + result += 'MS: No data for current retention time.\n'; + } + } + return result; +}; const formatedMS = (peaks, maxY, decimal = 2, isAscend = true) => { const ascendFunc = (a, b) => parseFloat(a) - parseFloat(b); const descendFunc = (a, b) => parseFloat(b) - parseFloat(a); @@ -427,6 +593,7 @@ const peaksBody = ({ atIndex = 0, waveLength, temperature, + hplcMsSt = null, feature }) => { const result = rmShiftFromPeaks(peaks, shift, atIndex); @@ -435,6 +602,9 @@ const peaksBody = ({ 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.LC_MS) { + return formatedLCMS(hplcMsSt, isAscend, decimal); + } if (layout === _list_layout.LIST_LAYOUT.MS) { return formatedMS(ordered, maxY, decimal, isAscend); } @@ -504,6 +674,7 @@ const isCyclicVoltaLayout = layoutSt => _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMME 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 isLCMsLayout = layoutSt => _list_layout.LIST_LAYOUT.LC_MS === 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; @@ -668,6 +839,7 @@ const inlineNotation = (layout, data, sampleName = '') => { }; const Format = { toPeakStr, + extractUvvisLcmsPeaks, buildData, spectraDigit, spectraOps, @@ -697,6 +869,7 @@ const Format = { isDLSIntensityLayout, isEmWaveLayout, isGCLayout, + isLCMsLayout, fixDigit, clampDecimalPlaces, formatPeaksByPrediction, @@ -712,6 +885,7 @@ const Format = { formatedXRD, strNumberFixedLength, inlineNotation, + formatedLCMS, formatHplcAucPanel, formatedHplcUvVis }; diff --git a/dist/helpers/integration.js b/dist/helpers/integration.js index 3be92276..8c1fac82 100644 --- a/dist/helpers/integration.js +++ b/dist/helpers/integration.js @@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.getArea = exports.getAbsoluteArea = exports.calcArea = void 0; +exports.splitAreaProportionally = exports.normalizeSplitLines = exports.getVisualSplitGroups = exports.getVisualSplitGroupBoundaries = exports.getSplitAreas = exports.getLinearBaseline = exports.getIntegrationPoints = exports.getArea = exports.getAbsoluteAreaWithBaseline = exports.getAbsoluteArea = exports.generateVisualSplitGroupId = exports.calcArea = exports.buildSplitIntervals = void 0; var _calc = require("./calc"); /* eslint-disable no-mixed-operators */ const getArea = (xL, xU, data) => { + if (!Array.isArray(data) || data.length === 0) return NaN; let [iL, iU] = [data.length - 1, 0]; for (let i = 0; i < data.length; i += 1) { const pt = data[i]; @@ -23,27 +24,68 @@ const getArea = (xL, xU, data) => { return Math.abs(data[iU].k - data[iL].k); }; exports.getArea = getArea; -const getAbsoluteArea = (xL, xU, data) => { - const ps = data.filter(d => d.x > xL && d.x < xU); - if (!ps[0]) return 0; - let area = 0; - const point1 = ps[0]; - const point2 = ps[ps.length - 1]; +const getIntegrationPoints = (xL, xU, data) => { + if (!Array.isArray(data)) return []; + return 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); - 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); - area += delta; + return point => point1.y + slope * (point.x - point1.x); +}; +exports.getLinearBaseline = getLinearBaseline; +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); +}; +exports.normalizeSplitLines = normalizeSplitLines; +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 + })); +}; +exports.buildSplitIntervals = buildSplitIntervals; +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; }; +exports.getAbsoluteAreaWithBaseline = getAbsoluteAreaWithBaseline; +const getAbsoluteArea = (xL, xU, data) => { + const points = getIntegrationPoints(xL, xU, data); + const baselineY = getLinearBaseline(points); + return getAbsoluteAreaWithBaseline(xL, xU, data, baselineY); +}; exports.getAbsoluteArea = getAbsoluteArea; +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) + })); +}; +exports.getSplitAreas = getSplitAreas; const calcArea = (d, refArea, refFactor, ignoreRef = false) => { if (ignoreRef) { const { @@ -53,6 +95,77 @@ const calcArea = (d, refArea, refFactor, ignoreRef = false) => { } return (d.area * refFactor / refArea).toFixed(2); }; +exports.calcArea = calcArea; +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 + }; +}; +exports.splitAreaProportionally = splitAreaProportionally; +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}`; +}; +exports.generateVisualSplitGroupId = generateVisualSplitGroupId; +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; +}; +exports.getVisualSplitGroups = getVisualSplitGroups; +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; +}; // eslint-disable-line -exports.calcArea = calcArea; \ No newline at end of file +exports.getVisualSplitGroupBoundaries = getVisualSplitGroupBoundaries; \ No newline at end of file diff --git a/dist/helpers/mount.js b/dist/helpers/mount.js index 5f1bb693..b1ca522b 100644 --- a/dist/helpers/mount.js +++ b/dist/helpers/mount.js @@ -3,7 +3,7 @@ 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; +exports.MountThresLine = exports.MountTags = exports.MountRef = exports.MountPath = exports.MountMarker = exports.MountMainFrame = exports.MountGrid = exports.MountGraphLabel = 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)'); @@ -17,6 +17,7 @@ const MountTags = target => { 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 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, @@ -30,6 +31,7 @@ const MountTags = target => { mpyt2Path, mpypPath, aucPath, + visualSplitPath, peckerPath // eslint-disable-line }; }; @@ -91,6 +93,11 @@ const MountAxisLabelY = target => { 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 MountGraphLabel = target => { + const xTrans = `translate(${target.w / 2}, ${20})`; + target.root.append('text').attr('text-anchor', 'middle').attr('transform', xTrans).attr('class', 'mark-text').attr('font-family', 'Helvetica').style('font-size', '12px'); +}; +exports.MountGraphLabel = MountGraphLabel; const MountMarker = (target, color) => { const tTrans = `translate(${target.w - 80}, -10)`; const lTrans = `translate(${target.w - 200}, -18)`; diff --git a/dist/index.js b/dist/index.js index c30607e6..97acc0d8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -6,6 +6,8 @@ var _reactDom = _interopRequireDefault(require("react-dom")); var _material = require("@mui/material"); var _reactQuill = _interopRequireDefault(require("react-quill")); var _app = require("./app"); +var _extractEntityLCMS = require("./helpers/extractEntityLCMS"); +var _utils = require("./reducers/reducer_hplc_ms/utils"); var _shift = require("./helpers/shift"); var _nmr1h_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr1h_jcamp")); var _nmr1h_2_jcamp = _interopRequireDefault(require("./__tests__/fixtures/nmr1h_2_jcamp")); @@ -20,6 +22,14 @@ var _compare_ir_1_jcamp = _interopRequireDefault(require("./__tests__/fixtures/c 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 _lc_ms_jcamp = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp")); +var _lc_ms_jcamp_ = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_2")); +var _lc_ms_jcamp_tic_pos = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_tic_pos")); +var _lc_ms_jcamp_tic_neg = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_tic_neg")); +var _lc_ms_jcamp_uvvis = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_uvvis")); +var _lc_ms_jcamp_tic_chemstation = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_tic_chemstation")); +var _lc_ms_jcamp_mz_chemstation = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_mz_chemstation")); +var _lc_ms_jcamp_uvvis_chemstation = _interopRequireDefault(require("./__tests__/fixtures/lc_ms_jcamp_uvvis_chemstation")); 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")); @@ -72,6 +82,14 @@ 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 lcmsEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp.default); +const lcmsEntity2 = _app.FN.ExtractJcamp(_lc_ms_jcamp_.default); +const hplcMsTicPosEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_tic_pos.default); +const hplcMsTicNegEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_tic_neg.default); +const hplcMsUvvisEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_uvvis.default); +const hplcMsTicChemstationEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_tic_chemstation.default); +const hplcMsMzChemstationEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_mz_chemstation.default); +const hplcMsUvvisChemstationEntity = _app.FN.ExtractJcamp(_lc_ms_jcamp_uvvis_chemstation.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); @@ -96,6 +114,140 @@ 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); +const cloneData = value => JSON.parse(JSON.stringify(value)); +const parseNumericPage = feature => { + const candidates = [feature?.pageValue, feature?.page, feature?.pageSymbol]; + for (let i = 0; i < candidates.length; i += 1) { + const raw = candidates[i]; + if (raw != null) { + if (typeof raw === 'number' && Number.isFinite(raw)) return raw; + const text = String(raw).split('\n')[0].trim(); + const match = text.match(/[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/); + if (match) { + const value = Number(match[0]); + if (Number.isFinite(value)) return value; + } + } + } + return null; +}; +const getCurveFeatures = curve => { + if (Array.isArray(curve?.features)) return curve.features; + if (curve?.features && typeof curve.features === 'object') { + return Object.values(curve.features); + } + return []; +}; +const selectClosestMsFeature = (retentionTime, polarity) => { + const featurePool = [...getCurveFeatures(lcmsEntity).map(feature => ({ + curve: lcmsEntity, + feature + })), ...getCurveFeatures(lcmsEntity2).map(feature => ({ + curve: lcmsEntity2, + feature + }))].filter(entry => Number.isFinite(parseNumericPage(entry.feature))); + if (featurePool.length === 0) return null; + const normalizedPolarity = polarity ? String(polarity).toLowerCase() : null; + const filteredPool = normalizedPolarity ? featurePool.filter(entry => (0, _extractEntityLCMS.getLcMsInfo)(entry.curve).polarity === normalizedPolarity) : featurePool; + const pool = filteredPool.length > 0 ? filteredPool : featurePool; + if (pool.length === 0) return null; + if (!Number.isFinite(retentionTime)) return pool[0]; + return pool.reduce((best, entry) => { + const bestRt = parseNumericPage(best.feature); + const currentRt = parseNumericPage(entry.feature); + if (!Number.isFinite(bestRt)) return entry; + if (!Number.isFinite(currentRt)) return best; + return Math.abs(currentRt - retentionTime) < Math.abs(bestRt - retentionTime) ? entry : best; + }, pool[0]); +}; +const buildLcmsStandaloneMultiEntities = (retentionTime, polarity) => { + const selected = selectClosestMsFeature(retentionTime, polarity); + const selectedMsCurve = selected?.curve || lcmsEntity; + const allFeatures = getCurveFeatures(selectedMsCurve); + const msCurve = cloneData(selectedMsCurve); + const spectrArr = Array.isArray(msCurve.spectra) ? msCurve.spectra : []; + const nFeat = allFeatures.length; + const nSpec = spectrArr.length; + const primaryIdx = selected?.feature != null && allFeatures.indexOf(selected.feature) >= 0 ? allFeatures.indexOf(selected.feature) : 0; + let rawLen = Math.min(nFeat, nSpec); + if (primaryIdx >= rawLen) { + rawLen = Math.min(primaryIdx + 1, nFeat, nSpec); + } + const safePrimary = Math.min(primaryIdx, Math.max(0, rawLen - 1)); + const allIndices = Array.from({ + length: rawLen + }, (_, i) => i); + const orderedIdx = [safePrimary, ...allIndices.filter(i => i !== safePrimary)]; + msCurve.features = orderedIdx.map(i => cloneData(allFeatures[i])); + msCurve.spectra = orderedIdx.map(i => cloneData(spectrArr[i])); + const multi = [cloneData(hplcMsTicPosEntity), cloneData(hplcMsTicNegEntity), cloneData(hplcMsUvvisEntity), msCurve]; + const pol = polarity ? String(polarity).toLowerCase() : 'positive'; + const ticEntityForPolarity = pol === 'negative' ? multi[1] : multi[0]; + const ticXs = ticEntityForPolarity?.features?.[0]?.data?.[0]?.x || []; + const rtNum = Number.isFinite(retentionTime) ? retentionTime : parseNumericPage({ + pageValue: retentionTime, + page: retentionTime, + pageSymbol: retentionTime + }); + const snapped = Array.isArray(ticXs) && ticXs.length > 0 && Number.isFinite(rtNum) ? (0, _utils.snapRtToAxis)(rtNum, ticXs) : null; + if (snapped != null && Number.isFinite(snapped)) { + if (msCurve.features[0]) { + msCurve.features[0].pageValue = snapped; + msCurve.features[0].page = String(snapped); + msCurve.features[0].pageSymbol = String(snapped); + } + if (msCurve.spectra?.[0]) { + msCurve.spectra[0].pageValue = snapped; + msCurve.spectra[0].page = String(snapped); + msCurve.spectra[0].pageSymbol = String(snapped); + } + } + return multi; +}; +const getInitialLcmsRetentionTime = () => { + const ticX = hplcMsTicPosEntity?.features?.[0]?.data?.[0]?.x; + return Array.isArray(ticX) && Number.isFinite(ticX[0]) ? ticX[0] : null; +}; +const selectClosestChemstationMzFeature = retentionTime => { + const allFeatures = getCurveFeatures(hplcMsMzChemstationEntity); + if (allFeatures.length === 0) return null; + if (!Number.isFinite(retentionTime)) return allFeatures[0]; + return allFeatures.reduce((best, feature) => { + const bestRt = parseNumericPage(best); + const currentRt = parseNumericPage(feature); + if (!Number.isFinite(bestRt)) return feature; + if (!Number.isFinite(currentRt)) return best; + return Math.abs(currentRt - retentionTime) < Math.abs(bestRt - retentionTime) ? feature : best; + }, allFeatures[0]); +}; +const buildChemstationStandaloneMultiEntities = retentionTime => { + const allFeatures = getCurveFeatures(hplcMsMzChemstationEntity); + const selectedFeature = selectClosestChemstationMzFeature(retentionTime); + const featureIdx = selectedFeature != null && allFeatures.indexOf(selectedFeature) >= 0 ? allFeatures.indexOf(selectedFeature) : 0; + const msCurve = cloneData(hplcMsMzChemstationEntity); + const spectrArr = Array.isArray(msCurve.spectra) ? msCurve.spectra : []; + const safeIdx = Math.min(featureIdx, Math.max(allFeatures.length - 1, 0)); + msCurve.features = [cloneData(allFeatures[safeIdx])]; + msCurve.spectra = spectrArr[safeIdx] ? [cloneData(spectrArr[safeIdx])] : [cloneData(allFeatures[safeIdx])]; + const ticXs = hplcMsTicChemstationEntity?.features?.[0]?.data?.[0]?.x || []; + const rtNum = Number.isFinite(retentionTime) ? retentionTime : parseNumericPage(msCurve.features[0]); + const snapped = Array.isArray(ticXs) && ticXs.length > 0 && Number.isFinite(rtNum) ? (0, _utils.snapRtToAxis)(rtNum, ticXs) : null; + if (snapped != null && Number.isFinite(snapped)) { + msCurve.features[0].pageValue = snapped; + msCurve.features[0].page = String(snapped); + msCurve.features[0].pageSymbol = String(snapped); + if (msCurve.spectra[0]) { + msCurve.spectra[0].pageValue = snapped; + msCurve.spectra[0].page = String(snapped); + msCurve.spectra[0].pageSymbol = String(snapped); + } + } + return [cloneData(hplcMsTicChemstationEntity), msCurve, cloneData(hplcMsUvvisChemstationEntity)]; +}; +const getInitialChemstationRetentionTime = () => { + const ticX = hplcMsTicChemstationEntity?.features?.[0]?.data?.[0]?.x; + return Array.isArray(ticX) && Number.isFinite(ticX[0]) ? ticX[0] : null; +}; class DemoWriteIr extends _react.default.Component { constructor(props) { super(props); @@ -105,7 +257,9 @@ class DemoWriteIr extends _react.default.Component { predictions: false, molecule: '', showOthers: false, - descChanged: '' + descChanged: '', + lcmsDynamicMultiEntities: null, + lcmsChemstationDynamicMultiEntities: null }; this.onClick = this.onClick.bind(this); this.writeMpy = this.writeMpy.bind(this); @@ -121,16 +275,8 @@ class DemoWriteIr extends _react.default.Component { 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: '' - }); - }; + this.handleLcmsPageRequest = this.handleLcmsPageRequest.bind(this); + this.lcmsRequestCounter = 0; } onShowOthers(jcamp) { // eslint-disable-line @@ -144,6 +290,82 @@ class DemoWriteIr extends _react.default.Component { descChanged: content }); } + componentDidUpdate(_prevProps, prevState) { + const { + typ + } = this.state; + const { + typ: prevTyp + } = prevState; + if (typ === 'lcms' && prevTyp !== 'lcms') { + const initialRt = getInitialLcmsRetentionTime(); + this.handleLcmsPageRequest({ + retentionTime: initialRt, + polarity: 'positive', + trigger: 'initial_load' + }); + } + if (typ === 'lcms chemstation' && prevTyp !== 'lcms chemstation') { + const initialRt = getInitialChemstationRetentionTime(); + this.handleLcmsPageRequest({ + retentionTime: initialRt, + polarity: 'positive', + trigger: 'initial_load' + }); + } + } + handleLcmsPageRequest(request) { + const { + typ + } = this.state; + if (typ !== 'lcms' && typ !== 'lcms chemstation') return; + const retentionTime = request?.retentionTime; + const polarity = request?.polarity; + const trigger = request?.trigger || 'unknown'; + this.lcmsRequestCounter += 1; + const requestId = this.lcmsRequestCounter; + if (typeof window !== 'undefined') { + // eslint-disable-next-line no-underscore-dangle + const history = Array.isArray(window.__lcmsDemoRequests) ? window.__lcmsDemoRequests : []; + history.push({ + requestId, + retentionTime, + polarity, + trigger, + createdAt: Date.now() + }); + // eslint-disable-next-line no-underscore-dangle + window.__lcmsDemoRequests = history; + } + setTimeout(() => { + if (requestId !== this.lcmsRequestCounter) return; + if (typ === 'lcms chemstation') { + this.setState({ + lcmsChemstationDynamicMultiEntities: buildChemstationStandaloneMultiEntities(retentionTime) + }); + return; + } + this.setState({ + lcmsDynamicMultiEntities: buildLcmsStandaloneMultiEntities(retentionTime, polarity) + }); + }, 250); + } + onClick(typ) { + return () => { + const isLcms = typ === 'lcms'; + const isChemstation = typ === 'lcms chemstation'; + const initialRt = getInitialLcmsRetentionTime(); + const initialChemstationRt = getInitialChemstationRetentionTime(); + this.setState({ + typ, + desc: '', + predictions: false, + molecule: '', + lcmsDynamicMultiEntities: isLcms ? buildLcmsStandaloneMultiEntities(initialRt) : null, + lcmsChemstationDynamicMultiEntities: isChemstation ? buildChemstationStandaloneMultiEntities(initialChemstationRt) : null + }); + }; + } loadEntity() { const { typ @@ -194,14 +416,22 @@ class DemoWriteIr extends _react.default.Component { case 'gc': return gcEntity1; case 'ms': + return msEntity; + case 'lcms': + return lcmsEntity; + case 'lcms chemstation': + return hplcMsUvvisChemstationEntity; default: return msEntity; } } loadMultiEntities() { const { - typ + typ, + lcmsDynamicMultiEntities, + lcmsChemstationDynamicMultiEntities } = this.state; + const chemstationMultiEntities = lcmsChemstationDynamicMultiEntities || buildChemstationStandaloneMultiEntities(getInitialChemstationRetentionTime()); switch (typ) { case 'cyclic volta': return [cyclicVoltaEntity1, cyclicVoltaEntity2, cyclicVoltaEntity3]; @@ -219,8 +449,12 @@ class DemoWriteIr extends _react.default.Component { return [aifEntity1, aifEntity2]; case 'gc': return [gcEntity1, gcEntity2, gcEntity3]; + case 'lcms': + return lcmsDynamicMultiEntities || buildLcmsStandaloneMultiEntities(getInitialLcmsRetentionTime()); + case 'lcms chemstation': + return chemstationMultiEntities; default: - return false; + return []; } } loadQuill() { @@ -247,6 +481,8 @@ class DemoWriteIr extends _react.default.Component { case 'dsc': case 'xrd': case 'ms': + case 'lcms': + case 'lcms chemstation': case 'cyclic volta': case 'cds': case 'sec': @@ -314,7 +550,8 @@ class DemoWriteIr extends _react.default.Component { boundary, integration, waveLength, - temperature + temperature, + hplcMsSt: _app.store.getState().hplcMs }); const wrapper = _app.FN.peaksWrapper(safeLayout, shiftForFormatting); let desc = this.rmDollarSign(wrapper.head) + body + wrapper.tail; @@ -482,10 +719,7 @@ class DemoWriteIr extends _react.default.Component { shift, isAscend, decimal, - analysis, isIntensity, - integration, - multiplicity, waveLength } = pickSelectedSpectrumFromPayload(payload); const entity = this.loadEntity(); @@ -514,18 +748,20 @@ class DemoWriteIr extends _react.default.Component { isIntensity, boundary, waveLength, - temperature + temperature, + hplcMsSt: _app.store.getState().hplcMs }); /*eslint-disable */ - console.log(analysis); - console.log(integration); - console.log(multiplicity); + let message = `Peaks: ${body}\n`; 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'); + message += '- - - - - - - - - - -\n'; + message += `Shift solvent = ${label}, ${shift.ref.value}ppm\n`; } + console.info(message); // eslint-disable-line no-console + this.setState({ + desc: message + }); /*eslint-disable */ } predictOp({ @@ -598,7 +834,9 @@ class DemoWriteIr extends _react.default.Component { value: this.writeMpy }, ...operations]; } - const refreshCb = () => alert('Refresch simulation!'); + const refreshCb = () => { + console.info('Refresh simulation requested.'); // eslint-disable-line no-console + }; const forecast = { btnCb: this.predictOp, refreshCb, @@ -786,6 +1024,20 @@ class DemoWriteIr extends _react.default.Component { }, onClick: this.onClick('ms'), children: "MS" + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, { + variant: "contained", + style: { + margin: '0 10px 0 10px' + }, + onClick: this.onClick('lcms'), + children: "LC/MS OpenLab" + }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, { + variant: "contained", + style: { + margin: '0 10px 0 10px' + }, + onClick: this.onClick('lcms chemstation'), + children: "LC/MS Chemstation" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, { variant: "contained", style: { @@ -818,6 +1070,7 @@ class DemoWriteIr extends _react.default.Component { }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_app.SpectraEditor, { entity: entity, multiEntities: multiEntities, + onLcmsPageRequest: this.handleLcmsPageRequest, others: others, editorOnly: false, descriptions: desc, @@ -864,4 +1117,9 @@ class DemoWriteIr extends _react.default.Component { } // - - - DOM - - - -_reactDom.default.render(/*#__PURE__*/(0, _jsxRuntime.jsx)(DemoWriteIr, {}), document.getElementById('root')); \ No newline at end of file +_reactDom.default.render(/*#__PURE__*/(0, _jsxRuntime.jsx)(DemoWriteIr, {}), document.getElementById('root')); +if (typeof window !== 'undefined') { + window.__spectraStore = _app.store; + // eslint-disable-next-line no-underscore-dangle + window.__lcmsDemoRequests = []; +} \ No newline at end of file diff --git a/dist/layer_content.js b/dist/layer_content.js index 56a2fb51..7192e375 100644 --- a/dist/layer_content.js +++ b/dist/layer_content.js @@ -17,9 +17,11 @@ 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 safeForecast = forecast && typeof forecast === 'object' ? forecast : {}; + const isEmpty = Object.keys(safeForecast).length === 0 && safeForecast.constructor === Object; const isNmr = _format.default.isNmrLayout(layoutSt); const isMs = _format.default.isMsLayout(layoutSt); + const isLCMs = _format.default.isLCMsLayout(layoutSt); const isIr = _format.default.isIrLayout(layoutSt); const isUvvis = _format.default.isUvVisLayout(layoutSt) || _format.default.isHplcUvVisLayout(layoutSt); const isXRD = _format.default.isXRDLayout(layoutSt); @@ -30,7 +32,8 @@ const extractLayout = (forecast, layoutSt) => { isIr, isMs, isUvvis, - isXRD + isXRD, + isLCMs }; }; const Content = ({ @@ -49,7 +52,8 @@ const Content = ({ isIr, isMs, isUvvis, - isXRD + isXRD, + isLCMs } = extractLayout(forecast, layoutSt); if (showForecast) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_forecast_viewer.default, { @@ -76,6 +80,16 @@ const Content = ({ isHidden: false }); } + if (isLCMs) { + 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, diff --git a/dist/layer_init.js b/dist/layer_init.js index 84ef3c26..6a1ee548 100644 --- a/dist/layer_init.js +++ b/dist/layer_init.js @@ -17,8 +17,11 @@ var _meta = require("./actions/meta"); var _jcamp = require("./actions/jcamp"); var _layer_prism = _interopRequireDefault(require("./layer_prism")); var _format = _interopRequireDefault(require("./helpers/format")); +var _extractEntityLCMS = require("./helpers/extractEntityLCMS"); var _multi_jcamps_viewer = _interopRequireDefault(require("./components/multi_jcamps_viewer")); +var _hplc_viewer = _interopRequireDefault(require("./components/hplc_viewer")); var _curve = require("./actions/curve"); +var _hplc_ms = require("./actions/hplc_ms"); var _ui = require("./actions/ui"); var _jsxRuntime = require("react/jsx-runtime"); /* eslint-disable prefer-object-spread, default-param-last */ @@ -29,6 +32,18 @@ const hasActiveZoom = sweepExtent => { }; const styles = () => ({}); class LayerInit extends _react.default.Component { + static entitySignature(e) { + if (!e) return 'none'; + const id = e.idDt ?? e.id ?? e.datasetId; + if (id != null && id !== '') return `id:${id}`; + const firstFeature = (Array.isArray(e.features) ? e.features[0] : null) || (Array.isArray(e.spectra) ? e.spectra[0] : null) || null; + const data0 = firstFeature?.data?.[0]; + const xs = data0?.x; + const xLen = Array.isArray(xs) ? xs.length : 0; + const xHead = Array.isArray(xs) && xs.length > 0 ? xs[0] : ''; + const xTail = Array.isArray(xs) && xs.length > 0 ? xs[xs.length - 1] : ''; + return `sig:${e.layout || ''}|${e.title || ''}|${xLen}|${xHead}|${xTail}`; + } constructor(props) { super(props); const { @@ -59,20 +74,39 @@ class LayerInit extends _react.default.Component { } componentDidUpdate(prevProps) { const { + others, multiEntities, - entity + entity, + operations } = this.props; this.normChange(prevProps); - this.updateOthers(); + if (prevProps.operations !== operations || prevProps.entity !== entity) { + this.initReducer(); + } + if (prevProps.others !== others) { + this.updateOthers(); + } if (prevProps.multiEntities !== multiEntities || prevProps.entity !== entity) { this.updateMultiEntities(false); } } normChange(prevProps) { const { - entity + entity, + multiEntities, + clearHplcMsStateAct } = this.props; if (prevProps.entity !== entity) { + const prevIsLcms = _format.default.isLCMsLayout(prevProps.entity?.layout); + const nextIsLcms = _format.default.isLCMsLayout(entity?.layout); + const lcmsSessionActive = prevIsLcms && nextIsLcms && Array.isArray(multiEntities) && (0, _extractEntityLCMS.isLcMsGroup)(multiEntities); + if ((prevIsLcms || nextIsLcms) && !lcmsSessionActive) { + const prevSig = LayerInit.entitySignature(prevProps.entity); + const nextSig = LayerInit.entitySignature(entity); + if (prevSig !== nextSig) { + clearHplcMsStateAct(); + } + } this.execReset(); } } @@ -89,11 +123,12 @@ class LayerInit extends _react.default.Component { updateDSCMetaDataAct, resetMultiplicityAct } = this.props; + if (!entity || !entity.layout) return; resetInitCommonAct(); resetDetectorAct(); const { layout, - features + features = {} } = entity; // Sync the layout deterministically on every spectrum open. Otherwise it // only updates via the d3 RESETALL, which can be skipped (active zoom or @@ -140,14 +175,18 @@ class LayerInit extends _react.default.Component { operations, updateOperationAct } = this.props; - updateOperationAct(operations[0]); + if (Array.isArray(operations) && operations.length > 0) { + updateOperationAct(operations[0]); + } } updateOthers() { const { others, addOthersAct } = this.props; - addOthersAct(others); + if (others) { + addOthersAct(others); + } } buildSetAllCurvesPayload(entities, isInitial) { const { @@ -167,9 +206,37 @@ class LayerInit extends _react.default.Component { setAllCurvesAct, entity } = this.props; + if (!entity || !entity.layout) return; + const lcmsCurveMeta = () => { + const uvvisFromMulti = Array.isArray(multiEntities) ? multiEntities.find(e => (0, _extractEntityLCMS.getLcMsInfo)(e).kind === 'uvvis') : null; + const mzFromMulti = Array.isArray(multiEntities) ? multiEntities.find(e => (0, _extractEntityLCMS.getLcMsInfo)(e).kind === 'mz') : null; + const idDt = uvvisFromMulti?.idDt ?? uvvisFromMulti?.id ?? uvvisFromMulti?.datasetId ?? entity?.idDt ?? entity?.id ?? entity?.datasetId ?? null; + const lcmsUvvisWavelength = entity?.lcms_uvvis_wavelength ?? entity?.lcmsUvvisWavelength ?? uvvisFromMulti?.lcms_uvvis_wavelength ?? uvvisFromMulti?.lcmsUvvisWavelength; + const lcmsMzPage = entity?.lcms_mz_page ?? entity?.lcmsMzPage ?? mzFromMulti?.lcms_mz_page ?? mzFromMulti?.lcmsMzPage ?? uvvisFromMulti?.lcms_mz_page ?? uvvisFromMulti?.lcmsMzPage; + const mzInfo = mzFromMulti ? (0, _extractEntityLCMS.getLcMsInfo)(mzFromMulti) : null; + const lcmsPolarity = entity?.lcms_polarity ?? entity?.lcmsPolarity ?? entity?.ticPolarity ?? mzFromMulti?.lcms_polarity ?? mzFromMulti?.lcmsPolarity ?? (mzInfo?.kind === 'mz' ? mzInfo.polarity : null); + const out = {}; + if (idDt != null) out.idDt = idDt; + if (lcmsUvvisWavelength != null && lcmsUvvisWavelength !== '') { + out.lcmsUvvisWavelength = lcmsUvvisWavelength; + } + if (lcmsMzPage != null && lcmsMzPage !== '') { + out.lcmsMzPage = lcmsMzPage; + } + if (lcmsPolarity != null && lcmsPolarity !== '') { + out.lcmsPolarity = lcmsPolarity; + } + return Object.keys(out).length ? out : undefined; + }; const isMultiSpectra = Array.isArray(multiEntities) && multiEntities.length > 1; if (isMultiSpectra) { - setAllCurvesAct(this.buildSetAllCurvesPayload(multiEntities, isInitial)); + const meta = _format.default.isLCMsLayout(entity.layout) ? lcmsCurveMeta() : undefined; + setAllCurvesAct(this.buildSetAllCurvesPayload(multiEntities, isInitial), meta); + return; + } + if (_format.default.isLCMsLayout(entity.layout)) { + const entities = Array.isArray(multiEntities) && multiEntities.length > 0 ? multiEntities : [entity]; + setAllCurvesAct(this.buildSetAllCurvesPayload(entities, isInitial), lcmsCurveMeta()); return; } if (_format.default.isCyclicVoltaLayout(entity.layout)) { @@ -195,15 +262,35 @@ class LayerInit extends _react.default.Component { onDescriptionChanged, multiEntities, entityFileNames, - userManualLink + userManualLink, + onLcmsPageRequest } = 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 hasMultiEntities = Array.isArray(multiEntities) && multiEntities.length > 0; + const hasLcmsEntity = hasMultiEntities && multiEntities.some(multiEntity => _format.default.isLCMsLayout(multiEntity?.layout)); + const isDetectedLcmsGroup = hasLcmsEntity && (0, _extractEntityLCMS.isLcMsGroup)(multiEntities); + // For multi mode, trust multiEntities over single entity to avoid mixed-layout misrouting. + const isLcms = hasMultiEntities ? isDetectedLcmsGroup : _format.default.isLCMsLayout(layout); + const target = isLcms ? null : entity.spectra && Array.isArray(entity.spectra) && entity.spectra[0] || null; + const xxLabel = !xLabel && xLabel === '' && target && target.xUnit ? `X (${target.xUnit})` : xLabel; + const yyLabel = !yLabel && yLabel === '' && target && target.yUnit ? `Y (${target.yUnit})` : yLabel; const isMultiSpectra = Array.isArray(multiEntities) && multiEntities.length > 1; + if (isLcms) { + return /*#__PURE__*/(0, _jsxRuntime.jsx)(_hplc_viewer.default, { + entityFileNames: entityFileNames, + userManualLink: userManualLink, + molSvg: molSvg, + forecast: forecast, + operations: operations, + descriptions: descriptions, + canChangeDescription: canChangeDescription, + onDescriptionChanged: onDescriptionChanged, + editorOnly: editorOnly, + onLcmsPageRequest: onLcmsPageRequest + }); + } if (isMultiSpectra) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_multi_jcamps_viewer.default, { multiEntities: multiEntities, @@ -211,6 +298,8 @@ class LayerInit extends _react.default.Component { userManualLink: userManualLink, molSvg: molSvg, exactMass: exactMass, + forecast: forecast, + editorOnly: editorOnly, operations: operations, descriptions: descriptions, canChangeDescription: canChangeDescription, @@ -224,6 +313,8 @@ class LayerInit extends _react.default.Component { userManualLink: userManualLink, molSvg: molSvg, exactMass: exactMass, + forecast: forecast, + editorOnly: editorOnly, operations: operations, descriptions: descriptions, canChangeDescription: canChangeDescription, @@ -241,6 +332,8 @@ class LayerInit extends _react.default.Component { molSvg: molSvg, editorOnly: editorOnly, exactMass: exactMass, + entityFileNames: entityFileNames, + userManualLink: userManualLink, canChangeDescription: canChangeDescription, onDescriptionChanged: onDescriptionChanged }); @@ -262,6 +355,7 @@ const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({ addOthersAct: _jcamp.addOthers, setAllCurvesAct: _curve.setAllCurves, updateDSCMetaDataAct: _meta.updateDSCMetaData, + clearHplcMsStateAct: _hplc_ms.clearHplcMsState, restoreSweepExtentAct: _ui.restoreSweepExtent }, dispatch); LayerInit.defaultProps = { @@ -299,12 +393,17 @@ LayerInit.propTypes = { canChangeDescription: _propTypes.default.bool.isRequired, onDescriptionChanged: _propTypes.default.func, // eslint-disable-line + onLcmsPageRequest: _propTypes.default.func, 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 + updateDSCMetaDataAct: _propTypes.default.func.isRequired, + clearHplcMsStateAct: _propTypes.default.func.isRequired +}; +LayerInit.defaultProps = { + onLcmsPageRequest: null }; var _default = exports.default = (0, _reactRedux.connect)( // eslint-disable-line diff --git a/dist/layer_prism.js b/dist/layer_prism.js index 7680524a..07650926 100644 --- a/dist/layer_prism.js +++ b/dist/layer_prism.js @@ -22,6 +22,13 @@ react/function-component-definition, react/require-default-props */ const styles = () => ({}); +const getThresholdState = state => { + const curveIdx = state?.curve?.curveIdx; + const thresholdList = state?.threshold?.list; + if (!Array.isArray(thresholdList)) return {}; + if (!Number.isInteger(curveIdx)) return thresholdList[0] || {}; + return thresholdList[curveIdx] || thresholdList[0] || {}; +}; const LayerPrism = ({ entity, cLabel, @@ -36,16 +43,25 @@ const LayerPrism = ({ thresSt, scanSt, uiSt, + curveSt, + integrationSt, canChangeDescription, - onDescriptionChanged + onDescriptionChanged, + entityFileNames, + userManualLink }) => { const { topic, feature, hasEdit, - integration + integration: initialIntegration, + features } = (0, _extractParams.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; @@ -67,6 +83,7 @@ const LayerPrism = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_content.default, { topic: topic, feature: feature, + features: features || [], cLabel: cLabel, xLabel: xLabel, yLabel: yLabel, @@ -95,6 +112,7 @@ const LayerPrism = ({ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_layer_content.default, { topic: topic, feature: feature, + features: features || [], cLabel: cLabel, xLabel: xLabel, yLabel: yLabel, @@ -111,6 +129,8 @@ const LayerPrism = ({ editorOnly: editorOnly, molSvg: molSvg, exactMass: exactMass, + entityFileNames: entityFileNames, + userManualLink: userManualLink, descriptions: descriptions, canChangeDescription: canChangeDescription, onDescriptionChanged: onDescriptionChanged @@ -124,8 +144,10 @@ const mapStateToProps = (state, props) => ( // eslint-disable-line { scanSt: state.scan, - thresSt: state.threshold.list[state.curve.curveIdx], - uiSt: state.ui + thresSt: getThresholdState(state), + uiSt: state.ui, + curveSt: state.curve, + integrationSt: state.integration.present }); const mapDispatchToProps = dispatch => (0, _redux.bindActionCreators)({}, dispatch); LayerPrism.propTypes = { @@ -142,8 +164,12 @@ LayerPrism.propTypes = { thresSt: _propTypes.default.object.isRequired, scanSt: _propTypes.default.object.isRequired, uiSt: _propTypes.default.object.isRequired, + curveSt: _propTypes.default.object.isRequired, + integrationSt: _propTypes.default.object.isRequired, canChangeDescription: _propTypes.default.bool.isRequired, - onDescriptionChanged: _propTypes.default.func + onDescriptionChanged: _propTypes.default.func, + entityFileNames: _propTypes.default.array, + userManualLink: _propTypes.default.object }; var _default = exports.default = (0, _reactRedux.connect)( // eslint-disable-line diff --git a/dist/reducers/index.js b/dist/reducers/index.js index 50868a3b..6217cadb 100644 --- a/dist/reducers/index.js +++ b/dist/reducers/index.js @@ -26,6 +26,7 @@ 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")); +var _reducer_hplc_ms = _interopRequireDefault(require("./reducer_hplc_ms")); const rootReducer = (0, _redux.combineReducers)({ threshold: _reducer_threshold.default, editPeak: _reducer_edit_peak.default, @@ -46,6 +47,7 @@ const rootReducer = (0, _redux.combineReducers)({ cyclicvolta: _reducer_voltammetry.default, curve: _reducer_curve.default, axesUnits: _reducer_axes.default, - detector: _reducer_detector.default + detector: _reducer_detector.default, + hplcMs: _reducer_hplc_ms.default }); var _default = exports.default = rootReducer; \ No newline at end of file diff --git a/dist/reducers/reducer_curve.js b/dist/reducers/reducer_curve.js index 509dae76..8137fe4d 100644 --- a/dist/reducers/reducer_curve.js +++ b/dist/reducers/reducer_curve.js @@ -7,6 +7,8 @@ Object.defineProperty(exports, "__esModule", { exports.default = void 0; var _action_type = require("../constants/action_type"); var _extractParams = require("../helpers/extractParams"); +var _extractEntityLCMS = require("../helpers/extractEntityLCMS"); +var _list_layout = require("../constants/list_layout"); var _chem = require("../helpers/chem"); var _format = _interopRequireDefault(require("../helpers/format")); /* eslint-disable prefer-object-spread, default-param-last, max-len */ @@ -46,47 +48,63 @@ const resolveCurveIdx = (entitiesLength, state, explicitIdx) => { }; const setAllCurves = (state, action) => { const { - entities, + entities: payloadEntities, curveIdx: explicitIdx } = normalizeSetAllCurvesPayload(action.payload); - if (entities) { - const listCurves = entities.map((entity, idx) => { - const { - topic, - feature, - hasEdit, - integration, - multiplicity - } = (0, _extractParams.extractParams)(entity, { - isEdit: true - }); - 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 - }; - }); - const curveIdx = resolveCurveIdx(entities.length, state, explicitIdx); - return Object.assign({}, state, { - curveIdx, - listCurves - }); - } - return Object.assign({}, state, { + const payload = payloadEntities ?? action.payload; + if (!payload) return { + ...state, curveIdx: 0, - listCurves: entities + listCurves: [] + }; + const isLcmsGroup = (0, _extractEntityLCMS.isLcMsGroup)(payload); + const entities = payload.map((entity, idx) => { + const lcmsInfo = (0, _extractEntityLCMS.getLcMsInfo)(entity); + const layout = isLcmsGroup && lcmsInfo.kind !== 'unknown' ? _list_layout.LIST_LAYOUT.LC_MS : entity.layout; + const extracted = (0, _extractParams.extractParams)(entity, { + isEdit: true + }, null, { + forceLcms: isLcmsGroup && lcmsInfo.kind !== 'unknown' + }); + const { + topic, + feature, + hasEdit, + integration, + multiplicity, + features, + entity: entityFromExtract, + spectra + } = extracted; + let finalFeatures = features; + if (!finalFeatures || Array.isArray(finalFeatures) && finalFeatures.length === 0) { + finalFeatures = entityFromExtract?.features || entity.features || []; + } + const maxminPeak = (0, _chem.Convert2MaxMinPeak)(layout, feature, 0); + const color = _format.default.mutiEntitiesColors(idx); + return { + layout, + lcmsKind: lcmsInfo.kind, + lcmsPolarity: lcmsInfo.polarity, + topic, + feature, + hasEdit, + integration, + multiplicity, + maxminPeak, + color, + curveIdx: idx, + features: finalFeatures, + entity: entityFromExtract || entity, + spectra: spectra || entity.spectra + }; }); + const curveIdx = resolveCurveIdx(entities.length, state, explicitIdx); + return { + ...state, + curveIdx, + listCurves: entities + }; }; const curveReducer = (state = initialState, action) => { switch (action.type) { diff --git a/dist/reducers/reducer_integration.js b/dist/reducers/reducer_integration.js index c65ce516..43c657ce 100644 --- a/dist/reducers/reducer_integration.js +++ b/dist/reducers/reducer_integration.js @@ -37,7 +37,7 @@ const addToStack = (state, action) => { integrations } = state; let selectedIntegration = integrations[curveIdx]; - if (selectedIntegration === false || selectedIntegration === undefined) { + if (!selectedIntegration) { selectedIntegration = defaultEmptyIntegration; } const { @@ -53,7 +53,7 @@ const addToStack = (state, action) => { xL, xU } = xExtent; - if (!xL || !xU || xU - xL === 0) { + if (!Number.isFinite(xL) || !Number.isFinite(xU) || xU - xL === 0) { return state; } const area = (0, _integration.getArea)(xL, xU, data); @@ -76,6 +76,22 @@ const addToStack = (state, action) => { 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, @@ -94,16 +110,251 @@ const rmFromStack = (state, action) => { 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 [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 = (0, _integration.splitAreaProportionally)(original.area, (0, _integration.getArea)(xL, splitX, data), (0, _integration.getArea)(splitX, xU, data)); + const absParts = (0, _integration.splitAreaProportionally)(original.absoluteArea, (0, _integration.getAbsoluteArea)(xL, splitX, data), (0, _integration.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, (0, _integration.getArea)(xL, xU, data), (0, _integration.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) { + 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 splitParts = buildSplitParts(original, xL, splitX, xU, shift, data, stack); + const [leftIntegration, rightIntegration] = splitParts; + 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) { + 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 = (0, _integration.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) { + 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 }); @@ -221,6 +472,12 @@ const integrationReducer = (state = initialState, action) => { 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.ADD_VISUAL_SPLIT: + return addVisualSplitLine(state, action); + case _action_type.INTEGRATION.RM_VISUAL_SPLIT: + return removeVisualSplitLine(state, action); case _action_type.INTEGRATION.SET_REF: return setRef(state, action); case _action_type.INTEGRATION.SET_FKR: diff --git a/dist/reducers/reducer_layout.js b/dist/reducers/reducer_layout.js index c264e570..6b0db6e1 100644 --- a/dist/reducers/reducer_layout.js +++ b/dist/reducers/reducer_layout.js @@ -14,7 +14,7 @@ const layoutReducer = (state = initialState, action) => { case _action_type.LAYOUT.UPDATE: return action.payload; case _action_type.MANAGER.RESETALL: - return action.payload.operation.layout; + return action.payload?.operation?.layout || state; default: return state; } diff --git a/dist/reducers/reducer_submit.js b/dist/reducers/reducer_submit.js index 6fc47bf8..7d166344 100644 --- a/dist/reducers/reducer_submit.js +++ b/dist/reducers/reducer_submit.js @@ -45,7 +45,8 @@ const submitReducer = (state = initialState, action) => { } case _action_type.MANAGER.RESETALL: { - const decimal = _format.default.spectraDigit(action.payload.operation.layout); + const layout = action.payload?.operation?.layout; + const decimal = layout ? _format.default.spectraDigit(layout) : state.decimal; return Object.assign({}, state, { decimal, isIntensity: true, diff --git a/dist/reducers/reducer_ui.js b/dist/reducers/reducer_ui.js index 14b7533f..db00437d 100644 --- a/dist/reducers/reducer_ui.js +++ b/dist/reducers/reducer_ui.js @@ -15,7 +15,137 @@ const initialState = { xExtent: false, yExtent: false }, - jcampIdx: 0 + jcampIdx: 0, + subViewerAt: { + x: null, + y: null + }, + zoom: { + graphIndex: 0, + sweepExtent: [{ + xExtent: false, + yExtent: false + }, { + xExtent: false, + yExtent: false + }, { + xExtent: false, + yExtent: false + }], + sweepTypes: [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET] + } +}; +const updateSweepType = (state, action) => { + const { + payload + } = action; + const { + graphIndex, + sweepType + } = payload; + if (!sweepType) { + return Object.assign({}, state, { + sweepType: action.payload, + jcampIdx: action.jcampIdx, + zoom: { + ...state.zoom, + sweepTypes: [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET] + } + }); + } + const { + zoom + } = state; + let newSweepTypes = zoom.sweepTypes.slice(); + if (sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN) { + newSweepTypes = newSweepTypes.map((val, idx) => idx === graphIndex ? _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN : _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET); + } else { + newSweepTypes = newSweepTypes.map(() => _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET); + if (graphIndex !== undefined) { + newSweepTypes[graphIndex] = sweepType; + } + } + const newZoom = Object.assign({}, zoom, { + sweepTypes: newSweepTypes, + graphIndex + }); + return Object.assign({}, state, { + zoom: newZoom, + sweepType + }); +}; +const updateZoom = (state, action) => { + const { + payload + } = action; + const { + graphIndex, + zoomValue, + lcmsSyncX + } = payload; + if (!zoomValue) { + return Object.assign({}, state, { + sweepExtent: payload + }); + } + const { + zoom + } = state; + const sweepExtent = Array.isArray(zoom.sweepExtent) ? [...zoom.sweepExtent] : []; + const selectedGraph = sweepExtent[graphIndex]; + const newSweepExtent = Object.assign({}, selectedGraph, zoomValue); + sweepExtent[graphIndex] = newSweepExtent; + if (lcmsSyncX != null && zoomValue && zoomValue.xExtent) { + const otherIdx = lcmsSyncX; + const otherGraph = sweepExtent[otherIdx] || {}; + sweepExtent[otherIdx] = Object.assign({}, otherGraph, { + xExtent: zoomValue.xExtent, + yExtent: false + }); + } + const newZoom = Object.assign({}, zoom, { + sweepExtent, + graphIndex + }); + return Object.assign({}, state, { + zoom: newZoom + }); +}; +const resetZoom = (state, action) => { + const { + payload + } = action; + const { + graphIndex + } = payload || {}; + if (graphIndex === undefined) { + return Object.assign({}, state, { + sweepExtent: { + xExtent: false, + yExtent: false + } + }); + } + const { + zoom + } = state; + const sweepExtent = Array.isArray(zoom.sweepExtent) ? [...zoom.sweepExtent] : []; + const indicesToReset = graphIndex === 0 || graphIndex === 1 ? [0, 1] : [graphIndex]; + indicesToReset.forEach(idx => { + const selectedGraph = sweepExtent[idx] || {}; + sweepExtent[idx] = Object.assign({}, selectedGraph, { + xExtent: false, + yExtent: false + }); + }); + return Object.assign({}, state, { + zoom: { + sweepExtent, + graphIndex, + sweepTypes: [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET] + }, + sweepType: _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET + }); }; const uiReducer = (state = initialState, action) => { switch (action.type) { @@ -24,21 +154,27 @@ const uiReducer = (state = initialState, action) => { 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 - } - }); + if (action.payload.sweepType === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET || action.payload === _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET) { + // return Object.assign({}, state, { + // sweepExtent: { xExtent: false, yExtent: false }, + // }); + return resetZoom(state, action); } - return Object.assign({}, state, { - sweepType: action.payload, - jcampIdx: action.jcampIdx - }); + // return Object.assign({}, state, { + // sweepType: action.payload, + // jcampIdx: action.jcampIdx, + // }); + return updateSweepType(state, action); case _action_type.UI.SWEEP.SELECT_ZOOMIN: + { + // return Object.assign({}, state, { + // sweepExtent: action.payload, + // }); + return updateZoom(state, action); + } + case _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT: return Object.assign({}, state, { - sweepExtent: action.payload + subViewerAt: action.payload }); case _action_type.MANAGER.RESETALL: return initialState; diff --git a/dist/reducers/undo_redo_config.js b/dist/reducers/undo_redo_config.js index 7a8cfeaa..b1f61d03 100644 --- a/dist/reducers/undo_redo_config.js +++ b/dist/reducers/undo_redo_config.js @@ -6,11 +6,11 @@ Object.defineProperty(exports, "__esModule", { 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.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 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.ADD_VISUAL_SPLIT, _action_type.INTEGRATION.RM_VISUAL_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, + ignoreInitialState: false, 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] diff --git a/dist/sagas/saga_ui.js b/dist/sagas/saga_ui.js index cd98903c..6836bf83 100644 --- a/dist/sagas/saga_ui.js +++ b/dist/sagas/saga_ui.js @@ -3,13 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = void 0; +exports.shouldDisplayLcmsSubViewerAt = 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; +var _list_graph = require("../constants/list_graph"); +var _saga_lcms_ui = require("./saga_lcms_ui"); +const getUiState = state => state.ui; +const getCurveState = state => state.curve; +const getHplcMsState = state => state.hplcMs; +const getSubViewZoomActionType = () => _action_type.UI.SWEEP.SELECT_ZOOMIN_SUBVIEW || _action_type.UI.SWEEP.SELECT_ZOOMIN; const calcPeaks = payload => { const { xExtent, @@ -28,76 +32,110 @@ const calcPeaks = payload => { const peaks = dataPks.filter(p => xL <= p.x && p.x <= xU && yL <= p.y && p.y <= yU); return peaks; }; +const getLayoutState = state => state.layout; function* selectUiSweep(action) { - const uiSt = yield (0, _effects.select)(getUiSt); + const uiState = yield (0, _effects.select)(getUiState); + const { + sweepType, + zoom + } = uiState; const { payload } = action; - const curveSt = yield (0, _effects.select)(getCurveSt); + const curveState = yield (0, _effects.select)(getCurveState); const { curveIdx - } = curveSt; - switch (uiSt.sweepType) { + } = curveState; + const hplcMsState = yield (0, _effects.select)(getHplcMsState); + const { + uvvis + } = hplcMsState; + const layoutState = yield (0, _effects.select)(getLayoutState); + switch (sweepType) { case _list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN: - yield (0, _effects.put)({ - type: _action_type.UI.SWEEP.SELECT_ZOOMIN, - payload - }); + if (layoutState === _list_layout.LIST_LAYOUT.LC_MS && uvvis.listWaveLength) { + yield* (0, _saga_lcms_ui.lcmsHandleSelectZoomIn)({ + payload, + zoom + }); + } else { + 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 - }); + if (layoutState === _list_layout.LIST_LAYOUT.LC_MS && (payload?.graphIndex === 0 || payload?.graphIndex === 1)) { + yield* (0, _saga_lcms_ui.lcmsHandleSelectZoomReset)(); + } else { + 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 + { + if (uvvis.selectedWaveLength && layoutState === _list_layout.LIST_LAYOUT.LC_MS) { + yield* (0, _saga_lcms_ui.lcmsHandleIntegrationAdd)({ + uvvis, + payload + }); + } else { + 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 + case _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_SWEEP_ADD: + { + const peaks = calcPeaks(payload); // eslint-disable-line + if (peaks.length === 0) { + break; } - }); - break; + const newPayload = { + ...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 layoutState = yield (0, _effects.select)(getLayoutState); const { payload } = action; + if (!payload?.xExtent || !payload?.yExtent) return; const { xExtent, yExtent, - direction + direction, + brushClass } = payload; const { yL, @@ -110,7 +148,7 @@ function* scrollUiWheel(action) { yExtent: false }; let [nyeL, nyeU, h, nytL, nytU] = [0, 1, 1, 0, 1]; - switch (layoutSt) { + switch (layoutState) { case _list_layout.LIST_LAYOUT.IR: case _list_layout.LIST_LAYOUT.RAMAN: [nyeL, nyeU] = [yeL + (yeU - yeL) * (1 - scale), yeU]; @@ -154,42 +192,95 @@ function* scrollUiWheel(action) { }; break; } - yield (0, _effects.put)({ - type: _action_type.UI.SWEEP.SELECT_ZOOMIN, - payload: nextExtent - }); + if (brushClass === `.${_list_graph.LIST_BRUSH_SVG_GRAPH.RECT}`) { + yield (0, _effects.put)({ + type: getSubViewZoomActionType(), + payload: nextExtent + }); + } else { + yield (0, _effects.put)({ + type: _action_type.UI.SWEEP.SELECT_ZOOMIN, + payload: nextExtent + }); + } } const getUiSweepType = state => state.ui.sweepType; +const shouldDisplayLcmsSubViewerAt = ({ + isLcmsLayout, + payload, + sourceHint, + uiSweepType +}) => isLcmsLayout && sourceHint === 'lcms_tic' && Number.isFinite(payload?.x) && [_list_ui.LIST_UI_SWEEP_TYPE.ZOOMIN, _list_ui.LIST_UI_SWEEP_TYPE.ZOOMRESET, _list_ui.LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT].includes(uiSweepType); +exports.shouldDisplayLcmsSubViewerAt = shouldDisplayLcmsSubViewerAt; function* clickUiTarget(action) { const { payload, onPeak, voltammetryPeakIdx, onPecker, + sourceHint, jcampIdx } = action; const uiSweepType = yield (0, _effects.select)(getUiSweepType); - const curveSt = yield (0, _effects.select)(getCurveSt); + const curveState = yield (0, _effects.select)(getCurveState); const { curveIdx - } = curveSt; + } = curveState; const targetCurveIdx = Number.isFinite(jcampIdx) ? jcampIdx : curveIdx; - if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD && !onPeak) { + const hplcMsState = yield (0, _effects.select)(getHplcMsState); + const { + uvvis + } = hplcMsState; + const isLcmsLayout = (yield (0, _effects.select)(getLayoutState)) === _list_layout.LIST_LAYOUT.LC_MS; + if (shouldDisplayLcmsSubViewerAt({ + isLcmsLayout, + payload, + sourceHint, + uiSweepType + })) { yield (0, _effects.put)({ - type: _action_type.EDITPEAK.ADD_POSITIVE, - payload: { - dataToAdd: payload, - curveIdx: targetCurveIdx - } + type: _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT, + payload }); + return; + } + if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_ADD && !onPeak) { + const spectrumId = hplcMsState?.uvvis?.selectedWaveLength; + if (isLcmsLayout && spectrumId == null) return; + const currentPeaks = hplcMsState?.uvvis?.currentSpectrum?.peaks || []; + const updatedPeaks = [...currentPeaks, payload]; + if (isLcmsLayout && spectrumId != null) { + yield (0, _effects.put)({ + type: _action_type.HPLC_MS.UPDATE_HPLCMS_PEAKS, + payload: { + spectrumId, + peaks: updatedPeaks + } + }); + } else { + yield (0, _effects.put)({ + type: _action_type.EDITPEAK.ADD_POSITIVE, + payload: { + dataToAdd: payload, + curveIdx: targetCurveIdx + } + }); + } } 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: targetCurveIdx - } - }); + if (isLcmsLayout && uvvis.selectedWaveLength) { + yield* (0, _saga_lcms_ui.lcmsHandlePeakDelete)({ + uvvis, + payload + }); + } else { + yield (0, _effects.put)({ + type: _action_type.EDITPEAK.ADD_NEGATIVE, + payload: { + dataToAdd: payload, + curveIdx: targetCurveIdx + } + }); + } } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.ANCHOR_SHIFT && onPeak) { yield (0, _effects.put)({ type: _action_type.SHIFT.SET_PEAK, @@ -199,13 +290,20 @@ function* clickUiTarget(action) { } }); } 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: targetCurveIdx - } - }); + if (uvvis.selectedWaveLength && isLcmsLayout) { + yield* (0, _saga_lcms_ui.lcmsHandleIntegrationRm)({ + uvvis, + payload + }); + } else { + yield (0, _effects.put)({ + type: _action_type.INTEGRATION.RM_ONE, + payload: { + dataToRemove: payload, + curveIdx: targetCurveIdx + } + }); + } } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.MULTIPLICITY_ONE_RM && onPeak) { yield (0, _effects.put)({ type: _action_type.INTEGRATION.RM_ONE, @@ -317,6 +415,11 @@ function* clickUiTarget(action) { jcampIdx: targetCurveIdx } }); + } else if (uiSweepType === _list_ui.LIST_UI_SWEEP_TYPE.PEAK_GROUP_SELECT) { + yield (0, _effects.put)({ + type: _action_type.UI.SUB_VIEWER.DISPLAY_VIEWER_AT, + payload + }); } } 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)]; diff --git a/dist/setupTests.js b/dist/setupTests.js index fc453d7d..859d0d6e 100644 --- a/dist/setupTests.js +++ b/dist/setupTests.js @@ -1,8 +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() +const Enzyme = require('enzyme'); +const AdapterModule = require('@wojtekmaj/enzyme-adapter-react-17'); +const Adapter = AdapterModule.default || AdapterModule; +Enzyme.configure({ + adapter: new Adapter() }); \ No newline at end of file diff --git a/src/components/cmd_bar/03_peak.js b/src/components/cmd_bar/03_peak.js index c780e18c..921448f9 100644 --- a/src/components/cmd_bar/03_peak.js +++ b/src/components/cmd_bar/03_peak.js @@ -107,7 +107,7 @@ const Peak = ({ 'btn-sv-bar-rmpeak', ) } - onClick={onSweepPeakDELETE} + onClick={onSweepPeakDelete} > P- diff --git a/src/components/panel/info.js b/src/components/panel/info.js index 6b86e303..3a105c36 100644 --- a/src/components/panel/info.js +++ b/src/components/panel/info.js @@ -265,7 +265,7 @@ const InfoPanel = ({ classes, expand, feature, integration, editorOnly, molSvg, descriptions, layoutSt, simulationSt, shiftSt, curveSt, exactMass, onExpand, canChangeDescription, onDescriptionChanged, detectorSt, - metaSt, updateDSCMetaDataAct, hplcMsSt, entities, + metaSt, updateDSCMetaDataAct, entities, }) => { if (!feature) return null; const msExactMass = Format.isMsLayout(layoutSt) && exactMass @@ -457,7 +457,7 @@ const InfoPanel = ({ marginBottom: '100px', }} > - {aucValue(integration, hplcMsSt) + {Format.formatHplcAucPanel(integration, feature) .split('\n') .map((line, idx) => (
{line}
@@ -510,7 +510,6 @@ InfoPanel.propTypes = { detectorSt: PropTypes.object.isRequired, metaSt: PropTypes.object.isRequired, updateDSCMetaDataAct: PropTypes.func.isRequired, - hplcMsSt: PropTypes.object.isRequired, entities: PropTypes.array, }; diff --git a/src/helpers/chem.js b/src/helpers/chem.js index 94e082c2..0ad74155 100644 --- a/src/helpers/chem.js +++ b/src/helpers/chem.js @@ -6,7 +6,6 @@ import Jcampconverter from 'jcampconverter'; import { createSelector } from 'reselect'; import { shiftOffsetAtIndex } from './shift'; -import Cfg from './cfg'; import Format from './format'; import { LIST_LAYOUT } from '../constants/list_layout'; import { getArea } from './integration';