Skip to content

Commit

Permalink
feat WIP: display lcms as a line spectrum
Browse files Browse the repository at this point in the history
  • Loading branch information
Lan Le committed Aug 20, 2024
1 parent c978a2f commit 9d316f7
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 28 deletions.
3 changes: 2 additions & 1 deletion src/components/cmd_bar/r05_submit_btn.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/components/cmd_bar/r06_predict_btn.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
37 changes: 17 additions & 20 deletions src/components/d3_line_rect/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
});

Expand All @@ -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,
Expand All @@ -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);
}

Expand All @@ -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);
}
}

Expand All @@ -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,
Expand All @@ -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,
Expand Down
234 changes: 234 additions & 0 deletions src/components/d3_line_rect/line_focus.js
Original file line number Diff line number Diff line change
@@ -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;
Loading

0 comments on commit 9d316f7

Please sign in to comment.