import type { Spectrum1D, Spectrum2D } from '@zakodium/nmrium-core'; import { Filters1D } from 'nmr-processing'; import type { ReactNode } from 'react'; import { getSlice } from '../../../../data/data2d/Spectrum2D/index.js'; import { useChartData } from '../../../context/ChartContext.js'; import { useActiveSpectrum } from '../../../hooks/useActiveSpectrum.js'; import useSpectrum from '../../../hooks/useSpectrum.js'; import type { TraceDirection } from '../../../reducer/Reducer.js'; import { PathBuilder } from '../../../utility/PathBuilder.js'; import { get2DXScale, get2DYScale, getSliceYScale, useScale2DX, useScale2DY, } from '../../utilities/scale.js'; import { useActivePhaseTraces } from './useActivePhaseTraces.js'; interface BaseComponentProps extends React.SVGAttributes { children?: ReactNode; } interface InnerSpectrumPhaseTraceProps extends BaseComponentProps { data: { x: Float64Array; re: Float64Array }; } interface SpectrumPhaseTraceProps extends BaseComponentProps { positionUnit: 'PPM' | 'Pixel'; position: { x: number; y: number }; } function usePath(x: Float64Array, y: Float64Array, direction: TraceDirection) { const { width, margin, height, xDomain, yDomain, mode } = useChartData(); const { scaleRatio } = useActivePhaseTraces(); const spectrum = useSpectrum() as Spectrum2D; if (!spectrum) return ''; if (direction === 'horizontal') { const scaleX = get2DXScale({ margin, width, xDomain, mode }); const scaleY = getSliceYScale(spectrum.data, height, 'RTL', { margin: margin.top + margin.bottom, scaleRatio, }); const pathBuilder = new PathBuilder(); pathBuilder.moveTo(scaleX(x[0]), scaleY(y[0])); for (let i = 1; i < x.length; i++) { pathBuilder.lineTo(scaleX(x[i]), scaleY(y[i])); } return pathBuilder.toString(); } const scaleX = get2DYScale({ margin, height, yDomain }); const scaleY = getSliceYScale(spectrum.data, width, 'RTL', { margin: margin.left + margin.right, scaleRatio, }); const pathBuilder = new PathBuilder(); pathBuilder.moveTo(scaleY(y.at(-1) as number), scaleX(x.at(-1) as number)); for (let i = x.length - 2; i >= 0; i--) { pathBuilder.lineTo(scaleY(y[i]), scaleX(x[i])); } return pathBuilder.toString(); } export function SpectrumPhaseTrace(props: SpectrumPhaseTraceProps) { const { positionUnit, position, children, ...otherProps } = props; const { tempData, width, margin, height } = useChartData(); const { activeTraceDirection: direction } = useActivePhaseTraces(); const scale2dX = useScale2DX(); const scale2dY = useScale2DY(); const activeSpectrum = useActiveSpectrum(); if (!activeSpectrum) { return null; } const spectrumBeforePhasing = tempData[activeSpectrum.index] as Spectrum2D; let positionInPixel; let positionInPPM; if (positionUnit === 'Pixel') { positionInPixel = position; positionInPPM = { x: scale2dX.invert(position.x), y: scale2dY.invert(position.y), }; } else { positionInPixel = { x: scale2dX(position.x), y: scale2dY(position.y), }; positionInPPM = position; } const sliceData = getSlice(spectrumBeforePhasing, positionInPPM, { sliceType: 'both', }); const data = sliceData?.[direction]?.data; if (!data) { return null; } const innerHeight = height - margin.top - margin.bottom; const innerWidth = width - margin.left - margin.right; const translateY = direction === 'horizontal' ? positionInPixel.y - innerHeight : 0; const translateX = direction === 'vertical' ? positionInPixel.x - innerWidth : 0; return ( {children} ); } function InnerSpectrumPhaseTrace(props: InnerSpectrumPhaseTraceProps) { const { data: dataBeforePhasing, children, ...othersProps } = props; const { color, activeTraceDirection: direction, ph0, ph1, } = useActivePhaseTraces(); const spectrum = { data: dataBeforePhasing, info: { isComplex: true, isFid: false }, }; Filters1D.phaseCorrection.apply(spectrum as Spectrum1D, { ph0, ph1, }); const { x, re } = spectrum.data; const path = usePath(x, re, direction); return ( {children} ); }