diff --git a/src/components/cmd_bar/r05_submit_btn.js b/src/components/cmd_bar/r05_submit_btn.js index c1c21491..a3f6db3b 100644 --- a/src/components/cmd_bar/r05_submit_btn.js +++ b/src/components/cmd_bar/r05_submit_btn.js @@ -16,6 +16,7 @@ import { } from '../../helpers/chem'; import { MuButton, commonStyle } from './common'; import { extractPeaksEdit, extractAreaUnderCurve } from '../../helpers/extractPeaksEdit'; +import Format from '../../helpers/format'; const styles = () => ( Object.assign( @@ -64,7 +65,7 @@ const BtnSubmit = ({ }) => { const peaksEdit = extractPeaksEdit(feature, editPeakSt, thresSt, shiftSt, layoutSt); // const disBtn = peaksEdit.length === 0 || statusSt.btnSubmit || disabled; - const scan = Convert2Scan(feature, scanSt); + const scan = Format.isMsLayout(layoutSt) ? Convert2Scan(feature, scanSt) : 0; const thres = Convert2Thres(feature, thresSt); const aucValues = extractAreaUnderCurve(allIntegrationSt, integrationSt, layoutSt); const { dscMetaData } = metaSt; diff --git a/src/components/cmd_bar/r06_predict_btn.js b/src/components/cmd_bar/r06_predict_btn.js index 18d4e3a1..73e97609 100644 --- a/src/components/cmd_bar/r06_predict_btn.js +++ b/src/components/cmd_bar/r06_predict_btn.js @@ -208,7 +208,7 @@ const BtnPredict = ({ const oriPeaksEdit = extractPeaksEdit(feature, editPeakSt, thresSt, shiftSt, layoutSt); const peaksEdit = Format.rmShiftFromPeaks(oriPeaksEdit, shiftSt); - const scan = Convert2Scan(feature, scanSt); + const scan = Format.isMsLayout(layoutSt) ? Convert2Scan(feature, scanSt) : 0; const thres = Convert2Thres(feature, thresSt); const simuCount = simulationSt.nmrSimPeaks.length; const uniqCount = [...new Set(simulationSt.nmrSimPeaks)].length; diff --git a/src/components/d3_line_rect/index.js b/src/components/d3_line_rect/index.js index 7e48a209..6c8714a9 100644 --- a/src/components/d3_line_rect/index.js +++ b/src/components/d3_line_rect/index.js @@ -5,11 +5,12 @@ import { bindActionCreators } from 'redux'; import PropTypes from 'prop-types'; import { - Topic2Seed, Feature2Peak, ToThresEndPts, ToShiftPeaks, + Topic2Seed, ToThresEndPts, } from '../../helpers/chem'; import { resetAll } from '../../actions/manager'; import { selectUiSweep, scrollUiWheel, clickUiTarget } from '../../actions/ui'; -import RectFocus from './rect_focus'; +// import RectFocus from './rect_focus'; +import LineFocus from './line_focus'; import { drawMain, drawLabel, drawDisplay, drawDestroy, } from '../common/draw'; @@ -23,8 +24,8 @@ class ViewerLineRect extends React.Component { super(props); const { clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct } = props; - this.rootKlass = '.d3Rect'; - this.focus = new RectFocus({ + this.rootKlass = '.d3Line'; + this.focus = new LineFocus({ W, H, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, }); @@ -33,23 +34,22 @@ class ViewerLineRect extends React.Component { componentDidMount() { const { - seed, peak, cLabel, xLabel, yLabel, feature, - tTrEndPts, tSfPeaks, isHidden, + seed, cLabel, xLabel, yLabel, feature, + tTrEndPts, layoutSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, + isHidden, resetAllAct, } = this.props; drawDestroy(this.rootKlass); resetAllAct(feature); const filterSeed = seed; - const filterPeak = peak; drawMain(this.rootKlass, W, H); this.focus.create({ filterSeed, - filterPeak, tTrEndPts, - tSfPeaks, + layoutSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, @@ -60,24 +60,24 @@ class ViewerLineRect extends React.Component { componentDidUpdate(prevProps) { const { - seed, peak, - tTrEndPts, tSfPeaks, isHidden, + seed, cLabel, xLabel, yLabel, + tTrEndPts, layoutSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, + isHidden, } = this.props; this.normChange(prevProps); const filterSeed = seed; - const filterPeak = peak; this.focus.update({ filterSeed, - filterPeak, tTrEndPts, - tSfPeaks, + layoutSt, sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, }); + drawLabel(this.rootKlass, cLabel, xLabel, yLabel); drawDisplay(this.rootKlass, isHidden); } @@ -86,10 +86,10 @@ class ViewerLineRect extends React.Component { } normChange(prevProps) { - const { feature, resetAllAct } = this.props; + const { feature } = this.props; const oldFeature = prevProps.feature; if (oldFeature !== feature) { - resetAllAct(feature); + // resetAllAct(feature); } } @@ -106,9 +106,7 @@ class ViewerLineRect extends React.Component { const mapStateToProps = (state, props) => ( { seed: Topic2Seed(state, props), - peak: Feature2Peak(state, props), tTrEndPts: ToThresEndPts(state, props), - tSfPeaks: ToShiftPeaks(state, props), sweepExtentSt: state.ui.sweepExtent, isUiAddIntgSt: state.ui.sweepType === LIST_UI_SWEEP_TYPE.INTEGRATION_ADD, isUiNoBrushSt: LIST_NON_BRUSH_TYPES.indexOf(state.ui.sweepType) < 0, @@ -126,13 +124,12 @@ const mapDispatchToProps = (dispatch) => ( ViewerLineRect.propTypes = { seed: PropTypes.array.isRequired, - peak: PropTypes.array.isRequired, cLabel: PropTypes.string.isRequired, xLabel: PropTypes.string.isRequired, yLabel: PropTypes.string.isRequired, + layoutSt: PropTypes.string.isRequired, feature: PropTypes.object.isRequired, tTrEndPts: PropTypes.array.isRequired, - tSfPeaks: PropTypes.array.isRequired, sweepExtentSt: PropTypes.object.isRequired, isUiAddIntgSt: PropTypes.bool.isRequired, isUiNoBrushSt: PropTypes.bool.isRequired, diff --git a/src/components/d3_line_rect/line_focus.js b/src/components/d3_line_rect/line_focus.js new file mode 100644 index 00000000..756b1c0d --- /dev/null +++ b/src/components/d3_line_rect/line_focus.js @@ -0,0 +1,234 @@ +/* eslint-disable prefer-object-spread, no-mixed-operators */ +import { + InitScale, InitAxisCall, InitTip, +} from '../../helpers/init'; +import { + MountPath, MountGrid, MountAxis, MountAxisLabelX, MountAxisLabelY, + MountClip, MountMainFrame, MountTags, +} from '../../helpers/mount'; +import MountBrush from '../../helpers/brush'; +import { TfRescale, MountCompass } from '../../helpers/compass'; +import { LIST_LAYOUT } from '../../constants/list_layout'; + +const d3 = require('d3'); + +class LineFocus { + constructor(props) { + const { + W, H, clickUiTargetAct, selectUiSweepAct, scrollUiWheelAct, + } = props; + + this.jcampIdx = 0; + this.rootKlass = '.d3Line'; + this.margin = { + t: 5, + b: 40, + l: 60, + r: 5, + }; + this.w = W - this.margin.l - this.margin.r; + this.h = H - this.margin.t - this.margin.b; + this.clickUiTargetAct = clickUiTargetAct; + this.selectUiSweepAct = selectUiSweepAct; + this.scrollUiWheelAct = scrollUiWheelAct; + this.brush = d3.brush(); + this.brushX = d3.brushX(); + + this.axis = null; + this.path = null; + this.grid = null; + this.tags = null; + this.data = []; + this.tTrEndPts = null; + this.root = null; + this.svg = null; + this.axisCall = InitAxisCall(5); + this.pathCall = null; + this.tip = null; + this.factor = 0.125; + this.currentExtent = null; + this.shouldUpdate = {}; + this.layout = LIST_LAYOUT.H1; + + this.getShouldUpdate = this.getShouldUpdate.bind(this); + this.resetShouldUpdate = this.resetShouldUpdate.bind(this); + this.setTip = this.setTip.bind(this); + this.setDataParams = this.setDataParams.bind(this); + this.create = this.create.bind(this); + this.update = this.update.bind(this); + this.setConfig = this.setConfig.bind(this); + this.drawLine = this.drawLine.bind(this); + this.drawGrid = this.drawGrid.bind(this); + this.onClickTarget = this.onClickTarget.bind(this); + this.isFirefox = typeof InstallTrigger !== 'undefined'; + } + + getShouldUpdate() { + const { + prevXt, prevYt, prevLySt, + prevTePt, prevData, + } = this.shouldUpdate; + const { xt, yt } = TfRescale(this); + const sameXY = xt(1.1) === prevXt && prevYt === yt(1.1); + const sameLySt = prevLySt === this.layout; + const sameTePt = prevTePt === this.tTrEndPts.length; + const sameData = prevData === this.data.length; + this.shouldUpdate = Object.assign( + {}, + this.shouldUpdate, + { + sameXY, sameLySt, // eslint-disable-line + sameTePt, sameData, // eslint-disable-line + }, + ); + } + + resetShouldUpdate() { + const { xt, yt } = TfRescale(this); + const prevXt = xt(1.1); + const prevYt = yt(1.1); + const prevTePt = this.tTrEndPts.length; + const prevData = this.data.length; + const prevLySt = this.layout; + this.shouldUpdate = Object.assign( + {}, + this.shouldUpdate, + { + prevXt, prevYt, prevLySt, // eslint-disable-line + prevTePt, prevData, // eslint-disable-line + }, + ); + } + + setTip() { + this.tip = InitTip(); + this.root.call(this.tip); + } + + setDataParams(data, tTrEndPts, layout) { + this.data = [...data]; + this.tTrEndPts = tTrEndPts; + this.layout = layout; + } + + updatePathCall(xt, yt) { + this.pathCall = d3.line() + .x((d) => xt(d.x)) + .y((d) => yt(d.y)); + } + + setConfig(sweepExtentSt) { + // Domain Calculate + let { xExtent, yExtent } = sweepExtentSt || { xExtent: false, yExtent: false }; + + if (!xExtent || !yExtent) { + const xes = d3.extent(this.data, (d) => d.x).sort((a, b) => a - b); + xExtent = { xL: xes[0], xU: xes[1] }; + const btm = d3.min(this.data, (d) => d.y); + const top = d3.max(this.data, (d) => d.y); + const height = top - btm; + yExtent = { + yL: (btm - this.factor * height), + yU: (top + this.factor * height), + }; + } + + this.scales.x.domain([xExtent.xL, xExtent.xU]); + this.scales.y.domain([yExtent.yL, yExtent.yU]); + + // rescale for zoom + const { xt, yt } = TfRescale(this); + + // Axis Call + this.axisCall.x.scale(xt); + this.axisCall.y.scale(yt); + + this.currentExtent = { xExtent, yExtent }; + } + + drawLine() { + const { sameXY } = this.shouldUpdate; + if (sameXY) return; + + const { xt, yt } = TfRescale(this); + this.updatePathCall(xt, yt); + this.path.attr('d', this.pathCall(this.data)); + } + + drawGrid() { + const { sameXY } = this.shouldUpdate; + if (sameXY) return; + + this.grid.x.call(this.axisCall.x + .tickSize(-this.h, 0, 0)) + .selectAll('line') + .attr('stroke', '#ddd') + .attr('stroke-opacity', 0.6) + .attr('fill', 'none'); + this.grid.y.call(this.axisCall.y + .tickSize(-this.w, 0, 0)) + .selectAll('line') + .attr('stroke', '#ddd') + .attr('stroke-opacity', 0.6) + .attr('fill', 'none'); + } + + onClickTarget(event, data) { + event.stopPropagation(); + event.preventDefault(); + const onPeak = true; + this.clickUiTargetAct(data, onPeak); + } + + create({ + filterSeed, tTrEndPts, + layoutSt, + sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, + }) { + this.svg = d3.select('.d3Svg'); + MountMainFrame(this, 'focus'); + MountClip(this); + + this.root = d3.select(this.rootKlass).selectAll('.focus-main'); + this.scales = InitScale(this, false); + this.setTip(); + this.setDataParams(filterSeed, tTrEndPts, layoutSt); + MountCompass(this); + + this.axis = MountAxis(this); + this.path = MountPath(this, 'steelblue'); + this.grid = MountGrid(this); + this.tags = MountTags(this); + MountAxisLabelX(this); + MountAxisLabelY(this); + + if (this.data && this.data.length > 0) { + this.setConfig(sweepExtentSt); + this.drawLine(); + this.drawGrid(); + } + MountBrush(this, isUiAddIntgSt, isUiNoBrushSt); + this.resetShouldUpdate(); + } + + update({ + filterSeed, tTrEndPts, + layoutSt, + sweepExtentSt, isUiAddIntgSt, isUiNoBrushSt, + }) { + this.root = d3.select(this.rootKlass).selectAll('.focus-main'); + this.scales = InitScale(this, false); + this.setDataParams(filterSeed, tTrEndPts, layoutSt); + + if (this.data && this.data.length > 0) { + this.setConfig(sweepExtentSt); + this.getShouldUpdate(); + this.drawLine(); + this.drawGrid(); + } + MountBrush(this, isUiAddIntgSt, isUiNoBrushSt); + this.resetShouldUpdate(); + } +} + +export default LineFocus; diff --git a/src/helpers/extractParams.js b/src/helpers/extractParams.js index 60be7b9c..87a9cea4 100644 --- a/src/helpers/extractParams.js +++ b/src/helpers/extractParams.js @@ -30,11 +30,43 @@ const extrShare = (entity, thresSt, scanIdx = 0) => { }; }; +const extrLcMs = (entity, scanSt) => { + console.log('entity', entity); + console.log('scanSt', scanSt); + const { spectra, features, layout } = entity; + console.log('features', features); + let arrX = []; + let arrY = []; + spectra.forEach((spectrum) => { + const { data, pageValue } = spectrum; + const { y } = data[0]; + const minY = Math.min(...y); + const maxY = Math.max(...y); + arrX = [...arrX, pageValue, pageValue]; + arrY = [...arrY, minY, maxY]; + }); + const topic = { x: arrX, y: arrY }; + const maxYFeature = Math.max(...arrY); + const featureData = [{ x: arrX, y: arrY }]; + const feature = { + maxY: maxYFeature, operation: { layout }, data: featureData, isPeaktable: false, + }; + return { topic, feature }; +}; + const extrMs = (entity, thresSt, scanSt) => { - const scanIdx = getScanIdx(entity, scanSt); - const { spectra, feature, hasEdit } = extrShare(entity, thresSt, scanIdx); - const topic = spectra[scanIdx].data[0]; - return { topic, feature, hasEdit }; + const { layout } = entity; + if (Format.isMsLayout(layout)) { + const scanIdx = getScanIdx(entity, scanSt); + const { spectra, feature, hasEdit } = extrShare(entity, thresSt, scanIdx); + const topic = spectra[scanIdx].data[0]; + return { topic, feature, hasEdit }; + } + const { spectra, features } = entity; + const { topic, feature } = extrLcMs(entity, scanSt); + return { + entity, spectra, features, topic, feature, + }; }; const extrNi = (entity, thresSt) => { diff --git a/src/helpers/extractPeaksEdit.js b/src/helpers/extractPeaksEdit.js index 260bbd77..c54329f7 100644 --- a/src/helpers/extractPeaksEdit.js +++ b/src/helpers/extractPeaksEdit.js @@ -1,3 +1,4 @@ +/* eslint-disable max-len */ import { PksEdit } from './converter'; import { Convert2Peak } from './chem'; import { FromManualToOffset } from './shift'; @@ -18,14 +19,14 @@ const niOffset = (shiftSt, atIndex = 0) => { const msOffset = () => 0; const extractPeaksEdit = (feature, editPeakSt, thresSt, shiftSt, layoutSt, atIndex = 0) => { - const offset = Format.isMsLayout(layoutSt) ? msOffset() : niOffset(shiftSt, atIndex); + const offset = (Format.isMsLayout(layoutSt) || Format.isLCMsLayout(layoutSt)) ? msOffset() : niOffset(shiftSt, atIndex); const peaks = Convert2Peak(feature, thresSt.value, offset); const peaksEdit = PksEdit(peaks, editPeakSt); return peaksEdit; }; const extractAutoPeaks = (feature, thresSt, shiftSt, layoutSt, atIndex = 0) => { - const offset = Format.isMsLayout(layoutSt) ? msOffset() : niOffset(shiftSt, atIndex); + const offset = (Format.isMsLayout(layoutSt) || Format.isLCMsLayout(layoutSt)) ? msOffset() : niOffset(shiftSt, atIndex); const peaks = Convert2Peak(feature, thresSt.value, offset); return peaks; }; diff --git a/src/sagas/saga_ui.js b/src/sagas/saga_ui.js index 05f5d5c6..9e806bf4 100644 --- a/src/sagas/saga_ui.js +++ b/src/sagas/saga_ui.js @@ -118,6 +118,8 @@ function* clickUiTarget(action) { const curveSt = yield select(getCurveSt); const { curveIdx } = curveSt; + const layoutSt = yield select(getLayoutSt); + console.log('layoutSt', layoutSt, payload, uiSweepType); if (uiSweepType === LIST_UI_SWEEP_TYPE.PEAK_ADD && !onPeak) { yield put({