@tetrascience-npm/tetrascience-react-ui 0.6.0-beta.81.1 → 0.6.0-beta.83.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 +79 -75
- 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 +37 -36
- 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 +84 -80
- package/dist/components/charts/Boxplot/Boxplot.js.map +1 -1
- 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 +51 -46
- 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 +47 -47
- 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/DotPlot/DotPlot.cjs +1 -1
- package/dist/components/charts/DotPlot/DotPlot.cjs.map +1 -1
- package/dist/components/charts/DotPlot/DotPlot.js +49 -59
- 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 +53 -63
- 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 +87 -83
- 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 +41 -48
- package/dist/components/charts/PieChart/PieChart.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 +40 -39
- 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 +26 -76
- package/dist/index.js +37 -36
- 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,9 +1,10 @@
|
|
|
1
|
-
import { jsx as p, jsxs as
|
|
2
|
-
import
|
|
3
|
-
import { useRef as
|
|
4
|
-
import { usePlotlyTheme as
|
|
1
|
+
import { jsx as p, jsxs as S } from "react/jsx-runtime";
|
|
2
|
+
import G from "plotly.js-dist";
|
|
3
|
+
import { useRef as j, useMemo as n, useEffect as F } from "react";
|
|
4
|
+
import { usePlotlyTheme as L } from "../../../hooks/use-plotly-theme.js";
|
|
5
|
+
import { CHART_COLORS as M } from "../../../utils/colors.js";
|
|
5
6
|
/* empty css */
|
|
6
|
-
const $ = 75,
|
|
7
|
+
const $ = 75, D = 1.05, H = (e) => {
|
|
7
8
|
const r = {
|
|
8
9
|
A: e.peakA,
|
|
9
10
|
T: e.peakT,
|
|
@@ -16,63 +17,67 @@ const $ = 75, L = 1.05, R = (e) => {
|
|
|
16
17
|
return Object.entries(r).forEach(([i, f]) => {
|
|
17
18
|
f > u && (h = i, u = f);
|
|
18
19
|
}), h;
|
|
19
|
-
},
|
|
20
|
+
}, K = ({
|
|
20
21
|
data: e = [],
|
|
21
22
|
width: r = 900,
|
|
22
23
|
height: m = 600,
|
|
23
24
|
positionInterval: d = 10,
|
|
24
|
-
colorA: h =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
colorA: h = M[0],
|
|
26
|
+
// blue
|
|
27
|
+
colorT: u = M[2],
|
|
28
|
+
// teal/green
|
|
29
|
+
colorG: i = M[3],
|
|
30
|
+
// red
|
|
31
|
+
colorC: f = M[1]
|
|
32
|
+
// orange
|
|
28
33
|
}) => {
|
|
29
|
-
const x =
|
|
34
|
+
const x = j(null), y = L(), t = n(() => e.map((s) => s.position), [e]), B = n(() => e.map((s) => H(s)), [e]), k = n(() => e.map((s) => s.peakA), [e]), P = n(() => e.map((s) => s.peakT), [e]), T = n(() => e.map((s) => s.peakG), [e]), N = n(() => e.map((s) => s.peakC), [e]), v = n(
|
|
30
35
|
() => ({
|
|
31
|
-
x:
|
|
36
|
+
x: t,
|
|
32
37
|
y: k,
|
|
33
38
|
type: "scatter",
|
|
34
39
|
mode: "lines",
|
|
35
40
|
name: "A",
|
|
36
41
|
line: { color: h, width: 2, shape: "spline" }
|
|
37
42
|
}),
|
|
38
|
-
[
|
|
39
|
-
),
|
|
43
|
+
[t, k, h]
|
|
44
|
+
), w = n(
|
|
40
45
|
() => ({
|
|
41
|
-
x:
|
|
46
|
+
x: t,
|
|
42
47
|
y: P,
|
|
43
48
|
type: "scatter",
|
|
44
49
|
mode: "lines",
|
|
45
50
|
name: "T",
|
|
46
51
|
line: { color: u, width: 2, shape: "spline" }
|
|
47
52
|
}),
|
|
48
|
-
[
|
|
49
|
-
),
|
|
53
|
+
[t, P, u]
|
|
54
|
+
), C = n(
|
|
50
55
|
() => ({
|
|
51
|
-
x:
|
|
56
|
+
x: t,
|
|
52
57
|
y: T,
|
|
53
58
|
type: "scatter",
|
|
54
59
|
mode: "lines",
|
|
55
60
|
name: "G",
|
|
56
61
|
line: { color: i, width: 2, shape: "spline" }
|
|
57
62
|
}),
|
|
58
|
-
[
|
|
59
|
-
),
|
|
63
|
+
[t, T, i]
|
|
64
|
+
), A = n(
|
|
60
65
|
() => ({
|
|
61
|
-
x:
|
|
62
|
-
y:
|
|
66
|
+
x: t,
|
|
67
|
+
y: N,
|
|
63
68
|
type: "scatter",
|
|
64
69
|
mode: "lines",
|
|
65
70
|
name: "C",
|
|
66
71
|
line: { color: f, width: 2, shape: "spline" }
|
|
67
72
|
}),
|
|
68
|
-
[
|
|
69
|
-
),
|
|
70
|
-
() => Math.max(...k, ...P, ...T, ...
|
|
71
|
-
[k, P, T,
|
|
73
|
+
[t, N, f]
|
|
74
|
+
), _ = n(
|
|
75
|
+
() => Math.max(...k, ...P, ...T, ...N),
|
|
76
|
+
[k, P, T, N]
|
|
72
77
|
);
|
|
73
|
-
return
|
|
78
|
+
return F(() => {
|
|
74
79
|
if (!x.current || e.length === 0) return;
|
|
75
|
-
const
|
|
80
|
+
const s = [v, w, C, A], b = {
|
|
76
81
|
width: r,
|
|
77
82
|
height: m - $,
|
|
78
83
|
margin: { l: 0, r: 0, b: 20, t: 10, pad: 0 },
|
|
@@ -87,7 +92,7 @@ const $ = 75, L = 1.05, R = (e) => {
|
|
|
87
92
|
zeroline: !1,
|
|
88
93
|
showticklabels: !1,
|
|
89
94
|
showline: !1,
|
|
90
|
-
range: [Math.min(...
|
|
95
|
+
range: [Math.min(...t), Math.max(...t)],
|
|
91
96
|
fixedrange: !0
|
|
92
97
|
},
|
|
93
98
|
yaxis: {
|
|
@@ -95,7 +100,7 @@ const $ = 75, L = 1.05, R = (e) => {
|
|
|
95
100
|
zeroline: !1,
|
|
96
101
|
showticklabels: !1,
|
|
97
102
|
showline: !1,
|
|
98
|
-
range: [0,
|
|
103
|
+
range: [0, _ * D],
|
|
99
104
|
fixedrange: !0
|
|
100
105
|
}
|
|
101
106
|
}, a = {
|
|
@@ -104,23 +109,23 @@ const $ = 75, L = 1.05, R = (e) => {
|
|
|
104
109
|
displaylogo: !1,
|
|
105
110
|
fillFrame: !0
|
|
106
111
|
};
|
|
107
|
-
|
|
112
|
+
G.newPlot(x.current, s, b, a);
|
|
108
113
|
const c = x.current;
|
|
109
114
|
return () => {
|
|
110
|
-
c &&
|
|
115
|
+
c && G.purge(c);
|
|
111
116
|
};
|
|
112
|
-
}, [e, r, m,
|
|
117
|
+
}, [e, r, m, v, w, C, A, _, t, y]), e.length === 0 ? /* @__PURE__ */ p("div", { className: "chart-container", children: "No data available" }) : /* @__PURE__ */ S("div", { className: "chromatogram-container", style: { width: r, height: m }, children: [
|
|
113
118
|
(() => {
|
|
114
|
-
const
|
|
115
|
-
const a = Math.min(...
|
|
116
|
-
return /* @__PURE__ */ p("div", { className: "sequence-letters-container", children:
|
|
117
|
-
const o =
|
|
119
|
+
const s = () => {
|
|
120
|
+
const a = Math.min(...t), c = Math.max(...t), q = r;
|
|
121
|
+
return /* @__PURE__ */ p("div", { className: "sequence-letters-container", children: B.map((l, g) => {
|
|
122
|
+
const o = t[g], E = l === "A" ? h : l === "T" ? u : l === "G" ? i : l === "C" ? f : y.textColor, R = (o - a) / (c - a) * q;
|
|
118
123
|
return /* @__PURE__ */ p(
|
|
119
124
|
"span",
|
|
120
125
|
{
|
|
121
126
|
className: "sequence-letter",
|
|
122
127
|
style: {
|
|
123
|
-
left: `${
|
|
128
|
+
left: `${R}px`,
|
|
124
129
|
color: E
|
|
125
130
|
},
|
|
126
131
|
children: l
|
|
@@ -128,21 +133,21 @@ const $ = 75, L = 1.05, R = (e) => {
|
|
|
128
133
|
`base-${g}`
|
|
129
134
|
);
|
|
130
135
|
}) });
|
|
131
|
-
},
|
|
132
|
-
const a = Math.min(...
|
|
136
|
+
}, b = () => {
|
|
137
|
+
const a = Math.min(...t), c = Math.max(...t), q = r, l = Math.ceil(a / d) * d, g = [];
|
|
133
138
|
for (let o = l; o <= c; o += d)
|
|
134
139
|
g.push({
|
|
135
140
|
position: o,
|
|
136
141
|
label: o.toString()
|
|
137
142
|
});
|
|
138
143
|
return /* @__PURE__ */ p("div", { className: "position-numbers-container", children: g.map((o) => {
|
|
139
|
-
const
|
|
144
|
+
const O = (o.position - a) / (c - a) * q;
|
|
140
145
|
return /* @__PURE__ */ p(
|
|
141
146
|
"span",
|
|
142
147
|
{
|
|
143
148
|
className: "position-number",
|
|
144
149
|
style: {
|
|
145
|
-
left: `${
|
|
150
|
+
left: `${O}px`
|
|
146
151
|
},
|
|
147
152
|
children: o.label
|
|
148
153
|
},
|
|
@@ -150,15 +155,15 @@ const $ = 75, L = 1.05, R = (e) => {
|
|
|
150
155
|
);
|
|
151
156
|
}) });
|
|
152
157
|
};
|
|
153
|
-
return /* @__PURE__ */
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
return /* @__PURE__ */ S("div", { className: "sequence-header", children: [
|
|
159
|
+
s(),
|
|
160
|
+
b()
|
|
156
161
|
] });
|
|
157
162
|
})(),
|
|
158
163
|
/* @__PURE__ */ p("div", { className: "chromatogram-chart", children: /* @__PURE__ */ p("div", { ref: x, style: { width: "100%", height: "100%" } }) })
|
|
159
164
|
] });
|
|
160
165
|
};
|
|
161
166
|
export {
|
|
162
|
-
|
|
167
|
+
K as Chromatogram
|
|
163
168
|
};
|
|
164
169
|
//# sourceMappingURL=Chromatogram.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chromatogram.js","sources":["../../../../src/components/charts/Chromatogram/Chromatogram.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport \"./Chromatogram.scss\";\n\n/** Height offset for the plot area in pixels */\nconst PLOT_HEIGHT_OFFSET = 75;\n/** Scale factor for y-axis range to add padding above max value */\nconst Y_AXIS_PADDING_FACTOR = 1.05;\n\ninterface PeakData {\n position: number;\n base?: string;\n peakA: number;\n peakT: number;\n peakG: number;\n peakC: number;\n}\n\ninterface ChromatogramProps {\n data?: PeakData[];\n width?: number;\n height?: number;\n positionInterval?: number;\n colorA?: string;\n colorT?: string;\n colorG?: string;\n colorC?: string;\n}\n\nconst determineBase = (item: PeakData): string => {\n const peakValues = {\n A: item.peakA,\n T: item.peakT,\n G: item.peakG,\n C: item.peakC,\n };\n\n const values = Object.values(peakValues);\n const allEqual = values.every((val) => val === values[0]);\n\n if (allEqual) {\n return \"\";\n }\n\n let highestBase = \"\";\n let highestValue = 0;\n\n Object.entries(peakValues).forEach(([base, value]) => {\n if (value > highestValue) {\n highestBase = base;\n highestValue = value;\n }\n });\n\n return highestBase;\n};\n\nconst Chromatogram: React.FC<ChromatogramProps> = ({\n data = [],\n width = 900,\n height = 600,\n positionInterval = 10,\n colorA = \"#2D9CDB\",\n colorT = \"#A1C63C\",\n colorG = \"#FF5C64\",\n colorC = \"#FFA62E\",\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n\n const positions = useMemo(() => data.map((item) => item.position), [data]);\n const sequence = useMemo(() => data.map((item) => determineBase(item)), [data]);\n const peakA = useMemo(() => data.map((item) => item.peakA), [data]);\n const peakT = useMemo(() => data.map((item) => item.peakT), [data]);\n const peakG = useMemo(() => data.map((item) => item.peakG), [data]);\n const peakC = useMemo(() => data.map((item) => item.peakC), [data]);\n\n const aTrace = useMemo(\n () => ({\n x: positions,\n y: peakA,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"A\",\n line: { color: colorA, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakA, colorA],\n );\n\n const tTrace = useMemo(\n () => ({\n x: positions,\n y: peakT,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"T\",\n line: { color: colorT, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakT, colorT],\n );\n\n const gTrace = useMemo(\n () => ({\n x: positions,\n y: peakG,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"G\",\n line: { color: colorG, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakG, colorG],\n );\n\n const cTrace = useMemo(\n () => ({\n x: positions,\n y: peakC,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"C\",\n line: { color: colorC, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakC, colorC],\n );\n\n const maxValue = useMemo(\n () => Math.max(...peakA, ...peakT, ...peakG, ...peakC),\n [peakA, peakT, peakG, peakC],\n );\n\n useEffect(() => {\n if (!plotRef.current || data.length === 0) return;\n\n const plotData = [aTrace, tTrace, gTrace, cTrace];\n\n const layout: Partial<Plotly.Layout> = {\n width: width,\n height: height - PLOT_HEIGHT_OFFSET,\n margin: { l: 0, r: 0, b: 20, t: 10, pad: 0 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n showlegend: false,\n xaxis: {\n showgrid: false,\n zeroline: false,\n showticklabels: false,\n showline: false,\n range: [Math.min(...positions), Math.max(...positions)],\n fixedrange: true,\n },\n yaxis: {\n showgrid: false,\n zeroline: false,\n showticklabels: false,\n showline: false,\n range: [0, maxValue * Y_AXIS_PADDING_FACTOR],\n fixedrange: true,\n },\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n fillFrame: true,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [data, width, height, aTrace, tTrace, gTrace, cTrace, maxValue, positions, theme]);\n\n if (data.length === 0) {\n return <div className=\"chart-container\">No data available</div>;\n }\n\n const renderSequence = () => {\n const renderSequenceLetters = () => {\n const minPosition = Math.min(...positions);\n const maxPosition = Math.max(...positions);\n const chartWidth = width;\n\n return (\n <div className=\"sequence-letters-container\">\n {sequence.map((base, index) => {\n const position = positions[index];\n const color =\n base === \"A\"\n ? colorA\n : base === \"T\"\n ? colorT\n : base === \"G\"\n ? colorG\n : base === \"C\"\n ? colorC\n : theme.textColor;\n\n const percentage =\n (position - minPosition) / (maxPosition - minPosition);\n const leftPosition = percentage * chartWidth;\n\n return (\n <span\n key={`base-${index}`}\n className=\"sequence-letter\"\n style={{\n left: `${leftPosition}px`,\n color,\n }}\n >\n {base}\n </span>\n );\n })}\n </div>\n );\n };\n\n const renderPositionNumbers = () => {\n const minPosition = Math.min(...positions);\n const maxPosition = Math.max(...positions);\n const chartWidth = width;\n\n const startPos =\n Math.ceil(minPosition / positionInterval) * positionInterval;\n\n const regularPositionLabels: Array<{ position: number; label: string }> =\n [];\n\n for (let pos = startPos; pos <= maxPosition; pos += positionInterval) {\n regularPositionLabels.push({\n position: pos,\n label: pos.toString(),\n });\n }\n\n return (\n <div className=\"position-numbers-container\">\n {regularPositionLabels.map((label) => {\n const percentage =\n (label.position - minPosition) / (maxPosition - minPosition);\n const leftPosition = percentage * chartWidth;\n\n return (\n <span\n key={`pos-${label.position}`}\n className=\"position-number\"\n style={{\n left: `${leftPosition}px`,\n }}\n >\n {label.label}\n </span>\n );\n })}\n </div>\n );\n };\n\n return (\n <div className=\"sequence-header\">\n {renderSequenceLetters()}\n {renderPositionNumbers()}\n </div>\n );\n };\n\n return (\n <div className=\"chromatogram-container\" style={{ width, height }}>\n {renderSequence()}\n <div className=\"chromatogram-chart\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n </div>\n </div>\n );\n};\n\nexport { Chromatogram };\nexport type { PeakData, ChromatogramProps };\n"],"names":["PLOT_HEIGHT_OFFSET","Y_AXIS_PADDING_FACTOR","determineBase","item","peakValues","values","val","highestBase","highestValue","base","value","Chromatogram","data","width","height","positionInterval","colorA","colorT","colorG","colorC","plotRef","useRef","theme","usePlotlyTheme","positions","useMemo","sequence","peakA","peakT","peakG","peakC","aTrace","tTrace","gTrace","cTrace","maxValue","useEffect","plotData","layout","config","Plotly","plotElement","jsx","jsxs","renderSequenceLetters","minPosition","maxPosition","chartWidth","index","position","color","leftPosition","renderPositionNumbers","startPos","regularPositionLabels","pos","label"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Chromatogram.js","sources":["../../../../src/components/charts/Chromatogram/Chromatogram.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { CHART_COLORS } from \"@/utils/colors\";\nimport \"./Chromatogram.scss\";\n\n/** Height offset for the plot area in pixels */\nconst PLOT_HEIGHT_OFFSET = 75;\n/** Scale factor for y-axis range to add padding above max value */\nconst Y_AXIS_PADDING_FACTOR = 1.05;\n\ninterface PeakData {\n position: number;\n base?: string;\n peakA: number;\n peakT: number;\n peakG: number;\n peakC: number;\n}\n\ninterface ChromatogramProps {\n data?: PeakData[];\n width?: number;\n height?: number;\n positionInterval?: number;\n colorA?: string;\n colorT?: string;\n colorG?: string;\n colorC?: string;\n}\n\nconst determineBase = (item: PeakData): string => {\n const peakValues = {\n A: item.peakA,\n T: item.peakT,\n G: item.peakG,\n C: item.peakC,\n };\n\n const values = Object.values(peakValues);\n const allEqual = values.every((val) => val === values[0]);\n\n if (allEqual) {\n return \"\";\n }\n\n let highestBase = \"\";\n let highestValue = 0;\n\n Object.entries(peakValues).forEach(([base, value]) => {\n if (value > highestValue) {\n highestBase = base;\n highestValue = value;\n }\n });\n\n return highestBase;\n};\n\nconst Chromatogram: React.FC<ChromatogramProps> = ({\n data = [],\n width = 900,\n height = 600,\n positionInterval = 10,\n colorA = CHART_COLORS[0], // blue\n colorT = CHART_COLORS[2], // teal/green\n colorG = CHART_COLORS[3], // red\n colorC = CHART_COLORS[1], // orange\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n\n const positions = useMemo(() => data.map((item) => item.position), [data]);\n const sequence = useMemo(() => data.map((item) => determineBase(item)), [data]);\n const peakA = useMemo(() => data.map((item) => item.peakA), [data]);\n const peakT = useMemo(() => data.map((item) => item.peakT), [data]);\n const peakG = useMemo(() => data.map((item) => item.peakG), [data]);\n const peakC = useMemo(() => data.map((item) => item.peakC), [data]);\n\n const aTrace = useMemo(\n () => ({\n x: positions,\n y: peakA,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"A\",\n line: { color: colorA, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakA, colorA],\n );\n\n const tTrace = useMemo(\n () => ({\n x: positions,\n y: peakT,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"T\",\n line: { color: colorT, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakT, colorT],\n );\n\n const gTrace = useMemo(\n () => ({\n x: positions,\n y: peakG,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"G\",\n line: { color: colorG, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakG, colorG],\n );\n\n const cTrace = useMemo(\n () => ({\n x: positions,\n y: peakC,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: \"C\",\n line: { color: colorC, width: 2, shape: \"spline\" as const },\n }),\n [positions, peakC, colorC],\n );\n\n const maxValue = useMemo(\n () => Math.max(...peakA, ...peakT, ...peakG, ...peakC),\n [peakA, peakT, peakG, peakC],\n );\n\n useEffect(() => {\n if (!plotRef.current || data.length === 0) return;\n\n const plotData = [aTrace, tTrace, gTrace, cTrace];\n\n const layout: Partial<Plotly.Layout> = {\n width: width,\n height: height - PLOT_HEIGHT_OFFSET,\n margin: { l: 0, r: 0, b: 20, t: 10, pad: 0 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n showlegend: false,\n xaxis: {\n showgrid: false,\n zeroline: false,\n showticklabels: false,\n showline: false,\n range: [Math.min(...positions), Math.max(...positions)],\n fixedrange: true,\n },\n yaxis: {\n showgrid: false,\n zeroline: false,\n showticklabels: false,\n showline: false,\n range: [0, maxValue * Y_AXIS_PADDING_FACTOR],\n fixedrange: true,\n },\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n fillFrame: true,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [data, width, height, aTrace, tTrace, gTrace, cTrace, maxValue, positions, theme]);\n\n if (data.length === 0) {\n return <div className=\"chart-container\">No data available</div>;\n }\n\n const renderSequence = () => {\n const renderSequenceLetters = () => {\n const minPosition = Math.min(...positions);\n const maxPosition = Math.max(...positions);\n const chartWidth = width;\n\n return (\n <div className=\"sequence-letters-container\">\n {sequence.map((base, index) => {\n const position = positions[index];\n const color =\n base === \"A\"\n ? colorA\n : base === \"T\"\n ? colorT\n : base === \"G\"\n ? colorG\n : base === \"C\"\n ? colorC\n : theme.textColor;\n\n const percentage =\n (position - minPosition) / (maxPosition - minPosition);\n const leftPosition = percentage * chartWidth;\n\n return (\n <span\n key={`base-${index}`}\n className=\"sequence-letter\"\n style={{\n left: `${leftPosition}px`,\n color,\n }}\n >\n {base}\n </span>\n );\n })}\n </div>\n );\n };\n\n const renderPositionNumbers = () => {\n const minPosition = Math.min(...positions);\n const maxPosition = Math.max(...positions);\n const chartWidth = width;\n\n const startPos =\n Math.ceil(minPosition / positionInterval) * positionInterval;\n\n const regularPositionLabels: Array<{ position: number; label: string }> =\n [];\n\n for (let pos = startPos; pos <= maxPosition; pos += positionInterval) {\n regularPositionLabels.push({\n position: pos,\n label: pos.toString(),\n });\n }\n\n return (\n <div className=\"position-numbers-container\">\n {regularPositionLabels.map((label) => {\n const percentage =\n (label.position - minPosition) / (maxPosition - minPosition);\n const leftPosition = percentage * chartWidth;\n\n return (\n <span\n key={`pos-${label.position}`}\n className=\"position-number\"\n style={{\n left: `${leftPosition}px`,\n }}\n >\n {label.label}\n </span>\n );\n })}\n </div>\n );\n };\n\n return (\n <div className=\"sequence-header\">\n {renderSequenceLetters()}\n {renderPositionNumbers()}\n </div>\n );\n };\n\n return (\n <div className=\"chromatogram-container\" style={{ width, height }}>\n {renderSequence()}\n <div className=\"chromatogram-chart\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n </div>\n </div>\n );\n};\n\nexport { Chromatogram };\nexport type { PeakData, ChromatogramProps };\n"],"names":["PLOT_HEIGHT_OFFSET","Y_AXIS_PADDING_FACTOR","determineBase","item","peakValues","values","val","highestBase","highestValue","base","value","Chromatogram","data","width","height","positionInterval","colorA","CHART_COLORS","colorT","colorG","colorC","plotRef","useRef","theme","usePlotlyTheme","positions","useMemo","sequence","peakA","peakT","peakG","peakC","aTrace","tTrace","gTrace","cTrace","maxValue","useEffect","plotData","layout","config","Plotly","plotElement","jsx","jsxs","renderSequenceLetters","minPosition","maxPosition","chartWidth","index","position","color","leftPosition","renderPositionNumbers","startPos","regularPositionLabels","pos","label"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("react/jsx-runtime"),Y=require("plotly.js-dist"),u=require("react"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("react/jsx-runtime"),Y=require("plotly.js-dist"),u=require("react"),J=require("../../../utils/colors.cjs"),j=require("./annotations.cjs"),K=require("./boundaryMarkers.cjs"),s=require("./constants.cjs"),f=require("./dataProcessing.cjs"),Q=require("./peakDetection.cjs"),V=require("../../../hooks/use-plotly-theme.cjs"),Z=({series:a,width:k=900,height:A=500,title:d,xAxisTitle:M="Retention Time (min)",yAxisTitle:T="Signal (mAU)",annotations:m=[],xRange:x,yRange:R,showLegend:P=!0,showGridX:v=!0,showGridY:G=!0,showMarkers:C=!1,markerSize:q=4,showCrosshairs:p=!1,baselineCorrection:H="none",baselineWindowSize:b=50,peakDetectionOptions:l,showPeakAreas:z=!1,boundaryMarkers:B="none",annotationOverlapThreshold:L=.4,showExportButton:I=!0})=>{const g=l!==void 0,N=u.useRef(null),e=V.usePlotlyTheme(),n=u.useMemo(()=>a.map(t=>{const r=f.validateSeriesData(t.x,t.y);return{...t,x:r.x,y:f.applyBaselineCorrection(r.y,H,b)}}),[a,H,b]),O=u.useMemo(()=>{if(m.length===0||n.length===0)return m;const{x:t,y:r}=n[0];return f.processUserAnnotations(m,t,r)},[m,n]),_=u.useMemo(()=>{const t=[];return g&&l&&n.forEach((r,c)=>{const y=Q.detectPeaks(r.x,r.y,l);y.length>0&&t.push({peaks:y,seriesIndex:c})}),t},[n,g,l]);return u.useEffect(()=>{const t=N.current;if(!t||a.length===0)return;const r=n.map((o,i)=>{const h=J.seriesColor(i,o.color),F=f.buildHoverExtraContent(o.name,o.metadata),E={x:o.x,y:o.y,type:"scatter",mode:C?"lines+markers":"lines",name:o.name,line:{color:h,width:1.5},hovertemplate:`%{x:.2f} ${M}<br>%{y:.2f} ${T}<extra>${F}</extra>`};return C&&(E.marker={size:q,color:h}),E});if(B!=="none"){const o=f.collectPeaksWithBoundaryData(_,O,n);if(o.length>0){const i=K.createBoundaryMarkerTraces(o);r.push(...i)}}const c=[];O.forEach(o=>{c.push({peak:o,seriesIndex:-1})}),z&&g&&_.forEach(({peaks:o,seriesIndex:i})=>{o.forEach(h=>{c.push({peak:h,seriesIndex:i})})});const y=j.groupOverlappingPeaks(c,L),U=[];for(const o of y)U.push(...j.createGroupAnnotations(o));const D={title:d?{text:d,font:{size:20,family:"Inter, sans-serif",color:e.textColor}}:void 0,width:k,height:A,margin:{l:s.CHROMATOGRAM_LAYOUT.MARGIN_LEFT,r:s.CHROMATOGRAM_LAYOUT.MARGIN_RIGHT,b:s.CHROMATOGRAM_LAYOUT.MARGIN_BOTTOM,t:d?s.CHROMATOGRAM_LAYOUT.MARGIN_TOP_WITH_TITLE:s.CHROMATOGRAM_LAYOUT.MARGIN_TOP_NO_TITLE,pad:s.CHROMATOGRAM_LAYOUT.MARGIN_PAD},paper_bgcolor:e.paperBg,plot_bgcolor:e.plotBg,font:{family:"Inter, sans-serif"},hovermode:p?"x":"x unified",dragmode:"zoom",xaxis:{title:{text:M,font:{size:14,color:e.textSecondary,family:"Inter, sans-serif"},standoff:15},showgrid:v,gridcolor:e.gridColor,linecolor:e.lineColor,linewidth:1,range:x,autorange:!x,zeroline:!1,tickfont:{size:12,color:e.textColor,family:"Inter, sans-serif"},showspikes:p,spikemode:"across",spikesnap:"cursor",spikecolor:e.spikeColor,spikethickness:1,spikedash:"dot"},yaxis:{title:{text:T,font:{size:14,color:e.textSecondary,family:"Inter, sans-serif"},standoff:10},showgrid:G,gridcolor:e.gridColor,linecolor:e.lineColor,linewidth:1,range:R,autorange:!R,zeroline:!1,tickfont:{size:12,color:e.textColor,family:"Inter, sans-serif"},showspikes:p,spikemode:"across",spikesnap:"cursor",spikecolor:e.spikeColor,spikethickness:1,spikedash:"dot"},legend:{x:.5,y:-.15,xanchor:"center",yanchor:"top",orientation:"h",font:{size:12,color:e.textColor,family:"Inter, sans-serif"}},showlegend:P&&a.length>1,annotations:U},W={responsive:!0,displayModeBar:!0,displaylogo:!1,modeBarButtonsToRemove:["lasso2d","select2d",...I?[]:["toImage"]],...I&&{toImageButtonOptions:{format:"png",filename:"chromatogram",width:k,height:A}}};return Y.newPlot(t,r,D,W),()=>{t&&Y.purge(t)}},[n,_,a.length,k,A,d,M,T,O,x,R,P,v,G,C,q,p,g,l,z,B,L,I,e]),S.jsx("div",{className:"chromatogram-chart-container",children:S.jsx("div",{ref:N,style:{width:"100%",height:"100%"}})})};exports.ChromatogramChart=Z;
|
|
2
2
|
//# sourceMappingURL=ChromatogramChart.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChromatogramChart.cjs","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":"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"}
|
|
1
|
+
{"version":3,"file":"ChromatogramChart.cjs","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\";\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 = seriesColor(index, s.color);\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","seriesColor","extraContent","buildHoverExtraContent","trace","peaksWithData","collectPeaksWithBoundaryData","boundaryTraces","createBoundaryMarkerTraces","allPeaksWithMeta","ann","seriesIndex","peak","groups","groupOverlappingPeaks","plotlyAnnotations","group","createGroupAnnotations","layout","CHROMATOGRAM_LAYOUT","config","Plotly","jsx"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { jsx as
|
|
1
|
+
import { jsx as S } from "react/jsx-runtime";
|
|
2
2
|
import U from "plotly.js-dist";
|
|
3
|
-
import { useRef as
|
|
4
|
-
import {
|
|
3
|
+
import { useRef as F, useMemo as A, useEffect as q } from "react";
|
|
4
|
+
import { seriesColor as J } from "../../../utils/colors.js";
|
|
5
5
|
import { groupOverlappingPeaks as K, createGroupAnnotations as Q } from "./annotations.js";
|
|
6
6
|
import { createBoundaryMarkerTraces as V } from "./boundaryMarkers.js";
|
|
7
7
|
import { CHROMATOGRAM_LAYOUT as a } from "./constants.js";
|
|
8
8
|
import { validateSeriesData as Y, applyBaselineCorrection as Z, processUserAnnotations as X, buildHoverExtraContent as w, collectPeaksWithBoundaryData as ee } from "./dataProcessing.js";
|
|
9
9
|
import { detectPeaks as oe } from "./peakDetection.js";
|
|
10
|
-
import { usePlotlyTheme as
|
|
10
|
+
import { usePlotlyTheme as re } from "../../../hooks/use-plotly-theme.js";
|
|
11
11
|
const de = ({
|
|
12
12
|
series: s,
|
|
13
13
|
width: y = 900,
|
|
@@ -18,8 +18,8 @@ const de = ({
|
|
|
18
18
|
annotations: m = [],
|
|
19
19
|
xRange: I,
|
|
20
20
|
yRange: C,
|
|
21
|
-
showLegend:
|
|
22
|
-
showGridX:
|
|
21
|
+
showLegend: M = !0,
|
|
22
|
+
showGridX: R = !0,
|
|
23
23
|
showGridY: z = !0,
|
|
24
24
|
showMarkers: T = !1,
|
|
25
25
|
markerSize: B = 4,
|
|
@@ -29,33 +29,33 @@ const de = ({
|
|
|
29
29
|
peakDetectionOptions: l,
|
|
30
30
|
showPeakAreas: G = !1,
|
|
31
31
|
boundaryMarkers: O = "none",
|
|
32
|
-
annotationOverlapThreshold:
|
|
32
|
+
annotationOverlapThreshold: b = 0.4,
|
|
33
33
|
showExportButton: _ = !0
|
|
34
34
|
}) => {
|
|
35
|
-
const d = l !== void 0,
|
|
36
|
-
const
|
|
35
|
+
const d = l !== void 0, H = F(null), e = re(), n = A(() => s.map((r) => {
|
|
36
|
+
const t = Y(r.x, r.y);
|
|
37
37
|
return {
|
|
38
|
-
...
|
|
39
|
-
x:
|
|
40
|
-
y: Z(
|
|
38
|
+
...r,
|
|
39
|
+
x: t.x,
|
|
40
|
+
y: Z(t.y, N, E)
|
|
41
41
|
};
|
|
42
|
-
}), [s, N, E]),
|
|
42
|
+
}), [s, N, E]), v = A(() => {
|
|
43
43
|
if (m.length === 0 || n.length === 0)
|
|
44
44
|
return m;
|
|
45
|
-
const { x:
|
|
46
|
-
return X(m,
|
|
47
|
-
}, [m, n]),
|
|
48
|
-
const
|
|
49
|
-
return d && l && n.forEach((
|
|
50
|
-
const u = oe(
|
|
51
|
-
u.length > 0 &&
|
|
52
|
-
}),
|
|
45
|
+
const { x: r, y: t } = n[0];
|
|
46
|
+
return X(m, r, t);
|
|
47
|
+
}, [m, n]), P = A(() => {
|
|
48
|
+
const r = [];
|
|
49
|
+
return d && l && n.forEach((t, i) => {
|
|
50
|
+
const u = oe(t.x, t.y, l);
|
|
51
|
+
u.length > 0 && r.push({ peaks: u, seriesIndex: i });
|
|
52
|
+
}), r;
|
|
53
53
|
}, [n, d, l]);
|
|
54
|
-
return
|
|
55
|
-
const
|
|
56
|
-
if (!
|
|
57
|
-
const
|
|
58
|
-
const g = o.color
|
|
54
|
+
return q(() => {
|
|
55
|
+
const r = H.current;
|
|
56
|
+
if (!r || s.length === 0) return;
|
|
57
|
+
const t = n.map((o, c) => {
|
|
58
|
+
const g = J(c, o.color), j = w(o.name, o.metadata), L = {
|
|
59
59
|
x: o.x,
|
|
60
60
|
y: o.y,
|
|
61
61
|
type: "scatter",
|
|
@@ -65,32 +65,32 @@ const de = ({
|
|
|
65
65
|
color: g,
|
|
66
66
|
width: 1.5
|
|
67
67
|
},
|
|
68
|
-
hovertemplate: `%{x:.2f} ${k}<br>%{y:.2f} ${x}<extra>${
|
|
68
|
+
hovertemplate: `%{x:.2f} ${k}<br>%{y:.2f} ${x}<extra>${j}</extra>`
|
|
69
69
|
};
|
|
70
|
-
return T && (
|
|
70
|
+
return T && (L.marker = {
|
|
71
71
|
size: B,
|
|
72
72
|
color: g
|
|
73
|
-
}),
|
|
73
|
+
}), L;
|
|
74
74
|
});
|
|
75
75
|
if (O !== "none") {
|
|
76
|
-
const o = ee(
|
|
76
|
+
const o = ee(P, v, n);
|
|
77
77
|
if (o.length > 0) {
|
|
78
78
|
const c = V(o);
|
|
79
|
-
|
|
79
|
+
t.push(...c);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
const i = [];
|
|
83
|
-
|
|
83
|
+
v.forEach((o) => {
|
|
84
84
|
i.push({ peak: o, seriesIndex: -1 });
|
|
85
|
-
}), G && d &&
|
|
85
|
+
}), G && d && P.forEach(({ peaks: o, seriesIndex: c }) => {
|
|
86
86
|
o.forEach((g) => {
|
|
87
87
|
i.push({ peak: g, seriesIndex: c });
|
|
88
88
|
});
|
|
89
89
|
});
|
|
90
|
-
const u = K(i,
|
|
90
|
+
const u = K(i, b), D = [];
|
|
91
91
|
for (const o of u)
|
|
92
|
-
|
|
93
|
-
const
|
|
92
|
+
D.push(...Q(o));
|
|
93
|
+
const W = {
|
|
94
94
|
title: f ? {
|
|
95
95
|
text: f,
|
|
96
96
|
font: {
|
|
@@ -119,7 +119,7 @@ const de = ({
|
|
|
119
119
|
font: { size: 14, color: e.textSecondary, family: "Inter, sans-serif" },
|
|
120
120
|
standoff: 15
|
|
121
121
|
},
|
|
122
|
-
showgrid:
|
|
122
|
+
showgrid: R,
|
|
123
123
|
gridcolor: e.gridColor,
|
|
124
124
|
linecolor: e.lineColor,
|
|
125
125
|
linewidth: 1,
|
|
@@ -163,9 +163,9 @@ const de = ({
|
|
|
163
163
|
orientation: "h",
|
|
164
164
|
font: { size: 12, color: e.textColor, family: "Inter, sans-serif" }
|
|
165
165
|
},
|
|
166
|
-
showlegend:
|
|
167
|
-
annotations:
|
|
168
|
-
},
|
|
166
|
+
showlegend: M && s.length > 1,
|
|
167
|
+
annotations: D
|
|
168
|
+
}, $ = {
|
|
169
169
|
responsive: !0,
|
|
170
170
|
displayModeBar: !0,
|
|
171
171
|
displaylogo: !1,
|
|
@@ -183,23 +183,23 @@ const de = ({
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
};
|
|
186
|
-
return U.newPlot(t,
|
|
187
|
-
|
|
186
|
+
return U.newPlot(r, t, W, $), () => {
|
|
187
|
+
r && U.purge(r);
|
|
188
188
|
};
|
|
189
189
|
}, [
|
|
190
190
|
n,
|
|
191
|
-
|
|
191
|
+
P,
|
|
192
192
|
s.length,
|
|
193
193
|
y,
|
|
194
194
|
h,
|
|
195
195
|
f,
|
|
196
196
|
k,
|
|
197
197
|
x,
|
|
198
|
-
|
|
198
|
+
v,
|
|
199
199
|
I,
|
|
200
200
|
C,
|
|
201
|
-
P,
|
|
202
201
|
M,
|
|
202
|
+
R,
|
|
203
203
|
z,
|
|
204
204
|
T,
|
|
205
205
|
B,
|
|
@@ -208,10 +208,10 @@ const de = ({
|
|
|
208
208
|
l,
|
|
209
209
|
G,
|
|
210
210
|
O,
|
|
211
|
-
|
|
211
|
+
b,
|
|
212
212
|
_,
|
|
213
213
|
e
|
|
214
|
-
]), /* @__PURE__ */
|
|
214
|
+
]), /* @__PURE__ */ S("div", { className: "chromatogram-chart-container", children: /* @__PURE__ */ S("div", { ref: H, style: { width: "100%", height: "100%" } }) });
|
|
215
215
|
};
|
|
216
216
|
export {
|
|
217
217
|
de as ChromatogramChart
|