@tetrascience-npm/tetrascience-react-ui 0.6.0-beta.82.1 → 0.6.0-beta.84.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/charts/AreaGraph/AreaGraph.cjs +1 -1
- package/dist/components/charts/AreaGraph/AreaGraph.cjs.map +1 -1
- package/dist/components/charts/AreaGraph/AreaGraph.js +132 -98
- package/dist/components/charts/AreaGraph/AreaGraph.js.map +1 -1
- package/dist/components/charts/BarGraph/BarGraph.cjs +1 -1
- package/dist/components/charts/BarGraph/BarGraph.cjs.map +1 -1
- package/dist/components/charts/BarGraph/BarGraph.js +63 -57
- package/dist/components/charts/BarGraph/BarGraph.js.map +1 -1
- package/dist/components/charts/Boxplot/Boxplot.cjs +1 -1
- package/dist/components/charts/Boxplot/Boxplot.cjs.map +1 -1
- package/dist/components/charts/Boxplot/Boxplot.js +83 -74
- package/dist/components/charts/Boxplot/Boxplot.js.map +1 -1
- package/dist/components/charts/ChartTooltip/ChartTooltip.cjs +2 -0
- package/dist/components/charts/ChartTooltip/ChartTooltip.cjs.map +1 -0
- package/dist/components/charts/ChartTooltip/ChartTooltip.js +163 -0
- package/dist/components/charts/ChartTooltip/ChartTooltip.js.map +1 -0
- package/dist/components/charts/ChartTooltip/lines.cjs +2 -0
- package/dist/components/charts/ChartTooltip/lines.cjs.map +1 -0
- package/dist/components/charts/ChartTooltip/lines.js +29 -0
- package/dist/components/charts/ChartTooltip/lines.js.map +1 -0
- package/dist/components/charts/Chromatogram/Chromatogram.cjs +1 -1
- package/dist/components/charts/Chromatogram/Chromatogram.cjs.map +1 -1
- package/dist/components/charts/Chromatogram/Chromatogram.js +75 -61
- package/dist/components/charts/Chromatogram/Chromatogram.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.js +116 -108
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.js +32 -32
- package/dist/components/charts/ChromatogramChart/annotations.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.js +6 -6
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/constants.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/constants.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/constants.js +11 -5
- package/dist/components/charts/ChromatogramChart/constants.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.js +38 -49
- package/dist/components/charts/ChromatogramChart/dataProcessing.js.map +1 -1
- package/dist/components/charts/DotPlot/DotPlot.cjs +1 -1
- package/dist/components/charts/DotPlot/DotPlot.cjs.map +1 -1
- package/dist/components/charts/DotPlot/DotPlot.js +57 -63
- package/dist/components/charts/DotPlot/DotPlot.js.map +1 -1
- package/dist/components/charts/Histogram/Histogram.cjs +1 -1
- package/dist/components/charts/Histogram/Histogram.cjs.map +1 -1
- package/dist/components/charts/Histogram/Histogram.js +98 -104
- package/dist/components/charts/Histogram/Histogram.js.map +1 -1
- package/dist/components/charts/LineGraph/LineGraph.cjs +1 -1
- package/dist/components/charts/LineGraph/LineGraph.cjs.map +1 -1
- package/dist/components/charts/LineGraph/LineGraph.js +97 -88
- package/dist/components/charts/LineGraph/LineGraph.js.map +1 -1
- package/dist/components/charts/PieChart/PieChart.cjs +1 -1
- package/dist/components/charts/PieChart/PieChart.cjs.map +1 -1
- package/dist/components/charts/PieChart/PieChart.js +65 -68
- package/dist/components/charts/PieChart/PieChart.js.map +1 -1
- package/dist/components/charts/PlateMap/PlateMap.cjs +1 -1
- package/dist/components/charts/PlateMap/PlateMap.cjs.map +1 -1
- package/dist/components/charts/PlateMap/PlateMap.js +271 -256
- package/dist/components/charts/PlateMap/PlateMap.js.map +1 -1
- package/dist/components/charts/PlateMap/constants.cjs +1 -1
- package/dist/components/charts/PlateMap/constants.cjs.map +1 -1
- package/dist/components/charts/PlateMap/constants.js +20 -29
- package/dist/components/charts/PlateMap/constants.js.map +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.cjs +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.cjs.map +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.js +113 -89
- package/dist/components/charts/ScatterGraph/ScatterGraph.js.map +1 -1
- package/dist/hooks/use-plotly-theme.cjs +1 -1
- package/dist/hooks/use-plotly-theme.cjs.map +1 -1
- package/dist/hooks/use-plotly-theme.js +4 -2
- package/dist/hooks/use-plotly-theme.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +156 -76
- package/dist/index.js +587 -581
- package/dist/index.js.map +1 -1
- package/dist/index.tailwind.css +1 -1
- package/dist/utils/colors.cjs +1 -1
- package/dist/utils/colors.cjs.map +1 -1
- package/dist/utils/colors.js +38 -93
- package/dist/utils/colors.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,157 +1,161 @@
|
|
|
1
|
-
import { jsx as
|
|
1
|
+
import { jsxs as Y, jsx as q } from "react/jsx-runtime";
|
|
2
2
|
import U from "plotly.js-dist";
|
|
3
|
-
import { useRef as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
import { useRef as J, useMemo as v, useEffect as K } from "react";
|
|
4
|
+
import { seriesColor as Q } from "../../../utils/colors.js";
|
|
5
|
+
import { useChartTooltip as V } from "../ChartTooltip/ChartTooltip.js";
|
|
6
|
+
import { groupOverlappingPeaks as Z, createGroupAnnotations as $ } from "./annotations.js";
|
|
7
|
+
import { createBoundaryMarkerTraces as X } from "./boundaryMarkers.js";
|
|
8
|
+
import { CHROMATOGRAM_LAYOUT as s } from "./constants.js";
|
|
9
|
+
import { validateSeriesData as w, applyBaselineCorrection as oo, processUserAnnotations as eo, collectPeaksWithBoundaryData as ro } from "./dataProcessing.js";
|
|
10
|
+
import { detectPeaks as to } from "./peakDetection.js";
|
|
11
|
+
import { usePlotlyTheme as no } from "../../../hooks/use-plotly-theme.js";
|
|
12
|
+
const so = [], ko = ({
|
|
13
|
+
series: a,
|
|
13
14
|
width: y = 900,
|
|
14
15
|
height: h = 500,
|
|
15
16
|
title: f,
|
|
16
17
|
xAxisTitle: k = "Retention Time (min)",
|
|
17
|
-
yAxisTitle:
|
|
18
|
-
annotations: m =
|
|
19
|
-
xRange:
|
|
20
|
-
yRange:
|
|
21
|
-
showLegend:
|
|
22
|
-
showGridX:
|
|
23
|
-
showGridY:
|
|
24
|
-
showMarkers:
|
|
25
|
-
markerSize:
|
|
18
|
+
yAxisTitle: I = "Signal (mAU)",
|
|
19
|
+
annotations: m = so,
|
|
20
|
+
xRange: x,
|
|
21
|
+
yRange: T,
|
|
22
|
+
showLegend: M = !0,
|
|
23
|
+
showGridX: N = !0,
|
|
24
|
+
showGridY: R = !0,
|
|
25
|
+
showMarkers: _ = !1,
|
|
26
|
+
markerSize: z = 4,
|
|
26
27
|
showCrosshairs: p = !1,
|
|
27
|
-
baselineCorrection:
|
|
28
|
+
baselineCorrection: B = "none",
|
|
28
29
|
baselineWindowSize: E = 50,
|
|
29
30
|
peakDetectionOptions: l,
|
|
30
31
|
showPeakAreas: G = !1,
|
|
31
32
|
boundaryMarkers: O = "none",
|
|
32
|
-
annotationOverlapThreshold:
|
|
33
|
-
showExportButton:
|
|
33
|
+
annotationOverlapThreshold: b = 0.4,
|
|
34
|
+
showExportButton: C = !0
|
|
34
35
|
}) => {
|
|
35
|
-
const d = l !== void 0,
|
|
36
|
-
|
|
36
|
+
const d = l !== void 0, L = J(null), o = no(), { bindTooltip: S, tooltipElement: W } = V({
|
|
37
|
+
xLabel: k,
|
|
38
|
+
yLabel: I
|
|
39
|
+
}), n = v(() => a.map((e) => {
|
|
40
|
+
const t = w(e.x, e.y);
|
|
37
41
|
return {
|
|
38
|
-
...
|
|
39
|
-
x:
|
|
40
|
-
y:
|
|
42
|
+
...e,
|
|
43
|
+
x: t.x,
|
|
44
|
+
y: oo(t.y, B, E)
|
|
41
45
|
};
|
|
42
|
-
}), [
|
|
46
|
+
}), [a, B, E]), A = v(() => {
|
|
43
47
|
if (m.length === 0 || n.length === 0)
|
|
44
48
|
return m;
|
|
45
|
-
const { x:
|
|
46
|
-
return
|
|
47
|
-
}, [m, n]),
|
|
48
|
-
const
|
|
49
|
-
return d && l && n.forEach((
|
|
50
|
-
const u =
|
|
51
|
-
u.length > 0 &&
|
|
52
|
-
}),
|
|
49
|
+
const { x: e, y: t } = n[0];
|
|
50
|
+
return eo(m, e, t);
|
|
51
|
+
}, [m, n]), P = v(() => {
|
|
52
|
+
const e = [];
|
|
53
|
+
return d && l && n.forEach((t, i) => {
|
|
54
|
+
const u = to(t.x, t.y, l);
|
|
55
|
+
u.length > 0 && e.push({ peaks: u, seriesIndex: i });
|
|
56
|
+
}), e;
|
|
53
57
|
}, [n, d, l]);
|
|
54
|
-
return
|
|
55
|
-
const
|
|
56
|
-
if (!
|
|
57
|
-
const
|
|
58
|
-
const g =
|
|
59
|
-
x:
|
|
60
|
-
y:
|
|
58
|
+
return K(() => {
|
|
59
|
+
const e = L.current;
|
|
60
|
+
if (!e || a.length === 0) return;
|
|
61
|
+
const t = n.map((r, c) => {
|
|
62
|
+
const g = Q(c, r.color), H = {
|
|
63
|
+
x: r.x,
|
|
64
|
+
y: r.y,
|
|
61
65
|
type: "scatter",
|
|
62
|
-
mode:
|
|
63
|
-
name:
|
|
66
|
+
mode: _ ? "lines+markers" : "lines",
|
|
67
|
+
name: r.name,
|
|
64
68
|
line: {
|
|
65
69
|
color: g,
|
|
66
70
|
width: 1.5
|
|
67
71
|
},
|
|
68
|
-
|
|
72
|
+
hoverinfo: "none"
|
|
69
73
|
};
|
|
70
|
-
return
|
|
71
|
-
size:
|
|
74
|
+
return _ && (H.marker = {
|
|
75
|
+
size: z,
|
|
72
76
|
color: g
|
|
73
|
-
}),
|
|
77
|
+
}), H;
|
|
74
78
|
});
|
|
75
79
|
if (O !== "none") {
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
78
|
-
const c =
|
|
79
|
-
|
|
80
|
+
const r = ro(P, A, n);
|
|
81
|
+
if (r.length > 0) {
|
|
82
|
+
const c = X(r);
|
|
83
|
+
t.push(...c);
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
86
|
const i = [];
|
|
83
|
-
|
|
84
|
-
i.push({ peak:
|
|
85
|
-
}), G && d &&
|
|
86
|
-
|
|
87
|
+
A.forEach((r) => {
|
|
88
|
+
i.push({ peak: r, seriesIndex: -1 });
|
|
89
|
+
}), G && d && P.forEach(({ peaks: r, seriesIndex: c }) => {
|
|
90
|
+
r.forEach((g) => {
|
|
87
91
|
i.push({ peak: g, seriesIndex: c });
|
|
88
92
|
});
|
|
89
93
|
});
|
|
90
|
-
const u =
|
|
91
|
-
for (const
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
+
const u = Z(i, b), D = [];
|
|
95
|
+
for (const r of u)
|
|
96
|
+
D.push(...$(r));
|
|
97
|
+
const j = {
|
|
94
98
|
title: f ? {
|
|
95
99
|
text: f,
|
|
96
100
|
font: {
|
|
97
101
|
size: 20,
|
|
98
102
|
family: "Inter, sans-serif",
|
|
99
|
-
color:
|
|
103
|
+
color: o.textColor
|
|
100
104
|
}
|
|
101
105
|
} : void 0,
|
|
102
106
|
width: y,
|
|
103
107
|
height: h,
|
|
104
108
|
margin: {
|
|
105
|
-
l:
|
|
106
|
-
r:
|
|
107
|
-
b:
|
|
108
|
-
t: f ?
|
|
109
|
-
pad:
|
|
109
|
+
l: s.MARGIN_LEFT,
|
|
110
|
+
r: s.MARGIN_RIGHT,
|
|
111
|
+
b: s.MARGIN_BOTTOM,
|
|
112
|
+
t: f ? s.MARGIN_TOP_WITH_TITLE : s.MARGIN_TOP_NO_TITLE,
|
|
113
|
+
pad: s.MARGIN_PAD
|
|
110
114
|
},
|
|
111
|
-
paper_bgcolor:
|
|
112
|
-
plot_bgcolor:
|
|
115
|
+
paper_bgcolor: o.paperBg,
|
|
116
|
+
plot_bgcolor: o.plotBg,
|
|
113
117
|
font: { family: "Inter, sans-serif" },
|
|
114
118
|
hovermode: p ? "x" : "x unified",
|
|
115
119
|
dragmode: "zoom",
|
|
116
120
|
xaxis: {
|
|
117
121
|
title: {
|
|
118
122
|
text: k,
|
|
119
|
-
font: { size: 14, color:
|
|
123
|
+
font: { size: 14, color: o.textSecondary, family: "Inter, sans-serif" },
|
|
120
124
|
standoff: 15
|
|
121
125
|
},
|
|
122
|
-
showgrid:
|
|
123
|
-
gridcolor:
|
|
124
|
-
linecolor:
|
|
126
|
+
showgrid: N,
|
|
127
|
+
gridcolor: o.gridColor,
|
|
128
|
+
linecolor: o.lineColor,
|
|
125
129
|
linewidth: 1,
|
|
126
|
-
range:
|
|
127
|
-
autorange: !
|
|
130
|
+
range: x,
|
|
131
|
+
autorange: !x,
|
|
128
132
|
zeroline: !1,
|
|
129
|
-
tickfont: { size: 12, color:
|
|
133
|
+
tickfont: { size: 12, color: o.textColor, family: "Inter, sans-serif" },
|
|
130
134
|
showspikes: p,
|
|
131
135
|
spikemode: "across",
|
|
132
136
|
spikesnap: "cursor",
|
|
133
|
-
spikecolor:
|
|
137
|
+
spikecolor: o.spikeColor,
|
|
134
138
|
spikethickness: 1,
|
|
135
139
|
spikedash: "dot"
|
|
136
140
|
},
|
|
137
141
|
yaxis: {
|
|
138
142
|
title: {
|
|
139
|
-
text:
|
|
140
|
-
font: { size: 14, color:
|
|
143
|
+
text: I,
|
|
144
|
+
font: { size: 14, color: o.textSecondary, family: "Inter, sans-serif" },
|
|
141
145
|
standoff: 10
|
|
142
146
|
},
|
|
143
|
-
showgrid:
|
|
144
|
-
gridcolor:
|
|
145
|
-
linecolor:
|
|
147
|
+
showgrid: R,
|
|
148
|
+
gridcolor: o.gridColor,
|
|
149
|
+
linecolor: o.lineColor,
|
|
146
150
|
linewidth: 1,
|
|
147
|
-
range:
|
|
148
|
-
autorange: !
|
|
151
|
+
range: T,
|
|
152
|
+
autorange: !T,
|
|
149
153
|
zeroline: !1,
|
|
150
|
-
tickfont: { size: 12, color:
|
|
154
|
+
tickfont: { size: 12, color: o.textColor, family: "Inter, sans-serif" },
|
|
151
155
|
showspikes: p,
|
|
152
156
|
spikemode: "across",
|
|
153
157
|
spikesnap: "cursor",
|
|
154
|
-
spikecolor:
|
|
158
|
+
spikecolor: o.spikeColor,
|
|
155
159
|
spikethickness: 1,
|
|
156
160
|
spikedash: "dot"
|
|
157
161
|
},
|
|
@@ -161,20 +165,20 @@ const de = ({
|
|
|
161
165
|
xanchor: "center",
|
|
162
166
|
yanchor: "top",
|
|
163
167
|
orientation: "h",
|
|
164
|
-
font: { size: 12, color:
|
|
168
|
+
font: { size: 12, color: o.textColor, family: "Inter, sans-serif" }
|
|
165
169
|
},
|
|
166
|
-
showlegend:
|
|
167
|
-
annotations:
|
|
168
|
-
},
|
|
170
|
+
showlegend: M && a.length > 1,
|
|
171
|
+
annotations: D
|
|
172
|
+
}, F = {
|
|
169
173
|
responsive: !0,
|
|
170
174
|
displayModeBar: !0,
|
|
171
175
|
displaylogo: !1,
|
|
172
176
|
modeBarButtonsToRemove: [
|
|
173
177
|
"lasso2d",
|
|
174
178
|
"select2d",
|
|
175
|
-
...
|
|
179
|
+
...C ? [] : ["toImage"]
|
|
176
180
|
],
|
|
177
|
-
...
|
|
181
|
+
...C && {
|
|
178
182
|
toImageButtonOptions: {
|
|
179
183
|
format: "png",
|
|
180
184
|
filename: "chromatogram",
|
|
@@ -183,37 +187,41 @@ const de = ({
|
|
|
183
187
|
}
|
|
184
188
|
}
|
|
185
189
|
};
|
|
186
|
-
return U.newPlot(t,
|
|
187
|
-
|
|
190
|
+
return U.newPlot(e, t, j, F), S(e), () => {
|
|
191
|
+
e && U.purge(e);
|
|
188
192
|
};
|
|
189
193
|
}, [
|
|
190
194
|
n,
|
|
191
|
-
|
|
192
|
-
|
|
195
|
+
P,
|
|
196
|
+
a.length,
|
|
193
197
|
y,
|
|
194
198
|
h,
|
|
195
199
|
f,
|
|
196
200
|
k,
|
|
197
|
-
x,
|
|
198
|
-
R,
|
|
199
201
|
I,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
+
A,
|
|
203
|
+
x,
|
|
204
|
+
T,
|
|
202
205
|
M,
|
|
206
|
+
N,
|
|
207
|
+
R,
|
|
208
|
+
_,
|
|
203
209
|
z,
|
|
204
|
-
T,
|
|
205
|
-
B,
|
|
206
210
|
p,
|
|
207
211
|
d,
|
|
208
212
|
l,
|
|
209
213
|
G,
|
|
210
214
|
O,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
+
b,
|
|
216
|
+
C,
|
|
217
|
+
o,
|
|
218
|
+
S
|
|
219
|
+
]), /* @__PURE__ */ Y("div", { className: "chromatogram-chart-container relative", children: [
|
|
220
|
+
/* @__PURE__ */ q("div", { ref: L, style: { width: "100%", height: "100%" } }),
|
|
221
|
+
W
|
|
222
|
+
] });
|
|
215
223
|
};
|
|
216
224
|
export {
|
|
217
|
-
|
|
225
|
+
ko as ChromatogramChart
|
|
218
226
|
};
|
|
219
227
|
//# sourceMappingURL=ChromatogramChart.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChromatogramChart.js","sources":["../../../../src/components/charts/ChromatogramChart/ChromatogramChart.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useMemo, useRef } from \"react\";\n\nimport { CHART_COLORS } from \"../../../utils/colors\";\n\n\nimport {\n groupOverlappingPeaks,\n createGroupAnnotations,\n} from \"./annotations\";\nimport { createBoundaryMarkerTraces } from \"./boundaryMarkers\";\nimport { CHROMATOGRAM_LAYOUT } from \"./constants\";\nimport {\n validateSeriesData,\n applyBaselineCorrection,\n buildHoverExtraContent,\n collectPeaksWithBoundaryData,\n processUserAnnotations,\n} from \"./dataProcessing\";\nimport { detectPeaks } from \"./peakDetection\";\n\nimport type {\n ChromatogramSeries,\n PeakAnnotation,\n BaselineCorrectionMethod,\n BoundaryMarkerStyle,\n BoundaryMarkerType,\n PeakDetectionOptions,\n ChromatogramChartProps,\n PeakWithMeta,\n} from \"./types\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\n// Re-export types for external use\nexport type {\n ChromatogramSeries,\n PeakAnnotation,\n BaselineCorrectionMethod,\n BoundaryMarkerStyle,\n BoundaryMarkerType,\n PeakDetectionOptions,\n ChromatogramChartProps,\n};\n\n\nconst ChromatogramChart: React.FC<ChromatogramChartProps> = ({\n series,\n width = 900,\n height = 500,\n title,\n xAxisTitle = \"Retention Time (min)\",\n yAxisTitle = \"Signal (mAU)\",\n annotations = [],\n xRange,\n yRange,\n showLegend = true,\n showGridX = true,\n showGridY = true,\n showMarkers = false,\n markerSize = 4,\n showCrosshairs = false,\n baselineCorrection = \"none\",\n baselineWindowSize = 50,\n peakDetectionOptions,\n showPeakAreas = false,\n boundaryMarkers = \"none\",\n annotationOverlapThreshold = 0.4,\n showExportButton = true,\n}) => {\n // Derive peak detection state from options\n const enablePeakDetection = peakDetectionOptions !== undefined;\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n\n // Memoize processed series with baseline correction\n const processedSeries = useMemo(() => {\n return series.map((s) => {\n const validated = validateSeriesData(s.x, s.y);\n return {\n ...s,\n x: validated.x,\n y: applyBaselineCorrection(validated.y, baselineCorrection, baselineWindowSize),\n };\n });\n }, [series, baselineCorrection, baselineWindowSize]);\n\n // Process user annotations to convert startX/endX to indices and compute areas\n const processedAnnotations = useMemo(() => {\n if (annotations.length === 0 || processedSeries.length === 0) {\n return annotations;\n }\n // Use first series data for index lookup (user annotations apply to first series)\n const { x, y } = processedSeries[0];\n return processUserAnnotations(annotations, x, y);\n }, [annotations, processedSeries]);\n\n // Memoize peak detection results\n const allDetectedPeaks = useMemo(() => {\n const peaks: { peaks: PeakAnnotation[]; seriesIndex: number }[] = [];\n if (enablePeakDetection && peakDetectionOptions) {\n processedSeries.forEach((s, index) => {\n const detected = detectPeaks(s.x, s.y, peakDetectionOptions);\n if (detected.length > 0) {\n peaks.push({ peaks: detected, seriesIndex: index });\n }\n });\n }\n return peaks;\n }, [processedSeries, enablePeakDetection, peakDetectionOptions]);\n\n useEffect(() => {\n const currentRef = plotRef.current;\n if (!currentRef || series.length === 0) return;\n\n // Build trace data with auto-assigned colors\n const plotData: Plotly.Data[] = processedSeries.map((s, index) => {\n const traceColor = s.color || CHART_COLORS[index % CHART_COLORS.length];\n const extraContent = buildHoverExtraContent(s.name, s.metadata);\n\n const trace: Plotly.Data = {\n x: s.x,\n y: s.y,\n type: \"scatter\" as const,\n mode: showMarkers ? \"lines+markers\" as const : \"lines\" as const,\n name: s.name,\n line: {\n color: traceColor,\n width: 1.5,\n },\n hovertemplate: `%{x:.2f} ${xAxisTitle}<br>%{y:.2f} ${yAxisTitle}<extra>${extraContent}</extra>`,\n };\n if (showMarkers) {\n trace.marker = {\n size: markerSize,\n color: traceColor,\n };\n }\n return trace;\n });\n\n // Add peak boundary markers if enabled\n if (boundaryMarkers !== \"none\") {\n const peaksWithData = collectPeaksWithBoundaryData(allDetectedPeaks, processedAnnotations, processedSeries);\n if (peaksWithData.length > 0) {\n const boundaryTraces = createBoundaryMarkerTraces(peaksWithData);\n plotData.push(...boundaryTraces);\n }\n }\n\n // Collect all peaks for unified staggering logic\n const allPeaksWithMeta: PeakWithMeta[] = [];\n\n // Add user-defined annotations (seriesIndex -1 indicates user-defined)\n processedAnnotations.forEach((ann) => {\n allPeaksWithMeta.push({ peak: ann, seriesIndex: -1 });\n });\n\n // Add auto-detected peaks if enabled\n if (showPeakAreas && enablePeakDetection) {\n allDetectedPeaks.forEach(({ peaks, seriesIndex }) => {\n peaks.forEach((peak) => {\n allPeaksWithMeta.push({ peak, seriesIndex });\n });\n });\n }\n\n // Group all overlapping peaks and create annotations with staggering\n const groups = groupOverlappingPeaks(allPeaksWithMeta, annotationOverlapThreshold);\n const plotlyAnnotations: Partial<Plotly.Annotations>[] = [];\n\n for (const group of groups) {\n plotlyAnnotations.push(...createGroupAnnotations(group));\n }\n\n const layout: Partial<Plotly.Layout> = {\n title: title\n ? {\n text: title,\n font: {\n size: 20,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n }\n : undefined,\n width,\n height,\n margin: {\n l: CHROMATOGRAM_LAYOUT.MARGIN_LEFT,\n r: CHROMATOGRAM_LAYOUT.MARGIN_RIGHT,\n b: CHROMATOGRAM_LAYOUT.MARGIN_BOTTOM,\n t: title ? CHROMATOGRAM_LAYOUT.MARGIN_TOP_WITH_TITLE : CHROMATOGRAM_LAYOUT.MARGIN_TOP_NO_TITLE,\n pad: CHROMATOGRAM_LAYOUT.MARGIN_PAD,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: { family: \"Inter, sans-serif\" },\n hovermode: showCrosshairs ? \"x\" as const : \"x unified\" as const,\n dragmode: \"zoom\" as const,\n xaxis: {\n title: {\n text: xAxisTitle,\n font: { size: 14, color: theme.textSecondary, family: \"Inter, sans-serif\" },\n standoff: 15,\n },\n showgrid: showGridX,\n gridcolor: theme.gridColor,\n linecolor: theme.lineColor,\n linewidth: 1,\n range: xRange,\n autorange: !xRange,\n zeroline: false,\n tickfont: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n showspikes: showCrosshairs,\n spikemode: \"across\" as const,\n spikesnap: \"cursor\" as const,\n spikecolor: theme.spikeColor,\n spikethickness: 1,\n spikedash: \"dot\" as const,\n },\n yaxis: {\n title: {\n text: yAxisTitle,\n font: { size: 14, color: theme.textSecondary, family: \"Inter, sans-serif\" },\n standoff: 10,\n },\n showgrid: showGridY,\n gridcolor: theme.gridColor,\n linecolor: theme.lineColor,\n linewidth: 1,\n range: yRange,\n autorange: !yRange,\n zeroline: false,\n tickfont: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n showspikes: showCrosshairs,\n spikemode: \"across\" as const,\n spikesnap: \"cursor\" as const,\n spikecolor: theme.spikeColor,\n spikethickness: 1,\n spikedash: \"dot\" as const,\n },\n legend: {\n x: 0.5,\n y: -0.15,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n },\n showlegend: showLegend && series.length > 1,\n annotations: plotlyAnnotations,\n };\n\n const config: Partial<Plotly.Config> = {\n responsive: true,\n displayModeBar: true,\n displaylogo: false,\n modeBarButtonsToRemove: [\n \"lasso2d\",\n \"select2d\",\n ...(showExportButton ? [] : [\"toImage\"] as Plotly.ModeBarDefaultButtons[]),\n ] as Plotly.ModeBarDefaultButtons[],\n ...(showExportButton && {\n toImageButtonOptions: {\n format: \"png\",\n filename: \"chromatogram\",\n width: width,\n height: height,\n },\n }),\n };\n\n Plotly.newPlot(currentRef, plotData, layout, config);\n\n return () => {\n if (currentRef) {\n Plotly.purge(currentRef);\n }\n };\n }, [\n processedSeries, allDetectedPeaks, series.length, width, height, title, xAxisTitle, yAxisTitle,\n processedAnnotations, xRange, yRange, showLegend, showGridX, showGridY, showMarkers, markerSize,\n showCrosshairs, enablePeakDetection, peakDetectionOptions, showPeakAreas, boundaryMarkers,\n annotationOverlapThreshold, showExportButton, theme,\n ]);\n\n return (\n <div className=\"chromatogram-chart-container\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n </div>\n );\n};\n\nexport { ChromatogramChart };\n\n"],"names":["ChromatogramChart","series","width","height","title","xAxisTitle","yAxisTitle","annotations","xRange","yRange","showLegend","showGridX","showGridY","showMarkers","markerSize","showCrosshairs","baselineCorrection","baselineWindowSize","peakDetectionOptions","showPeakAreas","boundaryMarkers","annotationOverlapThreshold","showExportButton","enablePeakDetection","plotRef","useRef","theme","usePlotlyTheme","processedSeries","useMemo","s","validated","validateSeriesData","applyBaselineCorrection","processedAnnotations","x","y","processUserAnnotations","allDetectedPeaks","peaks","index","detected","detectPeaks","useEffect","currentRef","plotData","traceColor","CHART_COLORS","extraContent","buildHoverExtraContent","trace","peaksWithData","collectPeaksWithBoundaryData","boundaryTraces","createBoundaryMarkerTraces","allPeaksWithMeta","ann","seriesIndex","peak","groups","groupOverlappingPeaks","plotlyAnnotations","group","createGroupAnnotations","layout","CHROMATOGRAM_LAYOUT","config","Plotly","jsx"],"mappings":";;;;;;;;;;AA8CA,MAAMA,KAAsD,CAAC;AAAA,EAC3D,QAAAC;AAAA,EACA,OAAAC,IAAQ;AAAA,EACR,QAAAC,IAAS;AAAA,EACT,OAAAC;AAAA,EACA,YAAAC,IAAa;AAAA,EACb,YAAAC,IAAa;AAAA,EACb,aAAAC,IAAc,CAAA;AAAA,EACd,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,YAAAC,IAAa;AAAA,EACb,WAAAC,IAAY;AAAA,EACZ,WAAAC,IAAY;AAAA,EACZ,aAAAC,IAAc;AAAA,EACd,YAAAC,IAAa;AAAA,EACb,gBAAAC,IAAiB;AAAA,EACjB,oBAAAC,IAAqB;AAAA,EACrB,oBAAAC,IAAqB;AAAA,EACrB,sBAAAC;AAAA,EACA,eAAAC,IAAgB;AAAA,EAChB,iBAAAC,IAAkB;AAAA,EAClB,4BAAAC,IAA6B;AAAA,EAC7B,kBAAAC,IAAmB;AACrB,MAAM;AAEJ,QAAMC,IAAsBL,MAAyB,QAC/CM,IAAUC,EAAuB,IAAI,GACrCC,IAAQC,GAAA,GAGRC,IAAkBC,EAAQ,MACvB5B,EAAO,IAAI,CAAC6B,MAAM;AACvB,UAAMC,IAAYC,EAAmBF,EAAE,GAAGA,EAAE,CAAC;AAC7C,WAAO;AAAA,MACL,GAAGA;AAAA,MACH,GAAGC,EAAU;AAAA,MACb,GAAGE,EAAwBF,EAAU,GAAGf,GAAoBC,CAAkB;AAAA,IAAA;AAAA,EAElF,CAAC,GACA,CAAChB,GAAQe,GAAoBC,CAAkB,CAAC,GAG7CiB,IAAuBL,EAAQ,MAAM;AACzC,QAAItB,EAAY,WAAW,KAAKqB,EAAgB,WAAW;AACzD,aAAOrB;AAGT,UAAM,EAAE,GAAA4B,GAAG,GAAAC,MAAMR,EAAgB,CAAC;AAClC,WAAOS,EAAuB9B,GAAa4B,GAAGC,CAAC;AAAA,EACjD,GAAG,CAAC7B,GAAaqB,CAAe,CAAC,GAG3BU,IAAmBT,EAAQ,MAAM;AACrC,UAAMU,IAA4D,CAAA;AAClE,WAAIhB,KAAuBL,KACzBU,EAAgB,QAAQ,CAACE,GAAGU,MAAU;AACpC,YAAMC,IAAWC,GAAYZ,EAAE,GAAGA,EAAE,GAAGZ,CAAoB;AAC3D,MAAIuB,EAAS,SAAS,KACpBF,EAAM,KAAK,EAAE,OAAOE,GAAU,aAAaD,GAAO;AAAA,IAEtD,CAAC,GAEID;AAAA,EACT,GAAG,CAACX,GAAiBL,GAAqBL,CAAoB,CAAC;AAE/D,SAAAyB,EAAU,MAAM;AACd,UAAMC,IAAapB,EAAQ;AAC3B,QAAI,CAACoB,KAAc3C,EAAO,WAAW,EAAG;AAGxC,UAAM4C,IAA0BjB,EAAgB,IAAI,CAACE,GAAGU,MAAU;AAChE,YAAMM,IAAahB,EAAE,SAASiB,EAAaP,IAAQO,EAAa,MAAM,GAChEC,IAAeC,EAAuBnB,EAAE,MAAMA,EAAE,QAAQ,GAExDoB,IAAqB;AAAA,QACzB,GAAGpB,EAAE;AAAA,QACL,GAAGA,EAAE;AAAA,QACL,MAAM;AAAA,QACN,MAAMjB,IAAc,kBAA2B;AAAA,QAC/C,MAAMiB,EAAE;AAAA,QACR,MAAM;AAAA,UACJ,OAAOgB;AAAA,UACP,OAAO;AAAA,QAAA;AAAA,QAET,eAAe,YAAYzC,CAAU,gBAAgBC,CAAU,UAAU0C,CAAY;AAAA,MAAA;AAEvF,aAAInC,MACFqC,EAAM,SAAS;AAAA,QACb,MAAMpC;AAAA,QACN,OAAOgC;AAAA,MAAA,IAGJI;AAAA,IACT,CAAC;AAGD,QAAI9B,MAAoB,QAAQ;AAC9B,YAAM+B,IAAgBC,GAA6Bd,GAAkBJ,GAAsBN,CAAe;AAC1G,UAAIuB,EAAc,SAAS,GAAG;AAC5B,cAAME,IAAiBC,EAA2BH,CAAa;AAC/D,QAAAN,EAAS,KAAK,GAAGQ,CAAc;AAAA,MACjC;AAAA,IACF;AAGA,UAAME,IAAmC,CAAA;AAGzC,IAAArB,EAAqB,QAAQ,CAACsB,MAAQ;AACpC,MAAAD,EAAiB,KAAK,EAAE,MAAMC,GAAK,aAAa,IAAI;AAAA,IACtD,CAAC,GAGGrC,KAAiBI,KACnBe,EAAiB,QAAQ,CAAC,EAAE,OAAAC,GAAO,aAAAkB,QAAkB;AACnD,MAAAlB,EAAM,QAAQ,CAACmB,MAAS;AACtB,QAAAH,EAAiB,KAAK,EAAE,MAAAG,GAAM,aAAAD,EAAA,CAAa;AAAA,MAC7C,CAAC;AAAA,IACH,CAAC;AAIH,UAAME,IAASC,EAAsBL,GAAkBlC,CAA0B,GAC3EwC,IAAmD,CAAA;AAEzD,eAAWC,KAASH;AAClB,MAAAE,EAAkB,KAAK,GAAGE,EAAuBD,CAAK,CAAC;AAGzD,UAAME,IAAiC;AAAA,MACrC,OAAO5D,IACH;AAAA,QACE,MAAMA;AAAA,QACN,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,OAAOsB,EAAM;AAAA,QAAA;AAAA,MACf,IAEF;AAAA,MACJ,OAAAxB;AAAA,MACA,QAAAC;AAAA,MACA,QAAQ;AAAA,QACN,GAAG8D,EAAoB;AAAA,QACvB,GAAGA,EAAoB;AAAA,QACvB,GAAGA,EAAoB;AAAA,QACvB,GAAG7D,IAAQ6D,EAAoB,wBAAwBA,EAAoB;AAAA,QAC3E,KAAKA,EAAoB;AAAA,MAAA;AAAA,MAE3B,eAAevC,EAAM;AAAA,MACrB,cAAcA,EAAM;AAAA,MACpB,MAAM,EAAE,QAAQ,oBAAA;AAAA,MAChB,WAAWX,IAAiB,MAAe;AAAA,MAC3C,UAAU;AAAA,MACV,OAAO;AAAA,QACL,OAAO;AAAA,UACL,MAAMV;AAAA,UACN,MAAM,EAAE,MAAM,IAAI,OAAOqB,EAAM,eAAe,QAAQ,oBAAA;AAAA,UACtD,UAAU;AAAA,QAAA;AAAA,QAEZ,UAAUf;AAAA,QACV,WAAWe,EAAM;AAAA,QACjB,WAAWA,EAAM;AAAA,QACjB,WAAW;AAAA,QACX,OAAOlB;AAAA,QACP,WAAW,CAACA;AAAA,QACZ,UAAU;AAAA,QACV,UAAU,EAAE,MAAM,IAAI,OAAOkB,EAAM,WAAW,QAAQ,oBAAA;AAAA,QACtD,YAAYX;AAAA,QACZ,WAAW;AAAA,QACX,WAAW;AAAA,QACX,YAAYW,EAAM;AAAA,QAClB,gBAAgB;AAAA,QAChB,WAAW;AAAA,MAAA;AAAA,MAEb,OAAO;AAAA,QACL,OAAO;AAAA,UACL,MAAMpB;AAAA,UACN,MAAM,EAAE,MAAM,IAAI,OAAOoB,EAAM,eAAe,QAAQ,oBAAA;AAAA,UACtD,UAAU;AAAA,QAAA;AAAA,QAEZ,UAAUd;AAAA,QACV,WAAWc,EAAM;AAAA,QACjB,WAAWA,EAAM;AAAA,QACjB,WAAW;AAAA,QACX,OAAOjB;AAAA,QACP,WAAW,CAACA;AAAA,QACZ,UAAU;AAAA,QACV,UAAU,EAAE,MAAM,IAAI,OAAOiB,EAAM,WAAW,QAAQ,oBAAA;AAAA,QACtD,YAAYX;AAAA,QACZ,WAAW;AAAA,QACX,WAAW;AAAA,QACX,YAAYW,EAAM;AAAA,QAClB,gBAAgB;AAAA,QAChB,WAAW;AAAA,MAAA;AAAA,MAEb,QAAQ;AAAA,QACN,GAAG;AAAA,QACH,GAAG;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,MAAM,EAAE,MAAM,IAAI,OAAOA,EAAM,WAAW,QAAQ,oBAAA;AAAA,MAAoB;AAAA,MAExE,YAAYhB,KAAcT,EAAO,SAAS;AAAA,MAC1C,aAAa4D;AAAA,IAAA,GAGTK,IAAiC;AAAA,MACrC,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,wBAAwB;AAAA,QACtB;AAAA,QACA;AAAA,QACA,GAAI5C,IAAmB,CAAA,IAAK,CAAC,SAAS;AAAA,MAAA;AAAA,MAExC,GAAIA,KAAoB;AAAA,QACtB,sBAAsB;AAAA,UACpB,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAApB;AAAA,UACA,QAAAC;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAGF,WAAAgE,EAAO,QAAQvB,GAAYC,GAAUmB,GAAQE,CAAM,GAE5C,MAAM;AACX,MAAItB,KACFuB,EAAO,MAAMvB,CAAU;AAAA,IAE3B;AAAA,EACF,GAAG;AAAA,IACDhB;AAAA,IAAiBU;AAAA,IAAkBrC,EAAO;AAAA,IAAQC;AAAA,IAAOC;AAAA,IAAQC;AAAA,IAAOC;AAAA,IAAYC;AAAA,IACpF4B;AAAA,IAAsB1B;AAAA,IAAQC;AAAA,IAAQC;AAAA,IAAYC;AAAA,IAAWC;AAAA,IAAWC;AAAA,IAAaC;AAAA,IACrFC;AAAA,IAAgBQ;AAAA,IAAqBL;AAAA,IAAsBC;AAAA,IAAeC;AAAA,IAC1EC;AAAA,IAA4BC;AAAA,IAAkBI;AAAA,EAAA,CAC/C,GAGC,gBAAA0C,EAAC,OAAA,EAAI,WAAU,gCACb,4BAAC,OAAA,EAAI,KAAK5C,GAAS,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAA,GAAU,GAC/D;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"ChromatogramChart.js","sources":["../../../../src/components/charts/ChromatogramChart/ChromatogramChart.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useMemo, useRef } from \"react\";\n\nimport { seriesColor } from \"../../../utils/colors\";\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport {\n groupOverlappingPeaks,\n createGroupAnnotations,\n} from \"./annotations\";\nimport { createBoundaryMarkerTraces } from \"./boundaryMarkers\";\nimport { CHROMATOGRAM_LAYOUT } from \"./constants\";\nimport {\n validateSeriesData,\n applyBaselineCorrection,\n collectPeaksWithBoundaryData,\n processUserAnnotations,\n} from \"./dataProcessing\";\nimport { detectPeaks } from \"./peakDetection\";\n\nimport type {\n ChromatogramSeries,\n PeakAnnotation,\n BaselineCorrectionMethod,\n BoundaryMarkerStyle,\n BoundaryMarkerType,\n PeakDetectionOptions,\n ChromatogramChartProps,\n PeakWithMeta,\n} from \"./types\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\n// Re-export types for external use\nexport type {\n ChromatogramSeries,\n PeakAnnotation,\n BaselineCorrectionMethod,\n BoundaryMarkerStyle,\n BoundaryMarkerType,\n PeakDetectionOptions,\n ChromatogramChartProps,\n};\n\n\n// Stable default so the no-annotations case keeps a constant identity; an\n// inline `[]` default would change every render, re-running the plot effect\n// (and tearing down the hover tooltip) on each re-render.\nconst EMPTY_ANNOTATIONS: PeakAnnotation[] = [];\n\nconst ChromatogramChart: React.FC<ChromatogramChartProps> = ({\n series,\n width = 900,\n height = 500,\n title,\n xAxisTitle = \"Retention Time (min)\",\n yAxisTitle = \"Signal (mAU)\",\n annotations = EMPTY_ANNOTATIONS,\n xRange,\n yRange,\n showLegend = true,\n showGridX = true,\n showGridY = true,\n showMarkers = false,\n markerSize = 4,\n showCrosshairs = false,\n baselineCorrection = \"none\",\n baselineWindowSize = 50,\n peakDetectionOptions,\n showPeakAreas = false,\n boundaryMarkers = \"none\",\n annotationOverlapThreshold = 0.4,\n showExportButton = true,\n}) => {\n // Derive peak detection state from options\n const enablePeakDetection = peakDetectionOptions !== undefined;\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({\n xLabel: xAxisTitle,\n yLabel: yAxisTitle,\n });\n\n // Memoize processed series with baseline correction\n const processedSeries = useMemo(() => {\n return series.map((s) => {\n const validated = validateSeriesData(s.x, s.y);\n return {\n ...s,\n x: validated.x,\n y: applyBaselineCorrection(validated.y, baselineCorrection, baselineWindowSize),\n };\n });\n }, [series, baselineCorrection, baselineWindowSize]);\n\n // Process user annotations to convert startX/endX to indices and compute areas\n const processedAnnotations = useMemo(() => {\n if (annotations.length === 0 || processedSeries.length === 0) {\n return annotations;\n }\n // Use first series data for index lookup (user annotations apply to first series)\n const { x, y } = processedSeries[0];\n return processUserAnnotations(annotations, x, y);\n }, [annotations, processedSeries]);\n\n // Memoize peak detection results\n const allDetectedPeaks = useMemo(() => {\n const peaks: { peaks: PeakAnnotation[]; seriesIndex: number }[] = [];\n if (enablePeakDetection && peakDetectionOptions) {\n processedSeries.forEach((s, index) => {\n const detected = detectPeaks(s.x, s.y, peakDetectionOptions);\n if (detected.length > 0) {\n peaks.push({ peaks: detected, seriesIndex: index });\n }\n });\n }\n return peaks;\n }, [processedSeries, enablePeakDetection, peakDetectionOptions]);\n\n useEffect(() => {\n const currentRef = plotRef.current;\n if (!currentRef || series.length === 0) return;\n\n // Build trace data with auto-assigned colors\n const plotData: Plotly.Data[] = processedSeries.map((s, index) => {\n const traceColor = seriesColor(index, s.color);\n\n const trace: Plotly.Data = {\n x: s.x,\n y: s.y,\n type: \"scatter\" as const,\n mode: showMarkers ? \"lines+markers\" as const : \"lines\" as const,\n name: s.name,\n line: {\n color: traceColor,\n width: 1.5,\n },\n hoverinfo: \"none\" as const,\n };\n if (showMarkers) {\n trace.marker = {\n size: markerSize,\n color: traceColor,\n };\n }\n return trace;\n });\n\n // Add peak boundary markers if enabled\n if (boundaryMarkers !== \"none\") {\n const peaksWithData = collectPeaksWithBoundaryData(allDetectedPeaks, processedAnnotations, processedSeries);\n if (peaksWithData.length > 0) {\n const boundaryTraces = createBoundaryMarkerTraces(peaksWithData);\n plotData.push(...boundaryTraces);\n }\n }\n\n // Collect all peaks for unified staggering logic\n const allPeaksWithMeta: PeakWithMeta[] = [];\n\n // Add user-defined annotations (seriesIndex -1 indicates user-defined)\n processedAnnotations.forEach((ann) => {\n allPeaksWithMeta.push({ peak: ann, seriesIndex: -1 });\n });\n\n // Add auto-detected peaks if enabled\n if (showPeakAreas && enablePeakDetection) {\n allDetectedPeaks.forEach(({ peaks, seriesIndex }) => {\n peaks.forEach((peak) => {\n allPeaksWithMeta.push({ peak, seriesIndex });\n });\n });\n }\n\n // Group all overlapping peaks and create annotations with staggering\n const groups = groupOverlappingPeaks(allPeaksWithMeta, annotationOverlapThreshold);\n const plotlyAnnotations: Partial<Plotly.Annotations>[] = [];\n\n for (const group of groups) {\n plotlyAnnotations.push(...createGroupAnnotations(group));\n }\n\n const layout: Partial<Plotly.Layout> = {\n title: title\n ? {\n text: title,\n font: {\n size: 20,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n }\n : undefined,\n width,\n height,\n margin: {\n l: CHROMATOGRAM_LAYOUT.MARGIN_LEFT,\n r: CHROMATOGRAM_LAYOUT.MARGIN_RIGHT,\n b: CHROMATOGRAM_LAYOUT.MARGIN_BOTTOM,\n t: title ? CHROMATOGRAM_LAYOUT.MARGIN_TOP_WITH_TITLE : CHROMATOGRAM_LAYOUT.MARGIN_TOP_NO_TITLE,\n pad: CHROMATOGRAM_LAYOUT.MARGIN_PAD,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: { family: \"Inter, sans-serif\" },\n hovermode: showCrosshairs ? \"x\" as const : \"x unified\" as const,\n dragmode: \"zoom\" as const,\n xaxis: {\n title: {\n text: xAxisTitle,\n font: { size: 14, color: theme.textSecondary, family: \"Inter, sans-serif\" },\n standoff: 15,\n },\n showgrid: showGridX,\n gridcolor: theme.gridColor,\n linecolor: theme.lineColor,\n linewidth: 1,\n range: xRange,\n autorange: !xRange,\n zeroline: false,\n tickfont: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n showspikes: showCrosshairs,\n spikemode: \"across\" as const,\n spikesnap: \"cursor\" as const,\n spikecolor: theme.spikeColor,\n spikethickness: 1,\n spikedash: \"dot\" as const,\n },\n yaxis: {\n title: {\n text: yAxisTitle,\n font: { size: 14, color: theme.textSecondary, family: \"Inter, sans-serif\" },\n standoff: 10,\n },\n showgrid: showGridY,\n gridcolor: theme.gridColor,\n linecolor: theme.lineColor,\n linewidth: 1,\n range: yRange,\n autorange: !yRange,\n zeroline: false,\n tickfont: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n showspikes: showCrosshairs,\n spikemode: \"across\" as const,\n spikesnap: \"cursor\" as const,\n spikecolor: theme.spikeColor,\n spikethickness: 1,\n spikedash: \"dot\" as const,\n },\n legend: {\n x: 0.5,\n y: -0.15,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n },\n showlegend: showLegend && series.length > 1,\n annotations: plotlyAnnotations,\n };\n\n const config: Partial<Plotly.Config> = {\n responsive: true,\n displayModeBar: true,\n displaylogo: false,\n modeBarButtonsToRemove: [\n \"lasso2d\",\n \"select2d\",\n ...(showExportButton ? [] : [\"toImage\"] as Plotly.ModeBarDefaultButtons[]),\n ] as Plotly.ModeBarDefaultButtons[],\n ...(showExportButton && {\n toImageButtonOptions: {\n format: \"png\",\n filename: \"chromatogram\",\n width: width,\n height: height,\n },\n }),\n };\n\n Plotly.newPlot(currentRef, plotData, layout, config);\n bindTooltip(currentRef);\n\n return () => {\n if (currentRef) {\n Plotly.purge(currentRef);\n }\n };\n }, [\n processedSeries, allDetectedPeaks, series.length, width, height, title, xAxisTitle, yAxisTitle,\n processedAnnotations, xRange, yRange, showLegend, showGridX, showGridY, showMarkers, markerSize,\n showCrosshairs, enablePeakDetection, peakDetectionOptions, showPeakAreas, boundaryMarkers,\n annotationOverlapThreshold, showExportButton, theme, bindTooltip,\n ]);\n\n return (\n <div className=\"chromatogram-chart-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { ChromatogramChart };\n\n"],"names":["EMPTY_ANNOTATIONS","ChromatogramChart","series","width","height","title","xAxisTitle","yAxisTitle","annotations","xRange","yRange","showLegend","showGridX","showGridY","showMarkers","markerSize","showCrosshairs","baselineCorrection","baselineWindowSize","peakDetectionOptions","showPeakAreas","boundaryMarkers","annotationOverlapThreshold","showExportButton","enablePeakDetection","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","processedSeries","useMemo","s","validated","validateSeriesData","applyBaselineCorrection","processedAnnotations","x","y","processUserAnnotations","allDetectedPeaks","peaks","index","detected","detectPeaks","useEffect","currentRef","plotData","traceColor","seriesColor","trace","peaksWithData","collectPeaksWithBoundaryData","boundaryTraces","createBoundaryMarkerTraces","allPeaksWithMeta","ann","seriesIndex","peak","groups","groupOverlappingPeaks","plotlyAnnotations","group","createGroupAnnotations","layout","CHROMATOGRAM_LAYOUT","config","Plotly","jsxs","jsx"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=require("../../../utils/colors.cjs"),O=require("./constants.cjs"),A={default:{ax:0,ay:-35},overlap:[{ax:50,ay:-35},{ax:-60,ay:-35},{ax:70,ay:-55},{ax:-80,ay:-55},{ax:50,ay:-75},{ax:-60,ay:-75}]};function u(t,n){const e=[...t].sort((a,s)=>a.peak.x-s.peak.x),o=[];let r=[];for(const a of e){if(r.length===0){r.push(a);continue}const s=r[r.length-1];Math.abs(a.peak.x-s.peak.x)<n?r.push(a):(o.push(r),r=[a])}return r.length>0&&o.push(r),o}function c(t,n,e){const o=n===-1,r=o?O.CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_COLOR:T.seriesColor(n),a=o?O.CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_TEXT_COLOR:r,s=t.text??(t._computed?.area===void 0?"":`Area: ${t._computed.area.toFixed(2)}`),i=o&&t.ax!==void 0?t.ax:e.ax,N=o&&t.ay!==void 0?t.ay:e.ay;return{x:t.x,y:t.y,text:s,showarrow:!0,arrowhead:2,arrowsize:1,arrowwidth:1,arrowcolor:r,ax:i,ay:N,font:{size:o?O.CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_FONT_SIZE:O.CHROMATOGRAM_ANNOTATION.AUTO_ANNOTATION_FONT_SIZE,color:a,family:"Inter, sans-serif"},bgcolor:O.CHROMATOGRAM_ANNOTATION.BACKGROUND_COLOR,borderpad:2,bordercolor:o?void 0:r,borderwidth:o?0:1}}function l(t){if(t.length===1){const{peak:e,seriesIndex:o}=t[0];return[c(e,o,A.default)]}return[...t].sort((e,o)=>e.peak.y-o.peak.y).map(({peak:e,seriesIndex:o},r)=>{const a=A.overlap[r%A.overlap.length];return c(e,o,a)})}exports.ANNOTATION_SLOTS=A;exports.createGroupAnnotations=l;exports.createPeakAnnotation=c;exports.groupOverlappingPeaks=u;
|
|
2
2
|
//# sourceMappingURL=annotations.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotations.cjs","sources":["../../../../src/components/charts/ChromatogramChart/annotations.ts"],"sourcesContent":["/**\n * Annotation utilities for ChromatogramChart\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"annotations.cjs","sources":["../../../../src/components/charts/ChromatogramChart/annotations.ts"],"sourcesContent":["/**\n * Annotation utilities for ChromatogramChart\n */\n\nimport { seriesColor } from \"../../../utils/colors\";\n\nimport { CHROMATOGRAM_ANNOTATION } from \"./constants\";\n\nimport type { PeakAnnotation, PeakWithMeta } from \"./types\";\nimport type Plotly from \"plotly.js-dist\";\n\n/**\n * Annotation slot positions for peak labels\n */\nexport const ANNOTATION_SLOTS = {\n default: { ax: 0, ay: -35 },\n overlap: [\n { ax: 50, ay: -35 }, // Right, level 1\n { ax: -60, ay: -35 }, // Left, level 1\n { ax: 70, ay: -55 }, // Right, level 2\n { ax: -80, ay: -55 }, // Left, level 2\n { ax: 50, ay: -75 }, // Right, level 3\n { ax: -60, ay: -75 }, // Left, level 3\n ],\n};\n\n/**\n * Group overlapping peaks by retention time (x) proximity\n */\nexport function groupOverlappingPeaks(\n peaksWithMeta: PeakWithMeta[],\n overlapThreshold: number\n): PeakWithMeta[][] {\n const sorted = [...peaksWithMeta].sort((a, b) => a.peak.x - b.peak.x);\n\n const groups: PeakWithMeta[][] = [];\n let currentGroup: PeakWithMeta[] = [];\n\n for (const current of sorted) {\n if (currentGroup.length === 0) {\n currentGroup.push(current);\n continue;\n }\n\n const lastInGroup = currentGroup[currentGroup.length - 1];\n const timeDiff = Math.abs(current.peak.x - lastInGroup.peak.x);\n\n if (timeDiff < overlapThreshold) {\n currentGroup.push(current);\n } else {\n groups.push(currentGroup);\n currentGroup = [current];\n }\n }\n\n if (currentGroup.length > 0) {\n groups.push(currentGroup);\n }\n\n return groups;\n}\n\n/**\n * Create a Plotly annotation for a peak.\n * seriesIndex of -1 indicates a user-defined annotation (uses grey/black styling).\n */\nexport function createPeakAnnotation(\n peak: PeakAnnotation,\n seriesIndex: number,\n slot: { ax: number; ay: number }\n): Partial<Plotly.Annotations> {\n const isUserDefined = seriesIndex === -1;\n const color = isUserDefined\n ? CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_COLOR\n : seriesColor(seriesIndex);\n const textColor = isUserDefined\n ? CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_TEXT_COLOR\n : color;\n\n // Use provided text or auto-generate from computed area\n const text = peak.text ?? (peak._computed?.area === undefined ? \"\" : `Area: ${peak._computed.area.toFixed(2)}`);\n\n // For user-defined annotations, respect their ax/ay if provided\n const ax = isUserDefined && peak.ax !== undefined ? peak.ax : slot.ax;\n const ay = isUserDefined && peak.ay !== undefined ? peak.ay : slot.ay;\n\n return {\n x: peak.x,\n y: peak.y,\n text,\n showarrow: true,\n arrowhead: 2,\n arrowsize: 1,\n arrowwidth: 1,\n arrowcolor: color,\n ax,\n ay,\n font: {\n size: isUserDefined\n ? CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_FONT_SIZE\n : CHROMATOGRAM_ANNOTATION.AUTO_ANNOTATION_FONT_SIZE,\n color: textColor,\n family: \"Inter, sans-serif\",\n },\n bgcolor: CHROMATOGRAM_ANNOTATION.BACKGROUND_COLOR,\n borderpad: 2,\n bordercolor: isUserDefined ? undefined : color,\n borderwidth: isUserDefined ? 0 : 1,\n };\n}\n\n/**\n * Create annotations for a group of peaks, handling overlap positioning\n */\nexport function createGroupAnnotations(\n group: PeakWithMeta[]\n): Partial<Plotly.Annotations>[] {\n if (group.length === 1) {\n const { peak, seriesIndex } = group[0];\n return [createPeakAnnotation(peak, seriesIndex, ANNOTATION_SLOTS.default)];\n }\n\n // Sort by intensity (y, lowest first) so lower peaks get closer annotations\n const sortedGroup = [...group].sort((a, b) => a.peak.y - b.peak.y);\n\n return sortedGroup.map(({ peak, seriesIndex }, slotIndex) => {\n const slot =\n ANNOTATION_SLOTS.overlap[slotIndex % ANNOTATION_SLOTS.overlap.length];\n return createPeakAnnotation(peak, seriesIndex, slot);\n });\n}\n\n"],"names":["ANNOTATION_SLOTS","groupOverlappingPeaks","peaksWithMeta","overlapThreshold","sorted","b","groups","currentGroup","current","lastInGroup","createPeakAnnotation","peak","seriesIndex","slot","isUserDefined","color","CHROMATOGRAM_ANNOTATION","seriesColor","textColor","text","ax","ay","createGroupAnnotations","group","a","slotIndex"],"mappings":"0JAcaA,EAAmB,CAC9B,QAAS,CAAE,GAAI,EAAG,GAAI,GAAA,EACtB,QAAS,CACP,CAAE,GAAI,GAAI,GAAI,GAAA,EACd,CAAE,GAAI,IAAK,GAAI,GAAA,EACf,CAAE,GAAI,GAAI,GAAI,GAAA,EACd,CAAE,GAAI,IAAK,GAAI,GAAA,EACf,CAAE,GAAI,GAAI,GAAI,GAAA,EACd,CAAE,GAAI,IAAK,GAAI,GAAA,CAAI,CAEvB,EAKO,SAASC,EACdC,EACAC,EACkB,CAClB,MAAMC,EAAS,CAAC,GAAGF,CAAa,EAAE,KAAK,CAAC,EAAGG,IAAM,EAAE,KAAK,EAAIA,EAAE,KAAK,CAAC,EAE9DC,EAA2B,CAAA,EACjC,IAAIC,EAA+B,CAAA,EAEnC,UAAWC,KAAWJ,EAAQ,CAC5B,GAAIG,EAAa,SAAW,EAAG,CAC7BA,EAAa,KAAKC,CAAO,EACzB,QACF,CAEA,MAAMC,EAAcF,EAAaA,EAAa,OAAS,CAAC,EACvC,KAAK,IAAIC,EAAQ,KAAK,EAAIC,EAAY,KAAK,CAAC,EAE9CN,EACbI,EAAa,KAAKC,CAAO,GAEzBF,EAAO,KAAKC,CAAY,EACxBA,EAAe,CAACC,CAAO,EAE3B,CAEA,OAAID,EAAa,OAAS,GACxBD,EAAO,KAAKC,CAAY,EAGnBD,CACT,CAMO,SAASI,EACdC,EACAC,EACAC,EAC6B,CAC7B,MAAMC,EAAgBF,IAAgB,GAChCG,EAAQD,EACVE,EAAAA,wBAAwB,sBACxBC,EAAAA,YAAYL,CAAW,EACrBM,EAAYJ,EACdE,EAAAA,wBAAwB,2BACxBD,EAGEI,EAAOR,EAAK,OAASA,EAAK,WAAW,OAAS,OAAY,GAAK,SAASA,EAAK,UAAU,KAAK,QAAQ,CAAC,CAAC,IAGtGS,EAAKN,GAAiBH,EAAK,KAAO,OAAYA,EAAK,GAAKE,EAAK,GAC7DQ,EAAKP,GAAiBH,EAAK,KAAO,OAAYA,EAAK,GAAKE,EAAK,GAEnE,MAAO,CACL,EAAGF,EAAK,EACR,EAAGA,EAAK,EACR,KAAAQ,EACA,UAAW,GACX,UAAW,EACX,UAAW,EACX,WAAY,EACZ,WAAYJ,EACZ,GAAAK,EACA,GAAAC,EACA,KAAM,CACJ,KAAMP,EACFE,EAAAA,wBAAwB,0BACxBA,EAAAA,wBAAwB,0BAC5B,MAAOE,EACP,OAAQ,mBAAA,EAEV,QAASF,EAAAA,wBAAwB,iBACjC,UAAW,EACX,YAAaF,EAAgB,OAAYC,EACzC,YAAaD,EAAgB,EAAI,CAAA,CAErC,CAKO,SAASQ,EACdC,EAC+B,CAC/B,GAAIA,EAAM,SAAW,EAAG,CACtB,KAAM,CAAE,KAAAZ,EAAM,YAAAC,GAAgBW,EAAM,CAAC,EACrC,MAAO,CAACb,EAAqBC,EAAMC,EAAaZ,EAAiB,OAAO,CAAC,CAC3E,CAKA,MAFoB,CAAC,GAAGuB,CAAK,EAAE,KAAK,CAACC,EAAGnB,IAAMmB,EAAE,KAAK,EAAInB,EAAE,KAAK,CAAC,EAE9C,IAAI,CAAC,CAAE,KAAAM,EAAM,YAAAC,CAAA,EAAea,IAAc,CAC3D,MAAMZ,EACJb,EAAiB,QAAQyB,EAAYzB,EAAiB,QAAQ,MAAM,EACtE,OAAOU,EAAqBC,EAAMC,EAAaC,CAAI,CACrD,CAAC,CACH"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CHROMATOGRAM_ANNOTATION as
|
|
3
|
-
const
|
|
1
|
+
import { seriesColor as x } from "../../../utils/colors.js";
|
|
2
|
+
import { CHROMATOGRAM_ANNOTATION as i } from "./constants.js";
|
|
3
|
+
const c = {
|
|
4
4
|
default: { ax: 0, ay: -35 },
|
|
5
5
|
overlap: [
|
|
6
6
|
{ ax: 50, ay: -35 },
|
|
@@ -17,57 +17,57 @@ const i = {
|
|
|
17
17
|
// Left, level 3
|
|
18
18
|
]
|
|
19
19
|
};
|
|
20
|
-
function
|
|
21
|
-
const e = [...
|
|
22
|
-
let
|
|
20
|
+
function d(r, n) {
|
|
21
|
+
const e = [...r].sort((a, s) => a.peak.x - s.peak.x), o = [];
|
|
22
|
+
let t = [];
|
|
23
23
|
for (const a of e) {
|
|
24
|
-
if (
|
|
25
|
-
|
|
24
|
+
if (t.length === 0) {
|
|
25
|
+
t.push(a);
|
|
26
26
|
continue;
|
|
27
27
|
}
|
|
28
|
-
const s =
|
|
29
|
-
Math.abs(a.peak.x - s.peak.x) < n ?
|
|
28
|
+
const s = t[t.length - 1];
|
|
29
|
+
Math.abs(a.peak.x - s.peak.x) < n ? t.push(a) : (o.push(t), t = [a]);
|
|
30
30
|
}
|
|
31
|
-
return
|
|
31
|
+
return t.length > 0 && o.push(t), o;
|
|
32
32
|
}
|
|
33
|
-
function
|
|
34
|
-
const o = n === -1,
|
|
33
|
+
function u(r, n, e) {
|
|
34
|
+
const o = n === -1, t = o ? i.USER_ANNOTATION_COLOR : x(n), a = o ? i.USER_ANNOTATION_TEXT_COLOR : t, s = r.text ?? (r._computed?.area === void 0 ? "" : `Area: ${r._computed.area.toFixed(2)}`), O = o && r.ax !== void 0 ? r.ax : e.ax, l = o && r.ay !== void 0 ? r.ay : e.ay;
|
|
35
35
|
return {
|
|
36
|
-
x:
|
|
37
|
-
y:
|
|
36
|
+
x: r.x,
|
|
37
|
+
y: r.y,
|
|
38
38
|
text: s,
|
|
39
39
|
showarrow: !0,
|
|
40
40
|
arrowhead: 2,
|
|
41
41
|
arrowsize: 1,
|
|
42
42
|
arrowwidth: 1,
|
|
43
|
-
arrowcolor:
|
|
44
|
-
ax:
|
|
45
|
-
ay:
|
|
43
|
+
arrowcolor: t,
|
|
44
|
+
ax: O,
|
|
45
|
+
ay: l,
|
|
46
46
|
font: {
|
|
47
|
-
size: o ?
|
|
47
|
+
size: o ? i.USER_ANNOTATION_FONT_SIZE : i.AUTO_ANNOTATION_FONT_SIZE,
|
|
48
48
|
color: a,
|
|
49
49
|
family: "Inter, sans-serif"
|
|
50
50
|
},
|
|
51
|
-
bgcolor:
|
|
51
|
+
bgcolor: i.BACKGROUND_COLOR,
|
|
52
52
|
borderpad: 2,
|
|
53
|
-
bordercolor: o ? void 0 :
|
|
53
|
+
bordercolor: o ? void 0 : t,
|
|
54
54
|
borderwidth: o ? 0 : 1
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
if (
|
|
59
|
-
const { peak: e, seriesIndex: o } =
|
|
60
|
-
return [
|
|
57
|
+
function p(r) {
|
|
58
|
+
if (r.length === 1) {
|
|
59
|
+
const { peak: e, seriesIndex: o } = r[0];
|
|
60
|
+
return [u(e, o, c.default)];
|
|
61
61
|
}
|
|
62
|
-
return [...
|
|
63
|
-
const a =
|
|
64
|
-
return
|
|
62
|
+
return [...r].sort((e, o) => e.peak.y - o.peak.y).map(({ peak: e, seriesIndex: o }, t) => {
|
|
63
|
+
const a = c.overlap[t % c.overlap.length];
|
|
64
|
+
return u(e, o, a);
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
export {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
c as ANNOTATION_SLOTS,
|
|
69
|
+
p as createGroupAnnotations,
|
|
70
|
+
u as createPeakAnnotation,
|
|
71
|
+
d as groupOverlappingPeaks
|
|
72
72
|
};
|
|
73
73
|
//# sourceMappingURL=annotations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotations.js","sources":["../../../../src/components/charts/ChromatogramChart/annotations.ts"],"sourcesContent":["/**\n * Annotation utilities for ChromatogramChart\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"annotations.js","sources":["../../../../src/components/charts/ChromatogramChart/annotations.ts"],"sourcesContent":["/**\n * Annotation utilities for ChromatogramChart\n */\n\nimport { seriesColor } from \"../../../utils/colors\";\n\nimport { CHROMATOGRAM_ANNOTATION } from \"./constants\";\n\nimport type { PeakAnnotation, PeakWithMeta } from \"./types\";\nimport type Plotly from \"plotly.js-dist\";\n\n/**\n * Annotation slot positions for peak labels\n */\nexport const ANNOTATION_SLOTS = {\n default: { ax: 0, ay: -35 },\n overlap: [\n { ax: 50, ay: -35 }, // Right, level 1\n { ax: -60, ay: -35 }, // Left, level 1\n { ax: 70, ay: -55 }, // Right, level 2\n { ax: -80, ay: -55 }, // Left, level 2\n { ax: 50, ay: -75 }, // Right, level 3\n { ax: -60, ay: -75 }, // Left, level 3\n ],\n};\n\n/**\n * Group overlapping peaks by retention time (x) proximity\n */\nexport function groupOverlappingPeaks(\n peaksWithMeta: PeakWithMeta[],\n overlapThreshold: number\n): PeakWithMeta[][] {\n const sorted = [...peaksWithMeta].sort((a, b) => a.peak.x - b.peak.x);\n\n const groups: PeakWithMeta[][] = [];\n let currentGroup: PeakWithMeta[] = [];\n\n for (const current of sorted) {\n if (currentGroup.length === 0) {\n currentGroup.push(current);\n continue;\n }\n\n const lastInGroup = currentGroup[currentGroup.length - 1];\n const timeDiff = Math.abs(current.peak.x - lastInGroup.peak.x);\n\n if (timeDiff < overlapThreshold) {\n currentGroup.push(current);\n } else {\n groups.push(currentGroup);\n currentGroup = [current];\n }\n }\n\n if (currentGroup.length > 0) {\n groups.push(currentGroup);\n }\n\n return groups;\n}\n\n/**\n * Create a Plotly annotation for a peak.\n * seriesIndex of -1 indicates a user-defined annotation (uses grey/black styling).\n */\nexport function createPeakAnnotation(\n peak: PeakAnnotation,\n seriesIndex: number,\n slot: { ax: number; ay: number }\n): Partial<Plotly.Annotations> {\n const isUserDefined = seriesIndex === -1;\n const color = isUserDefined\n ? CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_COLOR\n : seriesColor(seriesIndex);\n const textColor = isUserDefined\n ? CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_TEXT_COLOR\n : color;\n\n // Use provided text or auto-generate from computed area\n const text = peak.text ?? (peak._computed?.area === undefined ? \"\" : `Area: ${peak._computed.area.toFixed(2)}`);\n\n // For user-defined annotations, respect their ax/ay if provided\n const ax = isUserDefined && peak.ax !== undefined ? peak.ax : slot.ax;\n const ay = isUserDefined && peak.ay !== undefined ? peak.ay : slot.ay;\n\n return {\n x: peak.x,\n y: peak.y,\n text,\n showarrow: true,\n arrowhead: 2,\n arrowsize: 1,\n arrowwidth: 1,\n arrowcolor: color,\n ax,\n ay,\n font: {\n size: isUserDefined\n ? CHROMATOGRAM_ANNOTATION.USER_ANNOTATION_FONT_SIZE\n : CHROMATOGRAM_ANNOTATION.AUTO_ANNOTATION_FONT_SIZE,\n color: textColor,\n family: \"Inter, sans-serif\",\n },\n bgcolor: CHROMATOGRAM_ANNOTATION.BACKGROUND_COLOR,\n borderpad: 2,\n bordercolor: isUserDefined ? undefined : color,\n borderwidth: isUserDefined ? 0 : 1,\n };\n}\n\n/**\n * Create annotations for a group of peaks, handling overlap positioning\n */\nexport function createGroupAnnotations(\n group: PeakWithMeta[]\n): Partial<Plotly.Annotations>[] {\n if (group.length === 1) {\n const { peak, seriesIndex } = group[0];\n return [createPeakAnnotation(peak, seriesIndex, ANNOTATION_SLOTS.default)];\n }\n\n // Sort by intensity (y, lowest first) so lower peaks get closer annotations\n const sortedGroup = [...group].sort((a, b) => a.peak.y - b.peak.y);\n\n return sortedGroup.map(({ peak, seriesIndex }, slotIndex) => {\n const slot =\n ANNOTATION_SLOTS.overlap[slotIndex % ANNOTATION_SLOTS.overlap.length];\n return createPeakAnnotation(peak, seriesIndex, slot);\n });\n}\n\n"],"names":["ANNOTATION_SLOTS","groupOverlappingPeaks","peaksWithMeta","overlapThreshold","sorted","b","groups","currentGroup","current","lastInGroup","createPeakAnnotation","peak","seriesIndex","slot","isUserDefined","color","CHROMATOGRAM_ANNOTATION","seriesColor","textColor","text","ax","ay","createGroupAnnotations","group","a","slotIndex"],"mappings":";;AAcO,MAAMA,IAAmB;AAAA,EAC9B,SAAS,EAAE,IAAI,GAAG,IAAI,IAAA;AAAA,EACtB,SAAS;AAAA,IACP,EAAE,IAAI,IAAI,IAAI,IAAA;AAAA;AAAA,IACd,EAAE,IAAI,KAAK,IAAI,IAAA;AAAA;AAAA,IACf,EAAE,IAAI,IAAI,IAAI,IAAA;AAAA;AAAA,IACd,EAAE,IAAI,KAAK,IAAI,IAAA;AAAA;AAAA,IACf,EAAE,IAAI,IAAI,IAAI,IAAA;AAAA;AAAA,IACd,EAAE,IAAI,KAAK,IAAI,IAAA;AAAA;AAAA,EAAI;AAEvB;AAKO,SAASC,EACdC,GACAC,GACkB;AAClB,QAAMC,IAAS,CAAC,GAAGF,CAAa,EAAE,KAAK,CAAC,GAAGG,MAAM,EAAE,KAAK,IAAIA,EAAE,KAAK,CAAC,GAE9DC,IAA2B,CAAA;AACjC,MAAIC,IAA+B,CAAA;AAEnC,aAAWC,KAAWJ,GAAQ;AAC5B,QAAIG,EAAa,WAAW,GAAG;AAC7B,MAAAA,EAAa,KAAKC,CAAO;AACzB;AAAA,IACF;AAEA,UAAMC,IAAcF,EAAaA,EAAa,SAAS,CAAC;AAGxD,IAFiB,KAAK,IAAIC,EAAQ,KAAK,IAAIC,EAAY,KAAK,CAAC,IAE9CN,IACbI,EAAa,KAAKC,CAAO,KAEzBF,EAAO,KAAKC,CAAY,GACxBA,IAAe,CAACC,CAAO;AAAA,EAE3B;AAEA,SAAID,EAAa,SAAS,KACxBD,EAAO,KAAKC,CAAY,GAGnBD;AACT;AAMO,SAASI,EACdC,GACAC,GACAC,GAC6B;AAC7B,QAAMC,IAAgBF,MAAgB,IAChCG,IAAQD,IACVE,EAAwB,wBACxBC,EAAYL,CAAW,GACrBM,IAAYJ,IACdE,EAAwB,6BACxBD,GAGEI,IAAOR,EAAK,SAASA,EAAK,WAAW,SAAS,SAAY,KAAK,SAASA,EAAK,UAAU,KAAK,QAAQ,CAAC,CAAC,KAGtGS,IAAKN,KAAiBH,EAAK,OAAO,SAAYA,EAAK,KAAKE,EAAK,IAC7DQ,IAAKP,KAAiBH,EAAK,OAAO,SAAYA,EAAK,KAAKE,EAAK;AAEnE,SAAO;AAAA,IACL,GAAGF,EAAK;AAAA,IACR,GAAGA,EAAK;AAAA,IACR,MAAAQ;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,YAAYJ;AAAA,IACZ,IAAAK;AAAA,IACA,IAAAC;AAAA,IACA,MAAM;AAAA,MACJ,MAAMP,IACFE,EAAwB,4BACxBA,EAAwB;AAAA,MAC5B,OAAOE;AAAA,MACP,QAAQ;AAAA,IAAA;AAAA,IAEV,SAASF,EAAwB;AAAA,IACjC,WAAW;AAAA,IACX,aAAaF,IAAgB,SAAYC;AAAA,IACzC,aAAaD,IAAgB,IAAI;AAAA,EAAA;AAErC;AAKO,SAASQ,EACdC,GAC+B;AAC/B,MAAIA,EAAM,WAAW,GAAG;AACtB,UAAM,EAAE,MAAAZ,GAAM,aAAAC,MAAgBW,EAAM,CAAC;AACrC,WAAO,CAACb,EAAqBC,GAAMC,GAAaZ,EAAiB,OAAO,CAAC;AAAA,EAC3E;AAKA,SAFoB,CAAC,GAAGuB,CAAK,EAAE,KAAK,CAACC,GAAGnB,MAAMmB,EAAE,KAAK,IAAInB,EAAE,KAAK,CAAC,EAE9C,IAAI,CAAC,EAAE,MAAAM,GAAM,aAAAC,EAAA,GAAea,MAAc;AAC3D,UAAMZ,IACJb,EAAiB,QAAQyB,IAAYzB,EAAiB,QAAQ,MAAM;AACtE,WAAOU,EAAqBC,GAAMC,GAAaC,CAAI;AAAA,EACrD,CAAC;AACH;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("../../../utils/colors.cjs"),m=-5,y=-12,c=-16;function d(o,e,t,r){return t==="none"?[]:[{x:[o],y:[e],type:"scatter",mode:"markers",marker:{symbol:t==="diamond"?"diamond":"triangle-up",size:8,color:r},showlegend:!1,hoverinfo:"skip"}]}function T(o){const e=[];for(const{peaks:t,seriesIndex:r,x:s}of o){const a=f.seriesColor(r),i=m+r*c,u=y+r*c;for(const n of t){const k=n._computed?.startIndex??0,M=n._computed?.endIndex??0,l=s[k],p=s[M],R=n.startMarker??"triangle",_=n.endMarker??"diamond";e.push(...d(l,i,R,a)),e.push(...d(p,u,_,a))}}return e}exports.createBoundaryMarkerTraces=T;
|
|
2
2
|
//# sourceMappingURL=boundaryMarkers.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boundaryMarkers.cjs","sources":["../../../../src/components/charts/ChromatogramChart/boundaryMarkers.ts"],"sourcesContent":["/**\n * Boundary marker utilities for ChromatogramChart\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"boundaryMarkers.cjs","sources":["../../../../src/components/charts/ChromatogramChart/boundaryMarkers.ts"],"sourcesContent":["/**\n * Boundary marker utilities for ChromatogramChart\n */\n\nimport { seriesColor } from \"../../../utils/colors\";\n\nimport type { PeakAnnotation, BoundaryMarkerType } from \"./types\";\nimport type Plotly from \"plotly.js-dist\";\n\n/** Base Y position for start boundary markers (below the x-axis) */\nconst BOUNDARY_MARKER_START_Y = -5;\n/** Y position for end boundary markers (below start markers) */\nconst BOUNDARY_MARKER_END_Y = -12;\n/** Y offset between series to prevent overlap */\nconst BOUNDARY_MARKER_SERIES_OFFSET = -16;\n\n/**\n * Create a marker trace for a boundary point.\n * Markers are placed on the x-axis below 0, staggered by series index.\n */\nfunction createMarkerTrace(\n xPos: number,\n yPos: number,\n markerType: BoundaryMarkerType,\n color: string\n): Plotly.Data[] {\n if (markerType === \"none\") {\n return [];\n }\n\n return [\n {\n x: [xPos],\n y: [yPos],\n type: \"scatter\" as const,\n mode: \"markers\" as const,\n marker: {\n symbol: markerType === \"diamond\" ? (\"diamond\" as const) : (\"triangle-up\" as const),\n size: 8,\n color,\n },\n showlegend: false,\n hoverinfo: \"skip\" as const,\n },\n ];\n}\n\n/**\n * Create boundary marker traces for peaks.\n * Uses per-peak startMarker/endMarker settings with defaults:\n * - startMarker: \"triangle\" (default)\n * - endMarker: \"diamond\" (default)\n */\nexport function createBoundaryMarkerTraces(\n allPeaks: {\n peaks: PeakAnnotation[];\n seriesIndex: number;\n x: number[];\n y: number[];\n }[]\n): Plotly.Data[] {\n const traces: Plotly.Data[] = [];\n\n for (const { peaks, seriesIndex, x } of allPeaks) {\n const color = seriesColor(seriesIndex);\n // Separate y positions for start vs end markers to prevent overlap when peaks are adjacent\n // Also stagger by series index to prevent overlap between different traces\n const startMarkerY = BOUNDARY_MARKER_START_Y + seriesIndex * BOUNDARY_MARKER_SERIES_OFFSET;\n const endMarkerY = BOUNDARY_MARKER_END_Y + seriesIndex * BOUNDARY_MARKER_SERIES_OFFSET;\n\n for (const peak of peaks) {\n const startIdx = peak._computed?.startIndex ?? 0;\n const endIdx = peak._computed?.endIndex ?? 0;\n const startX = x[startIdx];\n const endX = x[endIdx];\n\n // Get marker types with defaults: triangle at start, diamond at end\n const startMarkerType = peak.startMarker ?? \"triangle\";\n const endMarkerType = peak.endMarker ?? \"diamond\";\n\n // Create start boundary marker (upper row, staggered by series)\n traces.push(...createMarkerTrace(startX, startMarkerY, startMarkerType, color));\n\n // Create end boundary marker (lower row, staggered by series)\n traces.push(...createMarkerTrace(endX, endMarkerY, endMarkerType, color));\n }\n }\n\n return traces;\n}\n\n"],"names":["BOUNDARY_MARKER_START_Y","BOUNDARY_MARKER_END_Y","BOUNDARY_MARKER_SERIES_OFFSET","createMarkerTrace","xPos","yPos","markerType","color","createBoundaryMarkerTraces","allPeaks","traces","peaks","seriesIndex","x","seriesColor","startMarkerY","endMarkerY","peak","startIdx","endIdx","startX","endX","startMarkerType","endMarkerType"],"mappings":"6HAUMA,EAA0B,GAE1BC,EAAwB,IAExBC,EAAgC,IAMtC,SAASC,EACPC,EACAC,EACAC,EACAC,EACe,CACf,OAAID,IAAe,OACV,CAAA,EAGF,CACL,CACE,EAAG,CAACF,CAAI,EACR,EAAG,CAACC,CAAI,EACR,KAAM,UACN,KAAM,UACN,OAAQ,CACN,OAAQC,IAAe,UAAa,UAAuB,cAC3D,KAAM,EACN,MAAAC,CAAA,EAEF,WAAY,GACZ,UAAW,MAAA,CACb,CAEJ,CAQO,SAASC,EACdC,EAMe,CACf,MAAMC,EAAwB,CAAA,EAE9B,SAAW,CAAE,MAAAC,EAAO,YAAAC,EAAa,EAAAC,CAAA,IAAOJ,EAAU,CAChD,MAAMF,EAAQO,EAAAA,YAAYF,CAAW,EAG/BG,EAAef,EAA0BY,EAAcV,EACvDc,EAAaf,EAAwBW,EAAcV,EAEzD,UAAWe,KAAQN,EAAO,CACxB,MAAMO,EAAWD,EAAK,WAAW,YAAc,EACzCE,EAASF,EAAK,WAAW,UAAY,EACrCG,EAASP,EAAEK,CAAQ,EACnBG,EAAOR,EAAEM,CAAM,EAGfG,EAAkBL,EAAK,aAAe,WACtCM,EAAgBN,EAAK,WAAa,UAGxCP,EAAO,KAAK,GAAGP,EAAkBiB,EAAQL,EAAcO,EAAiBf,CAAK,CAAC,EAG9EG,EAAO,KAAK,GAAGP,EAAkBkB,EAAML,EAAYO,EAAehB,CAAK,CAAC,CAC1E,CACF,CAEA,OAAOG,CACT"}
|