import { xFindClosestIndex } from 'ml-spectra-processing';
import { Fragment, useMemo } from 'react';
import { MF } from 'react-mf';
import { get1DDataXY } from '../../data/data1d/Spectrum1D/index.js';
import {
isFid2DData,
isSpectrum2D,
} from '../../data/data2d/Spectrum2D/isSpectrum2D.js';
import { useBrushTracker } from '../EventsTrackers/BrushTracker.js';
import { useMouseTracker } from '../EventsTrackers/MouseTracker.js';
import { useChartData } from '../context/ChartContext.js';
import { FooterContainer, InfoItem } from '../elements/Footer.js';
import { useActiveSpectrum } from '../hooks/useActiveSpectrum.js';
import { useFormatNumberByNucleus } from '../hooks/useFormatNumberByNucleus.js';
import { options } from '../toolbar/ToolTypes.js';
import type { Spectrum1DTraces } from './useTracesSpectra.js';
import type { Get2DDimensionLayoutReturn } from './utilities/DimensionLayout.js';
import { LAYOUT, getLayoutID } from './utilities/DimensionLayout.js';
import { get1DYScale, get2DXScale, get2DYScale } from './utilities/scale.js';
interface FooterBannerProps {
layout: Get2DDimensionLayoutReturn;
data1D: Spectrum1DTraces;
}
export default function FooterBanner(props: FooterBannerProps) {
const { layout, data1D } = props;
const position = useMouseTracker();
const { startX, endX, startY, endY, step, mouseButton } = useBrushTracker();
const {
margin,
width,
height,
xDomain,
yDomain,
yDomains,
view: {
spectra: { activeTab },
},
data: spectra,
toolOptions: { selectedTool },
mode,
} = useChartData();
const activeSpectrum = useActiveSpectrum();
const trackID =
position &&
getLayoutID(layout, {
startX: position.x,
startY: position.y,
});
const nuclei = activeTab.split(',');
const [formatX, formatY] = useFormatNumberByNucleus(nuclei);
const hasTraces = data1D.x || data1D.y;
const scaleX = useMemo(() => {
if (selectedTool === options.slicing.id || !trackID) {
return null;
}
if (!hasTraces || trackID === 'MAIN' || trackID === 'TOP') {
return get2DXScale({ width, margin, xDomain, mode });
}
return get2DYScale({ height, margin, yDomain });
}, [
hasTraces,
selectedTool,
width,
margin,
xDomain,
mode,
trackID,
height,
yDomain,
]);
const scaleY = useMemo(() => {
if (selectedTool === options.slicing.id || !trackID) {
return null;
}
if (!hasTraces || trackID === 'MAIN') {
return get2DYScale({ height, margin, yDomain });
}
if (trackID === 'TOP') {
return data1D.x ? get1DYScale(yDomains[data1D.x.id], margin.top) : null;
}
return data1D.y ? get1DYScale(yDomains[data1D.y.id], margin.left) : null;
}, [
data1D.x,
data1D.y,
hasTraces,
height,
margin,
selectedTool,
trackID,
yDomain,
yDomains,
]);
if (
!activeSpectrum ||
!position ||
position.y < 10 ||
position.x < 10 ||
position.x > width - margin.right ||
position.y > height - margin.bottom
) {
return ;
}
const getRealYValue = (coordinate: number) => {
let axis: 'x' | 'y' | null = null;
if (trackID === LAYOUT.top) {
axis = 'x';
} else if (trackID === LAYOUT.left) {
axis = 'y';
}
const spectrum = axis && data1D[axis];
if (!scaleX || !spectrum) {
return 1;
}
const datum = get1DDataXY(spectrum);
const xIndex = xFindClosestIndex(datum.x, scaleX.invert(coordinate));
return datum.y[xIndex];
};
const getXValue = (x: number | null = null) => {
if (!scaleX || !trackID) return 0;
if (trackID === 'MAIN') {
return scaleX.invert(x || position.y);
}
// return if the trackID = "MAIN" | "TOP"
return scaleX.invert(x || position.x);
};
const getYValue = () => {
if (!scaleY || !trackID) return 0;
if (trackID === 'LEFT') {
return scaleY.invert(position.x);
}
return scaleY.invert(position.y);
};
const getRation = () => {
if (!trackID || trackID === 'MAIN') return 0;
if (trackID === 'TOP') {
return (
(getRealYValue(startX) / (getRealYValue(endX) || Number.MIN_VALUE)) *
100
).toFixed(2);
}
// tracKId = "LEFT"
return (
(getRealYValue(startY) / (getRealYValue(endY) || Number.MIN_VALUE)) *
100
).toFixed(2);
};
const getDeltaX = () => {
if (!trackID || trackID === 'MAIN') return 0;
if (trackID === 'TOP') {
return (getXValue(startX) - getXValue(endX)).toPrecision(6);
}
return (getXValue(startY) - getXValue(endY)).toPrecision(6);
};
const getLabel = (label2d: string, label1d: string, nucleus: string) => {
return trackID === LAYOUT.main ? (
{label2d} ( )
) : (
label1d
);
};
const getZValue = () => {
const spectrum = spectra[activeSpectrum.index];
if (trackID === LAYOUT.main && isSpectrum2D(spectrum)) {
const { data } = spectrum;
const { maxX, maxY, minX, minY, z } = isFid2DData(data)
? data.re
: data.rr;
const xStep = (maxX - minX) / (z[0].length - 1);
const yStep = (maxY - minY) / (z.length - 1);
const xIndex = Math.floor((getXValue() - minX) / xStep);
const yIndex = Math.floor((getYValue() - minY) / yStep);
if (xIndex < 0 || xIndex >= z[0].length) return 0;
if (yIndex < 0 || yIndex >= z.length) return 0;
return z[yIndex][xIndex];
}
return 0;
};
const isBrushing = step === 'brushing' && mouseButton === 'main';
return (
{getLabel('F2', 'X', nuclei[0])} :
{formatX(getXValue())}
ppm
{getLabel('F1', 'Y', nuclei[1])} :
{formatY(getYValue())}
ppm
Intensity :
{getZValue()}
{isBrushing && (
Δppm :
{getDeltaX()}
)}
{isBrushing && (
ratio :
{getRation()}%
)}
);
}