Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/component/1d-2d/components/axis_unit_picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import styled from '@emotion/styled';
import type { AxisUnit } from '@zakodium/nmrium-core';
import type { ReactNode } from 'react';
import { assert } from 'react-science/ui';

import type { ContextMenuItem } from '../../elements/ContextMenuBluePrint.tsx';
import { ContextMenu } from '../../elements/ContextMenuBluePrint.tsx';
import useCheckExperimentalFeature from '../../hooks/useCheckExperimentalFeature.ts';
import { axisUnitToLabel } from '../../hooks/use_axis_unit.ts';

interface AxisUnitPickerProps {
unit: AxisUnit;
allowedUnits: AxisUnit[];
onChange: (unit: AxisUnit) => void;
children: ReactNode;
}

export function AxisUnitPicker(props: AxisUnitPickerProps) {
const { unit, allowedUnits, onChange, children } = props;
const isExperimental = useCheckExperimentalFeature();

if (!isExperimental) return children;

const options: ContextMenuItem[] = allowedUnits.map((allowedUnit) => ({
key: allowedUnit,
roleStructure: 'listoption',
text: axisUnitToLabel[allowedUnit],
selected: allowedUnit === unit,
data: { unit: allowedUnit } as Data,
}));

function onSelect(data?: object) {
assert(data);
const { unit } = data as Data;
onChange(unit);
}

return (
<ContextMenuStyled
as="g"
className="unit"
options={options}
onSelect={onSelect}
>
{children}
</ContextMenuStyled>
);
}

const ContextMenuStyled = styled(ContextMenu)`
pointer-events: auto;
cursor: context-menu;
`;

interface Data {
unit: AxisUnit;
}
26 changes: 18 additions & 8 deletions src/component/1d/HorizontalAxis1D.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import type { AxisUnit } from '@zakodium/nmrium-core';
import { useMemo, useRef } from 'react';
import { useLinearPrimaryTicks } from 'react-d3-utils';

import { AxisUnitPicker } from '../1d-2d/components/axis_unit_picker.tsx';
import { useChartData } from '../context/ChartContext.js';
import { useScaleChecked } from '../context/ScaleContext.js';
import { D3Axis } from '../elements/D3Axis.js';
import { useCheckExportStatus } from '../hooks/useViewportSize.js';
import { axisUnitToLabel } from '../hooks/use_axis_unit.ts';
import {
axisUnitToLabel,
useHorizontalAxisUnit,
} from '../hooks/use_axis_unit.ts';
import { useGridline1DConfig } from '../hooks/use_gridlines_config.ts';

import { useIsInset } from './inset/InsetProvider.js';

export function HorizontalAxis1D() {
const { height, width, margin, mode } = useChartData();
const { height, width, margin } = useChartData();
const { scaleX } = useScaleChecked();
const isInset = useIsInset();
const isExportingProcessStart = useCheckExportStatus();

const chartUnit: AxisUnit = mode === 'RTL' ? 'ppm' : 's';
const label = axisUnitToLabel[chartUnit];
const { unit, allowedUnits, setUnit } = useHorizontalAxisUnit();
const unitLabel = axisUnitToLabel[unit];

Check failure on line 24 in src/component/1d/HorizontalAxis1D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / lint-check-types

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<"s" | "pt" | "ppm" | "hz", string>'.

Check failure on line 24 in src/component/1d/HorizontalAxis1D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / test-package

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<"s" | "pt" | "ppm" | "hz", string>'.

const refAxis = useRef<SVGGElement>(null);

const scaler = useMemo(() => {
// TODO apply unit conversion

Check warning on line 29 in src/component/1d/HorizontalAxis1D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / lint-eslint

Unexpected 'todo' comment: 'TODO apply unit conversion'
return scaleX(null);
}, [scaleX]);
const { ticks, scale: ticksScale } = useLinearPrimaryTicks(
Expand Down Expand Up @@ -51,9 +55,15 @@
secondaryGridProps={gridConfig.secondary.lineStyle}
>
{!isInset && (
<text fill="#000" x={width - 10} y="30" dy="0.70em" textAnchor="end">
{label}
</text>
<AxisUnitPicker
unit={unit}
allowedUnits={allowedUnits}
onChange={setUnit}
>
<text fill="#000" x={width - 10} y="30" dy="0.70em" textAnchor="end">
{unitLabel}
</text>
</AxisUnitPicker>
)}
</D3Axis>
);
Expand Down
18 changes: 2 additions & 16 deletions src/component/1d/LinesSeries.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import styled from '@emotion/styled';
import type { Spectrum1D } from '@zakodium/nmrium-core';

Check failure on line 2 in src/component/1d/LinesSeries.tsx

View workflow job for this annotation

GitHub Actions / nodejs / lint-eslint

'Spectrum1D' is defined but never used

import { get1DDataXY } from '../../data/data1d/Spectrum1D/get1DDataXY.js';
import { isSpectrum1D } from '../../data/data1d/Spectrum1D/isSpectrum1D.js';
import { useBrushTracker } from '../EventsTrackers/BrushTracker.js';
import { useChartData } from '../context/ChartContext.js';
import { useScaleChecked } from '../context/ScaleContext.js';
import { useActiveSpectra } from '../hooks/useActiveSpectra.js';
import { useSetActiveSpectrumAction } from '../hooks/useSetActiveSpectrumAction.js';
import { useVerticalAlign } from '../hooks/useVerticalAlign.js';
import { useVisibleSpectra1D } from '../hooks/use_visible_spectra_1d.ts';

import Line from './Line.js';
import { useInsetOptions } from './inset/InsetProvider.js';
Expand All @@ -23,23 +23,9 @@
}
`;

function useSpectra() {
const { xDomains, data } = useChartData();

const inset = useInsetOptions();

if (inset) {
return data?.filter((d) => isSpectrum1D(d) && d.id === inset.spectrumKey);
}

return data?.filter(
(d) => isSpectrum1D(d) && d.display.isVisible && xDomains[d.id],
);
}

function LinesSeries() {
const activeSpectra = useActiveSpectra();
const spectra = useSpectra() as Spectrum1D[];
const spectra = useVisibleSpectra1D();
const { id: insetKey = 'primary' } = useInsetOptions() || {};

return (
Expand Down
50 changes: 40 additions & 10 deletions src/component/2d/DirectAxis2D.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import type { AxisUnit, Spectrum2D } from '@zakodium/nmrium-core';
import { memo, useRef } from 'react';
import { useLinearPrimaryTicks } from 'react-d3-utils';

import { useIsInset } from '../1d/inset/InsetProvider.tsx';
import { AxisUnitPicker } from '../1d-2d/components/axis_unit_picker.tsx';
import { useChartData } from '../context/ChartContext.js';
import { D3Axis } from '../elements/D3Axis.js';
import useSpectrum from '../hooks/useSpectrum.js';
import { useCheckExportStatus } from '../hooks/useViewportSize.tsx';
import { axisUnitToLabel } from '../hooks/use_axis_unit.ts';
import { axisUnitToLabel, useDirectAxisUnit } from '../hooks/use_axis_unit.ts';
import { useGridline2DConfig } from '../hooks/use_gridlines_config.ts';

import { useScale2DX } from './utilities/scale.js';
Expand All @@ -27,11 +26,9 @@
const { margin: marginProps = defaultMargin } = props;

const { height, width, margin } = useChartData();
const spectrum = useSpectrum() as Spectrum2D;

const spectrumUnit: AxisUnit = spectrum?.info?.isFid ? 's' : 'ppm';
const unitLabel = axisUnitToLabel[spectrumUnit];

const axis = useDirectAxisUnit();
// TODO apply `axis.unit` conversion

Check warning on line 31 in src/component/2d/DirectAxis2D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / lint-eslint

Unexpected 'todo' comment: 'TODO apply `axis.unit` conversion'
const scaleX = useScale2DX();
const isInset = useIsInset();
const isExportingProcessStart = useCheckExportStatus();
Expand Down Expand Up @@ -65,11 +62,44 @@
primaryGridProps={gridConfig.primary.lineStyle}
secondaryGridProps={gridConfig.secondary.lineStyle}
>
<text fill="#000" x={width - 60} y="20" dy="0.71em" textAnchor="end">
{unitLabel}
</text>
<Unit width={width - 60} axis={axis} />
</D3Axis>
);
}

interface UnitProps {
width: number;
axis: ReturnType<typeof useDirectAxisUnit>;
}
function Unit(props: UnitProps) {
const { width, axis } = props;

if (!axis) {
return <UnitLabel width={width}>{axisUnitToLabel.ppm}</UnitLabel>;
}

const { unit, allowedUnits, setUnit } = axis;
const label = axisUnitToLabel[unit];

Check failure on line 82 in src/component/2d/DirectAxis2D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / lint-check-types

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<"s" | "pt" | "ppm" | "hz", string>'.

Check failure on line 82 in src/component/2d/DirectAxis2D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / test-package

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<"s" | "pt" | "ppm" | "hz", string>'.

return (
<AxisUnitPicker unit={unit} allowedUnits={allowedUnits} onChange={setUnit}>
<UnitLabel width={width}>{label}</UnitLabel>
</AxisUnitPicker>
);
}

interface UnitLabelProps {
width: number;
children: string;
}
function UnitLabel(props: UnitLabelProps) {
const { width, children } = props;

return (
<text fill="#000" x={width - 60} y="20" dy="0.71em" textAnchor="end">
{children}
</text>
);
}

export default memo(DirectAxis2D);
98 changes: 67 additions & 31 deletions src/component/2d/IndirectAxis2D.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type { AxisUnit } from '@zakodium/nmrium-core';
import { memo, useRef } from 'react';
import { useLinearPrimaryTicks } from 'react-d3-utils';

import { useIsInset } from '../1d/inset/InsetProvider.tsx';
import { AxisUnitPicker } from '../1d-2d/components/axis_unit_picker.tsx';
import { useChartData } from '../context/ChartContext.js';
import { D3Axis } from '../elements/D3Axis.js';
import { useActiveNucleusTab } from '../hooks/useActiveNucleusTab.js';
import { useTextMetrics } from '../hooks/useTextMetrics.js';
import { useCheckExportStatus } from '../hooks/useViewportSize.tsx';
import { axisUnitToLabel } from '../hooks/use_axis_unit.ts';
import {
axisUnitToLabel,
useIndirectAxisUnit,
} from '../hooks/use_axis_unit.ts';
import { useGridline2DConfig } from '../hooks/use_gridlines_config.ts';

import { useScale2DY } from './utilities/scale.js';
Expand All @@ -27,18 +30,15 @@
function IndirectAxis2D(props: IndirectAxis2DProps) {
const { margin: marginProps = defaultMargin } = props;

const { getTextWidth } = useTextMetrics({ labelSize: 10 });
const { width, height, margin } = useChartData();

const nucleus = useActiveNucleusTab();
const [, maybeNucleusUnit] = nucleus.split(',');
const chartUnit: AxisUnit | undefined = /^[0-9]+[A-Z][a-z]?$/.test(
maybeNucleusUnit,
)
? 'ppm'
: undefined;
const unitToDisplay = chartUnit;
const axis = useIndirectAxisUnit();

const matchNucleus = /^[0-9]+[A-Z][a-z]?$/.test(maybeNucleusUnit);

// TODO apply `axis.unit` conversion

Check warning on line 41 in src/component/2d/IndirectAxis2D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / lint-eslint

Unexpected 'todo' comment: 'TODO apply `axis.unit` conversion'
const scaleY = useScale2DY();
const isInset = useIsInset();
const isExportingProcessStart = useCheckExportStatus();
Expand All @@ -56,11 +56,6 @@
return null;
}

const label = unitToDisplay
? axisUnitToLabel[unitToDisplay]
: maybeNucleusUnit;
const labelHeight = getTextWidth(label);

return (
<D3Axis
ref={refAxis}
Expand All @@ -76,27 +71,68 @@
secondaryGridProps={gridConfig.secondary.lineStyle}
>
<g transform={`translate(${marginProps.right - 20}, ${margin.top})`}>
<rect
fill="white"
rx={5}
ry={5}
width={20}
height={labelHeight + 10}
x={-10}
y={-5}
opacity={0.8}
<Unit
axis={axis}
matchNucleus={matchNucleus}
maybeNucleusUnit={maybeNucleusUnit}
/>
<text
fill="#000"
transform="rotate(-90)"
dominantBaseline="middle"
textAnchor="end"
>
{label}
</text>
</g>
</D3Axis>
);
}

interface UnitProps {
matchNucleus: boolean;
maybeNucleusUnit: string;
axis: ReturnType<typeof useIndirectAxisUnit>;
}
function Unit(props: UnitProps) {
const { axis, matchNucleus, maybeNucleusUnit } = props;

if (!matchNucleus) return <UnitLabel>{maybeNucleusUnit}</UnitLabel>;
if (!axis) return <UnitLabel>{axisUnitToLabel.ppm}</UnitLabel>;

const { unit, setUnit, allowedUnits } = axis;
const label = axisUnitToLabel[unit];

Check failure on line 96 in src/component/2d/IndirectAxis2D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / lint-check-types

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<"s" | "pt" | "ppm" | "hz", string>'.

Check failure on line 96 in src/component/2d/IndirectAxis2D.tsx

View workflow job for this annotation

GitHub Actions / nodejs / test-package

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Record<"s" | "pt" | "ppm" | "hz", string>'.

return (
<AxisUnitPicker unit={unit} allowedUnits={allowedUnits} onChange={setUnit}>
<UnitLabel>{label}</UnitLabel>
</AxisUnitPicker>
);
}

interface UnitLabelProps {
children: string;
}
function UnitLabel(props: UnitLabelProps) {
const { children } = props;

const { getTextWidth } = useTextMetrics({ labelSize: 10 });
const labelHeight = getTextWidth(children);

return (
<>
<rect
fill="white"
rx={5}
ry={5}
width={20}
height={labelHeight + 10}
x={-10}
y={-5}
opacity={0.8}
/>
<text
fill="#000"
transform="rotate(-90)"
dominantBaseline="middle"
textAnchor="end"
>
{children}
</text>
</>
);
}

export default memo(IndirectAxis2D);
4 changes: 3 additions & 1 deletion src/component/context/DispatchContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { RangesActions } from '../reducer/actions/RangesActions.js';
import type { SpectrumActions } from '../reducer/actions/SpectraActions.js';
import type { ToolsActions } from '../reducer/actions/ToolsActions.js';
import type { ZonesActions } from '../reducer/actions/ZonesActions.js';
import type { UnitActions } from '../reducer/actions/unit_actions.ts';
import type { ActionType } from '../reducer/types/ActionType.js';

export type Action =
Expand All @@ -36,7 +37,8 @@ export type Action =
| CorrelationsActions
| ActionType<'INITIALIZE_NMRIUM'>
| ActionType<'SECRET_THROW_ERROR', { randomNumber: number }>
| InsetsActions;
| InsetsActions
| UnitActions;
// // eslint-disable-next-line @typescript-eslint/ban-types
// | { type: string & {}; payload?: Object };

Expand Down
Loading
Loading