Skip to content

Commit 14b4929

Browse files
authored
feat(ranges): forward options to publication string renderer (#3958)
* Export as > Preview publication string (modal) become Copy publication string * Display publication string (button) become Publication string menu * Publication string divider * Configure (modal) * Show / Hide (toggle button) * Configuration modal of publication string * Apply and copy are separated actions * copy is a floating button in preview container * "Apply and close" is an action of dialog footer (right align) * Add textStyle options forward to renderer * Add checkbox to control publication string visibility in configuration dialog fix(ranges): publication string preview iso with chart
1 parent a6378a5 commit 14b4929

15 files changed

Lines changed: 468 additions & 232 deletions

package-lock.json

Lines changed: 29 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@
6969
"@emotion/styled": "^11.14.1",
7070
"@hookform/resolvers": "^5.2.2",
7171
"@tanstack/react-form": "^1.27.7",
72-
"@zakodium/nmr-types": "^0.5.0",
73-
"@zakodium/nmrium-core": "^0.6.0",
74-
"@zakodium/nmrium-core-plugins": "^0.6.29",
72+
"@zakodium/nmr-types": "^0.5.1",
73+
"@zakodium/nmrium-core": "^0.6.1",
74+
"@zakodium/nmrium-core-plugins": "^0.6.33",
7575
"@zakodium/pdnd-esm": "^1.0.2",
7676
"@zip.js/zip.js": "^2.8.15",
7777
"cheminfo-font": "^1.13.1",
@@ -113,7 +113,7 @@
113113
"react-ocl-nmr": "^4.1.1",
114114
"react-plot": "^3.1.2",
115115
"react-rnd": "^10.5.2",
116-
"react-science": "^19.5.1",
116+
"react-science": "^19.7.1",
117117
"react-table": "^7.8.0",
118118
"smart-array-filter": "^5.0.0",
119119
"yup": "^1.7.1",

src/component/1d/FloatPublicationString.tsx

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
import styled from '@emotion/styled';
2-
import type { BoundingBox } from '@zakodium/nmrium-core';
3-
import { rangesToACS } from 'nmr-processing';
4-
import { useEffect, useState } from 'react';
2+
import type { BoundingBox, TextStyle } from '@zakodium/nmrium-core';
3+
import { useEffect, useMemo, useState } from 'react';
54
import { BsArrowsMove } from 'react-icons/bs';
65
import { FaTimes } from 'react-icons/fa';
76
import { Rnd } from 'react-rnd';
7+
import { SVGStyledText } from 'react-science/ui';
88

9-
import { isSpectrum1D } from '../../data/data1d/Spectrum1D/isSpectrum1D.js';
9+
import { isSpectrum1D } from '../../data/data1d/Spectrum1D/index.ts';
1010
import { useChartData } from '../context/ChartContext.js';
1111
import { useDispatch } from '../context/DispatchContext.js';
1212
import { useGlobal } from '../context/GlobalContext.js';
1313
import type { ActionsButtonsPopoverProps } from '../elements/ActionsButtonsPopover.js';
1414
import { ActionsButtonsPopover } from '../elements/ActionsButtonsPopover.js';
15-
import { useActiveNucleusTab } from '../hooks/useActiveNucleusTab.ts';
16-
import { usePanelPreferences } from '../hooks/usePanelPreferences.js';
1715
import { useSVGUnitConverter } from '../hooks/useSVGUnitConverter.js';
18-
import useSpectraByActiveNucleus from '../hooks/useSpectraPerNucleus.js';
1916
import { useTextMetrics } from '../hooks/useTextMetrics.ts';
2017
import { useCheckExportStatus } from '../hooks/useViewportSize.js';
18+
import { useACSSettings } from '../hooks/use_acs_settings.ts';
19+
import { usePublicationStrings } from '../hooks/use_publication_strings.ts';
2120

2221
const ReactRnd = styled(Rnd)`
2322
border: 1px solid transparent;
@@ -36,11 +35,17 @@ interface UseWrapSVGTextParams {
3635
text: string;
3736
width: number;
3837
fontSize: number;
38+
fontStyle: string | undefined;
39+
fontWeight: string | undefined;
3940
}
4041

4142
function useWrapSVGText(params: UseWrapSVGTextParams) {
42-
const { text, width, fontSize } = params;
43-
const { getTextWidth } = useTextMetrics(fontSize);
43+
const { text, width, fontSize, fontStyle, fontWeight } = params;
44+
const { getTextWidth } = useTextMetrics({
45+
labelSize: fontSize,
46+
labelStyle: fontStyle,
47+
labelWeight: fontWeight,
48+
});
4449

4550
const formattedText = text
4651
.replaceAll(/<sup>(?<n>.*?)<\/sup>/g, '++$1++ ')
@@ -73,28 +78,36 @@ function useWrapSVGText(params: UseWrapSVGTextParams) {
7378

7479
interface PublicationTextProps {
7580
text: string;
81+
textStyle: TextStyle;
7682
fontSize?: number;
7783
width: number;
7884
padding?: number;
7985
}
8086

8187
function PublicationText(props: PublicationTextProps) {
82-
const { fontSize = 12, padding = 10, width, text } = props;
88+
const { text, width } = props;
89+
const textStyle = {
90+
...props.textStyle,
91+
fontSize: props.textStyle.fontSize ?? props.fontSize ?? 12,
92+
};
93+
const { fontSize = textStyle.fontSize, padding = 10 } = props;
8394
const boxWidth = width - padding * 2;
8495

8596
const { lineHeight, lines } = useWrapSVGText({
8697
width: boxWidth,
8798
fontSize,
99+
fontStyle: textStyle.fontStyle,
100+
fontWeight: textStyle.fontWeight,
88101
text,
89102
});
90103

91104
return (
92105
<g transform={`translate(${padding} ${padding})`}>
93106
{lines.map((line, lineIndex) => (
94-
<text
107+
<SVGStyledText
95108
// eslint-disable-next-line react/no-array-index-key
96109
key={lineIndex}
97-
fontSize={fontSize}
110+
{...textStyle}
98111
fontFamily="Arial"
99112
y={lineIndex * lineHeight}
100113
dominantBaseline="hanging"
@@ -119,7 +132,7 @@ function PublicationText(props: PublicationTextProps) {
119132
return <tspan key={wordIndex}>{word} </tspan>;
120133
}
121134
})}
122-
</text>
135+
</SVGStyledText>
123136
))}
124137
</g>
125138
);
@@ -129,16 +142,18 @@ interface DraggablePublicationStringProps {
129142
value: string;
130143
bonding: BoundingBox;
131144
spectrumKey: string;
145+
nucleus: string | undefined;
132146
}
133147

134148
function DraggablePublicationString(props: DraggablePublicationStringProps) {
135-
const { value, bonding: externalBounding, spectrumKey } = props;
149+
const { value, bonding: externalBounding, spectrumKey, nucleus } = props;
136150
const dispatch = useDispatch();
137151
const { viewerRef } = useGlobal();
138152
const [bounding, setBounding] = useState<BoundingBox>(externalBounding);
139153
const [isMoveActive, setIsMoveActive] = useState(false);
140154
const { percentToPixel, pixelToPercent } = useSVGUnitConverter();
141155
const isExportProcessStart = useCheckExportStatus();
156+
const acsOptions = useACSSettings(nucleus);
142157

143158
useEffect(() => {
144159
setBounding({ ...externalBounding });
@@ -254,7 +269,11 @@ function DraggablePublicationString(props: DraggablePublicationStringProps) {
254269
if (isExportProcessStart) {
255270
return (
256271
<g transform={`translate(${x} ${y})`}>
257-
<PublicationText text={value} width={width} />
272+
<PublicationText
273+
text={value}
274+
width={width}
275+
textStyle={acsOptions.textStyle}
276+
/>
258277
</g>
259278
);
260279
}
@@ -298,51 +317,35 @@ function DraggablePublicationString(props: DraggablePublicationStringProps) {
298317
y={y}
299318
>
300319
<svg width={width} height={'auto'} xmlns="http://www.w3.org/2000/svg">
301-
<PublicationText text={value} width={width} />
320+
<PublicationText
321+
text={value}
322+
width={width}
323+
textStyle={acsOptions.textStyle}
324+
/>
302325
</svg>
303326
</ActionsButtonsPopover>
304327
</ReactRnd>
305328
);
306329
}
307330

308-
function usePublicationString() {
309-
const spectra = useSpectraByActiveNucleus();
310-
const activeTab = useActiveNucleusTab();
311-
const rangesPreferences = usePanelPreferences('ranges', activeTab);
312-
313-
const output: Record<string, string> = {};
314-
315-
for (const spectrum of spectra) {
316-
if (!isSpectrum1D(spectrum)) {
317-
continue;
318-
}
319-
const { id: spectrumKey, info, ranges } = spectrum;
320-
321-
if (!Array.isArray(ranges?.values) || ranges.values.length === 0) {
322-
continue;
323-
}
324-
325-
const { originFrequency: observedFrequency, nucleus } = info;
326-
327-
const value = rangesToACS(ranges.values, {
328-
nucleus, // '19f'
329-
deltaFormat: rangesPreferences.deltaPPM.format,
330-
couplingFormat: rangesPreferences.coupling.format,
331-
observedFrequency, //400
332-
});
333-
334-
output[spectrumKey] = value;
335-
}
336-
337-
return output;
338-
}
339-
340331
export function FloatPublicationString() {
341-
const publicationString = usePublicationString();
332+
const publicationString = usePublicationStrings();
342333
const {
334+
data: spectra,
343335
view: { ranges },
344336
} = useChartData();
345-
const options = Object.entries(ranges);
337+
const options = useMemo(() => Object.entries(ranges), [ranges]);
338+
const spectraToNucleusMap = useMemo(() => {
339+
const map = new Map<string, string>();
340+
341+
for (const spectrum of spectra) {
342+
if (!isSpectrum1D(spectrum)) continue;
343+
const { nucleus } = spectrum.info;
344+
map.set(spectrum.id, nucleus);
345+
}
346+
347+
return map;
348+
}, [spectra]);
346349

347350
return options.map(([spectrumKey, viewOptions]) => {
348351
const { showPublicationString, publicationStringBounding } = viewOptions;
@@ -352,6 +355,7 @@ export function FloatPublicationString() {
352355
<DraggablePublicationString
353356
key={spectrumKey}
354357
spectrumKey={spectrumKey}
358+
nucleus={spectraToNucleusMap.get(spectrumKey)}
355359
bonding={publicationStringBounding}
356360
value={publicationString[spectrumKey]}
357361
/>

src/component/1d/peaks/PeakAnnotations.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ function resolveYOverlaps(
5555
}
5656

5757
function useDetectPeakOverlaps(peaks: Peak[], format: string) {
58-
const { getTextWidth } = useTextMetrics(textSize);
58+
const { getTextWidth } = useTextMetrics({ labelSize: textSize });
5959
const overlapPeaksById: Record<string, boolean> = {};
6060

6161
let cluster: Peak[] = [];

src/component/1d/ranges/Ranges.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type ProcessedRange = RangeType & {
3232
function useStackRangesAssignmentsLabels(ranges: RangeType[]) {
3333
const { scaleX } = useScaleChecked();
3434

35-
const { getTextWidth } = useTextMetrics(labelSize);
35+
const { getTextWidth } = useTextMetrics({ labelSize });
3636

3737
if (ranges.length === 0) return null;
3838

src/component/2d/YAxis.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function YAxis(props: YAxisProps) {
2525
const { width, height, margin } = useChartData();
2626
const nucleusStr = useActiveNucleusTab();
2727
const [, unit] = nucleusStr.split(',');
28-
const { getTextWidth } = useTextMetrics(10);
28+
const { getTextWidth } = useTextMetrics({ labelSize: 10 });
2929

3030
const scaleY = useScale2DY();
3131

src/component/2d/zones/SignalsGuideLines.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function useSignalsOverlap(axis: IndicationLinesAxis, spectrum: Spectrum1D) {
6767
});
6868
const scaleX = useScale2DX();
6969
const scaleY = useScale2DY();
70-
const { getTextWidth } = useTextMetrics(labelSize);
70+
const { getTextWidth } = useTextMetrics({ labelSize });
7171

7272
if (!signals) return null;
7373

0 commit comments

Comments
 (0)