diff --git a/src/component/2d/utilities/extractSpectrumSignals.ts b/src/component/2d/utilities/extractSpectrumSignals.ts index 63093497f..6912ee3c1 100644 --- a/src/component/2d/utilities/extractSpectrumSignals.ts +++ b/src/component/2d/utilities/extractSpectrumSignals.ts @@ -8,46 +8,54 @@ interface ExtractSpectrumSignalsOptions { from?: number; to?: number; include?: (range: Range) => T; + onlyFirstSignal?: boolean; } + +function isRangeInBounds(range: Range, from?: number, to?: number): boolean { + if (typeof from === 'number' && typeof to === 'number') { + return range.from <= to && range.to >= from; + } + if (typeof to === 'number') { + return range.to <= to; + } + if (typeof from === 'number') { + return range.from >= from; + } + return true; +} + export function extractSpectrumSignals( spectrum: Spectrum1D, options: ExtractSpectrumSignalsOptions = {}, -) { - const result: Array> = []; - const { from, to, include } = options; +): Array> { + const { from, to, include, onlyFirstSignal = false } = options; const ranges = spectrum?.ranges?.values; - if (!Array.isArray(ranges) || ranges?.length === 0) { + if (!Array.isArray(ranges) || ranges.length === 0) { return []; } - for (const range of ranges) { - const rangeFrom = range.from; - const rangeTo = range.to; - let isInRange = true; - - if (typeof from === 'number' && typeof to === 'number') { - isInRange = rangeFrom <= to && rangeTo >= from; - } else if (typeof to === 'number') { - isInRange = rangeTo <= to; - } else if (typeof from === 'number') { - isInRange = rangeFrom >= from; - } + const result: Array> = []; - if (!isInRange) continue; + for (const range of ranges) { + if (!isRangeInBounds(range, from, to)) continue; const { signals = [] } = range; - let index = 0; + let includedCount = 0; + for (const signal of signals) { const { kind, assignment } = signal; - if (kind && signalKindsToInclude.has(kind)) { - result.push({ - ...signal, - assignment: index === 0 ? assignment : '', - ...include?.(range), - } as ExtractedSignal); - index++; - } + if (!kind || !signalKindsToInclude.has(kind)) continue; + + const keepAssignment = !onlyFirstSignal || includedCount === 0; + + result.push({ + ...signal, + assignment: keepAssignment ? assignment : '', + ...include?.(range), + } as ExtractedSignal); + + includedCount++; } } diff --git a/src/component/2d/zones/SignalsGuideLines.tsx b/src/component/2d/zones/SignalsGuideLines.tsx index 2b6d21942..75c8e147d 100644 --- a/src/component/2d/zones/SignalsGuideLines.tsx +++ b/src/component/2d/zones/SignalsGuideLines.tsx @@ -7,11 +7,7 @@ import { PiTextTBold, PiTextTSlashBold } from 'react-icons/pi'; import { isAssigned } from '../../../data/data1d/Spectrum1D/isRangeAssigned.js'; import { FieldEdition } from '../../1d-2d/FieldEdition.js'; -import { - useAssignment, - useAssignmentContext, -} from '../../assignment/AssignmentsContext.js'; -import { filterAssignedIDs } from '../../assignment/utilities/filterAssignedIDs.js'; +import { useAssignment } from '../../assignment/AssignmentsContext.js'; import { useChartData } from '../../context/ChartContext.js'; import { useDispatch } from '../../context/DispatchContext.js'; import { @@ -76,6 +72,7 @@ function useSignalsOverlap(axis: IndicationLinesAxis, spectrum: Spectrum1D) { const processedSignals: ProcessedSignal[] = signals.map((signal) => { const { delta, assignment } = signal; const text = assignment ?? ''; + const labelWidth = getTextWidth(text); return { @@ -151,23 +148,23 @@ function getAxisRangeId(options: GetAxisRangeIdOptions) { interface UseRangeAssignmentOptions { rangeId: string; - signalsIds: string[]; spectrumId: string; signalId: string; } function useRangeAssignment(options: UseRangeAssignmentOptions) { - const { rangeId, signalsIds, spectrumId, signalId } = options; + const { rangeId, spectrumId, signalId } = options; - const assignmentData = useAssignmentContext(); + // const assignmentData = useAssignmentContext(); const assignmentContext = useAssignment(signalId, spectrumId); - const highlightId = [rangeId] - .concat(assignmentContext.assignedDiaIds?.x || []) - .concat(filterAssignedIDs(assignmentData.data, signalsIds)); + const highlightId = [signalId].concat( + assignmentContext.assignedDiaIds?.x || [], + ); + // .concat(filterAssignedIDs(assignmentData.data, signalsIds)); const highlightContext = useHighlight(highlightId, { - type: 'RANGE', - extra: { id: rangeId, spectrumID: spectrumId }, + type: 'SIGNAL_1D', + extra: { id: signalId, rangeId, spectrumID: spectrumId }, }); return { highlightContext, assignmentContext }; @@ -180,10 +177,8 @@ function isRangeSignalAssigned( return isAssigned(otherProps); } -function hasDiaIds(signals: Signal1D[]) { - return signals.some( - (signal) => Array.isArray(signal?.diaIDs) && signal.diaIDs.length > 0, - ); +function hasDiaIds(signal: Partial) { + return Array.isArray(signal?.diaIDs) && signal.diaIDs.length > 0; } function IndicationLine(props: IndicationLineProps) { @@ -199,11 +194,9 @@ function IndicationLine(props: IndicationLineProps) { nbAtoms, id: signalId, } = props; - const { id: rangeId, signals } = range; + const { id: rangeId } = range; const highlightColor = useHighlightColor(); const isSignalAssigned = isRangeSignalAssigned({ range, diaIDs, nbAtoms }); - - const signalsIds = signals.map(({ id }) => id); const { margin, width, height } = useChartData(); const { setData: addNewAssignmentLabel } = useShareData(); @@ -211,11 +204,10 @@ function IndicationLine(props: IndicationLineProps) { const { assignmentContext, highlightContext } = useRangeAssignment({ rangeId, spectrumId, - signalsIds, signalId, }); - const hasDiaIDs = hasDiaIds(signals); + const hasDiaIDs = hasDiaIds({ nbAtoms, diaIDs }); const isAssignmentActive = assignmentContext.isActive; const isHighlighted = highlightContext.isActive || isAssignmentActive; @@ -269,6 +261,7 @@ function IndicationLine(props: IndicationLineProps) { type: 'UNASSIGN_1D_SIGNAL', payload: { rangeKey: rangeId, + signalId, spectrumId, }, }); @@ -279,13 +272,13 @@ function IndicationLine(props: IndicationLineProps) { icon: , onClick: assignHandler, intent: 'success', - title: 'Assign range', + title: 'Assign signal', }, { icon: , onClick: () => unAssignHandler(), intent: 'danger', - title: 'Unassign range', + title: 'Unassign signal', visible: isAssignmentActive || hasDiaIDs, }, { diff --git a/src/component/EventsTrackers/KeysListenerTracker.tsx b/src/component/EventsTrackers/KeysListenerTracker.tsx index c82c0f934..07744e133 100644 --- a/src/component/EventsTrackers/KeysListenerTracker.tsx +++ b/src/component/EventsTrackers/KeysListenerTracker.tsx @@ -139,12 +139,13 @@ function KeysListenerTracker(props: KeysListenerTrackerProps) { break; } case 'SIGNAL_1D': { - const { id, rangeId } = extra; + const { id, rangeId, spectrumID } = extra; dispatch({ type: 'DELETE_1D_SIGNAL', payload: { signalId: id, rangeId, + spectrumId: spectrumID, }, }); // remove keys from the highlighted list after delete diff --git a/src/component/panels/RangesPanel/RangesTableRow.tsx b/src/component/panels/RangesPanel/RangesTableRow.tsx index 9d188faee..5bc6d14dc 100644 --- a/src/component/panels/RangesPanel/RangesTableRow.tsx +++ b/src/component/panels/RangesPanel/RangesTableRow.tsx @@ -115,6 +115,10 @@ export default function RangesTableRow(props: RangesTableRowProps) { const signalIndex = tableMetaInfo.signalIndex; + if (typeof signalIndex !== 'number') { + return; + } + dispatch({ type: 'UNASSIGN_1D_SIGNAL', payload: { diff --git a/src/component/reducer/actions/RangesActions.ts b/src/component/reducer/actions/RangesActions.ts index 23b980a8f..9e98babfb 100644 --- a/src/component/reducer/actions/RangesActions.ts +++ b/src/component/reducer/actions/RangesActions.ts @@ -79,11 +79,15 @@ interface DeleteSignalProps { } type DeleteSignalAction = ActionType<'DELETE_1D_SIGNAL', DeleteSignalProps>; -interface UnAssign1DSignalOptions { +type SignalSelector = + | { signalId: string; signalIndex?: never } + | { signalIndex: number; signalId?: never } + | { signalId?: never; signalIndex?: never }; + +type UnAssign1DSignalOptions = { rangeKey?: string; - spectrumId?: string; // If not specified, the currently active spectrum will be used by default. - signalIndex?: number; -} + spectrumId?: string; +} & SignalSelector; type UnAssign1DSignalAction = ActionType< 'UNASSIGN_1D_SIGNAL', UnAssign1DSignalOptions @@ -413,24 +417,49 @@ function handleDeleteSignal(draft: Draft, action: DeleteSignalAction) { deleteSignal1D(draft, action.payload); } +function resolveSignalIndex( + range: Range, + { + signalId, + signalIndex = -1, + }: Pick, +): number { + if (!signalId) return signalIndex; + return range.signals.findIndex((signal) => signal.id === signalId); +} + +function clearRangeAssignment( + ranges: Draft, + rangeIndex: number, + options: Pick, +) { + const index = resolveSignalIndex(ranges[rangeIndex], options); + ranges[rangeIndex] = unlink(ranges[rangeIndex], index); +} + function clearSignalAssignment( draft: Draft, options: UnAssign1DSignalOptions = {}, ) { - const { spectrumId, rangeKey, signalIndex = -1 } = options; + const { spectrumId, rangeKey, signalIndex = -1, signalId } = options; const spectrum = getSpectrum(draft, spectrumId); if (!isSpectrum1D(spectrum)) return; const ranges = spectrum.ranges.values; - if (rangeKey) { - const rangeIndex = getRangeIndex(spectrum, rangeKey); - ranges[rangeIndex] = unlink(ranges[rangeIndex], signalIndex); - } else { + + if (!rangeKey) { for (const range of ranges) { unlink(range, -1); } + return; } + + const rangeIndex = getRangeIndex(spectrum, rangeKey); + const index = resolveSignalIndex(ranges[rangeIndex], options); + ranges[rangeIndex] = unlink(ranges[rangeIndex], index); + + clearRangeAssignment(ranges, rangeIndex, { signalId, signalIndex }); } //action