@tetrascience-npm/tetrascience-react-ui 0.6.0-beta.83.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 +112 -82
- 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 +53 -48
- 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 +65 -60
- 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 -66
- 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 +107 -99
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.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 +52 -48
- 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 +96 -92
- 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 +44 -39
- 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 +58 -54
- 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/ScatterGraph/ScatterGraph.cjs +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.cjs.map +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.js +112 -89
- package/dist/components/charts/ScatterGraph/ScatterGraph.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +130 -0
- package/dist/index.js +585 -580
- package/dist/index.js.map +1 -1
- package/dist/index.tailwind.css +1 -1
- package/package.json +1 -1
|
@@ -1,85 +1,93 @@
|
|
|
1
|
-
import { jsx as p, jsxs as
|
|
2
|
-
import
|
|
3
|
-
import { useRef as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { jsx as p, jsxs as G } from "react/jsx-runtime";
|
|
2
|
+
import L from "plotly.js-dist";
|
|
3
|
+
import { useRef as F, useMemo as s, useEffect as $ } from "react";
|
|
4
|
+
import { useChartTooltip as D } from "../ChartTooltip/ChartTooltip.js";
|
|
5
|
+
import { usePlotlyTheme as H } from "../../../hooks/use-plotly-theme.js";
|
|
6
|
+
import { CHART_COLORS as b } from "../../../utils/colors.js";
|
|
6
7
|
/* empty css */
|
|
7
|
-
const
|
|
8
|
+
const I = 75, V = 1.05, z = (e) => {
|
|
8
9
|
const r = {
|
|
9
10
|
A: e.peakA,
|
|
10
11
|
T: e.peakT,
|
|
11
12
|
G: e.peakG,
|
|
12
13
|
C: e.peakC
|
|
13
14
|
}, m = Object.values(r);
|
|
14
|
-
if (m.every((
|
|
15
|
+
if (m.every((a) => a === m[0]))
|
|
15
16
|
return "";
|
|
16
17
|
let h = "", u = 0;
|
|
17
|
-
return Object.entries(r).forEach(([
|
|
18
|
-
f > u && (h =
|
|
18
|
+
return Object.entries(r).forEach(([a, f]) => {
|
|
19
|
+
f > u && (h = a, u = f);
|
|
19
20
|
}), h;
|
|
20
|
-
},
|
|
21
|
+
}, ee = ({
|
|
21
22
|
data: e = [],
|
|
22
23
|
width: r = 900,
|
|
23
24
|
height: m = 600,
|
|
24
|
-
positionInterval:
|
|
25
|
-
colorA: h =
|
|
25
|
+
positionInterval: x = 10,
|
|
26
|
+
colorA: h = b[0],
|
|
26
27
|
// blue
|
|
27
|
-
colorT: u =
|
|
28
|
+
colorT: u = b[2],
|
|
28
29
|
// teal/green
|
|
29
|
-
colorG:
|
|
30
|
+
colorG: a = b[3],
|
|
30
31
|
// red
|
|
31
|
-
colorC: f =
|
|
32
|
+
colorC: f = b[1]
|
|
32
33
|
// orange
|
|
33
34
|
}) => {
|
|
34
|
-
const
|
|
35
|
+
const g = F(null), y = H(), { bindTooltip: M, tooltipElement: B } = D({
|
|
36
|
+
xLabel: "Position",
|
|
37
|
+
yLabel: "Intensity"
|
|
38
|
+
}), n = s(() => e.map((t) => t.position), [e]), R = s(() => e.map((t) => z(t)), [e]), T = s(() => e.map((t) => t.peakA), [e]), k = s(() => e.map((t) => t.peakT), [e]), P = s(() => e.map((t) => t.peakG), [e]), v = s(() => e.map((t) => t.peakC), [e]), q = s(
|
|
35
39
|
() => ({
|
|
36
|
-
x:
|
|
37
|
-
y:
|
|
40
|
+
x: n,
|
|
41
|
+
y: T,
|
|
38
42
|
type: "scatter",
|
|
39
43
|
mode: "lines",
|
|
44
|
+
hoverinfo: "none",
|
|
40
45
|
name: "A",
|
|
41
46
|
line: { color: h, width: 2, shape: "spline" }
|
|
42
47
|
}),
|
|
43
|
-
[
|
|
44
|
-
), w =
|
|
48
|
+
[n, T, h]
|
|
49
|
+
), w = s(
|
|
45
50
|
() => ({
|
|
46
|
-
x:
|
|
47
|
-
y:
|
|
51
|
+
x: n,
|
|
52
|
+
y: k,
|
|
48
53
|
type: "scatter",
|
|
49
54
|
mode: "lines",
|
|
55
|
+
hoverinfo: "none",
|
|
50
56
|
name: "T",
|
|
51
57
|
line: { color: u, width: 2, shape: "spline" }
|
|
52
58
|
}),
|
|
53
|
-
[
|
|
54
|
-
),
|
|
59
|
+
[n, k, u]
|
|
60
|
+
), A = s(
|
|
55
61
|
() => ({
|
|
56
|
-
x:
|
|
57
|
-
y:
|
|
62
|
+
x: n,
|
|
63
|
+
y: P,
|
|
58
64
|
type: "scatter",
|
|
59
65
|
mode: "lines",
|
|
66
|
+
hoverinfo: "none",
|
|
60
67
|
name: "G",
|
|
61
|
-
line: { color:
|
|
68
|
+
line: { color: a, width: 2, shape: "spline" }
|
|
62
69
|
}),
|
|
63
|
-
[
|
|
64
|
-
),
|
|
70
|
+
[n, P, a]
|
|
71
|
+
), E = s(
|
|
65
72
|
() => ({
|
|
66
|
-
x:
|
|
67
|
-
y:
|
|
73
|
+
x: n,
|
|
74
|
+
y: v,
|
|
68
75
|
type: "scatter",
|
|
69
76
|
mode: "lines",
|
|
77
|
+
hoverinfo: "none",
|
|
70
78
|
name: "C",
|
|
71
79
|
line: { color: f, width: 2, shape: "spline" }
|
|
72
80
|
}),
|
|
73
|
-
[
|
|
74
|
-
), _ =
|
|
75
|
-
() => Math.max(...
|
|
76
|
-
[k, P,
|
|
81
|
+
[n, v, f]
|
|
82
|
+
), _ = s(
|
|
83
|
+
() => Math.max(...T, ...k, ...P, ...v),
|
|
84
|
+
[T, k, P, v]
|
|
77
85
|
);
|
|
78
|
-
return
|
|
79
|
-
if (!
|
|
80
|
-
const
|
|
86
|
+
return $(() => {
|
|
87
|
+
if (!g.current || e.length === 0) return;
|
|
88
|
+
const t = [q, w, A, E], N = {
|
|
81
89
|
width: r,
|
|
82
|
-
height: m -
|
|
90
|
+
height: m - I,
|
|
83
91
|
margin: { l: 0, r: 0, b: 20, t: 10, pad: 0 },
|
|
84
92
|
paper_bgcolor: y.paperBg,
|
|
85
93
|
plot_bgcolor: y.plotBg,
|
|
@@ -92,7 +100,7 @@ const $ = 75, D = 1.05, H = (e) => {
|
|
|
92
100
|
zeroline: !1,
|
|
93
101
|
showticklabels: !1,
|
|
94
102
|
showline: !1,
|
|
95
|
-
range: [Math.min(...
|
|
103
|
+
range: [Math.min(...n), Math.max(...n)],
|
|
96
104
|
fixedrange: !0
|
|
97
105
|
},
|
|
98
106
|
yaxis: {
|
|
@@ -100,54 +108,54 @@ const $ = 75, D = 1.05, H = (e) => {
|
|
|
100
108
|
zeroline: !1,
|
|
101
109
|
showticklabels: !1,
|
|
102
110
|
showline: !1,
|
|
103
|
-
range: [0, _ *
|
|
111
|
+
range: [0, _ * V],
|
|
104
112
|
fixedrange: !0
|
|
105
113
|
}
|
|
106
|
-
},
|
|
114
|
+
}, i = {
|
|
107
115
|
responsive: !0,
|
|
108
116
|
displayModeBar: !1,
|
|
109
117
|
displaylogo: !1,
|
|
110
118
|
fillFrame: !0
|
|
111
119
|
};
|
|
112
|
-
|
|
113
|
-
const
|
|
120
|
+
L.newPlot(g.current, t, N, i), M(g.current);
|
|
121
|
+
const l = g.current;
|
|
114
122
|
return () => {
|
|
115
|
-
|
|
123
|
+
l && L.purge(l);
|
|
116
124
|
};
|
|
117
|
-
}, [e, r, m,
|
|
125
|
+
}, [e, r, m, q, w, A, E, _, n, y, M]), e.length === 0 ? /* @__PURE__ */ p("div", { className: "chart-container", children: "No data available" }) : /* @__PURE__ */ G("div", { className: "chromatogram-container relative", style: { width: r, height: m }, children: [
|
|
118
126
|
(() => {
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
return /* @__PURE__ */ p("div", { className: "sequence-letters-container", children:
|
|
122
|
-
const o =
|
|
127
|
+
const t = () => {
|
|
128
|
+
const i = Math.min(...n), l = Math.max(...n), C = r;
|
|
129
|
+
return /* @__PURE__ */ p("div", { className: "sequence-letters-container", children: R.map((c, d) => {
|
|
130
|
+
const o = n[d], O = c === "A" ? h : c === "T" ? u : c === "G" ? a : c === "C" ? f : y.textColor, j = (o - i) / (l - i) * C;
|
|
123
131
|
return /* @__PURE__ */ p(
|
|
124
132
|
"span",
|
|
125
133
|
{
|
|
126
134
|
className: "sequence-letter",
|
|
127
135
|
style: {
|
|
128
|
-
left: `${
|
|
129
|
-
color:
|
|
136
|
+
left: `${j}px`,
|
|
137
|
+
color: O
|
|
130
138
|
},
|
|
131
|
-
children:
|
|
139
|
+
children: c
|
|
132
140
|
},
|
|
133
|
-
`base-${
|
|
141
|
+
`base-${d}`
|
|
134
142
|
);
|
|
135
143
|
}) });
|
|
136
|
-
},
|
|
137
|
-
const
|
|
138
|
-
for (let o =
|
|
139
|
-
|
|
144
|
+
}, N = () => {
|
|
145
|
+
const i = Math.min(...n), l = Math.max(...n), C = r, c = Math.ceil(i / x) * x, d = [];
|
|
146
|
+
for (let o = c; o <= l; o += x)
|
|
147
|
+
d.push({
|
|
140
148
|
position: o,
|
|
141
149
|
label: o.toString()
|
|
142
150
|
});
|
|
143
|
-
return /* @__PURE__ */ p("div", { className: "position-numbers-container", children:
|
|
144
|
-
const
|
|
151
|
+
return /* @__PURE__ */ p("div", { className: "position-numbers-container", children: d.map((o) => {
|
|
152
|
+
const S = (o.position - i) / (l - i) * C;
|
|
145
153
|
return /* @__PURE__ */ p(
|
|
146
154
|
"span",
|
|
147
155
|
{
|
|
148
156
|
className: "position-number",
|
|
149
157
|
style: {
|
|
150
|
-
left: `${
|
|
158
|
+
left: `${S}px`
|
|
151
159
|
},
|
|
152
160
|
children: o.label
|
|
153
161
|
},
|
|
@@ -155,15 +163,16 @@ const $ = 75, D = 1.05, H = (e) => {
|
|
|
155
163
|
);
|
|
156
164
|
}) });
|
|
157
165
|
};
|
|
158
|
-
return /* @__PURE__ */
|
|
159
|
-
|
|
160
|
-
|
|
166
|
+
return /* @__PURE__ */ G("div", { className: "sequence-header", children: [
|
|
167
|
+
t(),
|
|
168
|
+
N()
|
|
161
169
|
] });
|
|
162
170
|
})(),
|
|
163
|
-
/* @__PURE__ */ p("div", { className: "chromatogram-chart", children: /* @__PURE__ */ p("div", { ref:
|
|
171
|
+
/* @__PURE__ */ p("div", { className: "chromatogram-chart", children: /* @__PURE__ */ p("div", { ref: g, style: { width: "100%", height: "100%" } }) }),
|
|
172
|
+
B
|
|
164
173
|
] });
|
|
165
174
|
};
|
|
166
175
|
export {
|
|
167
|
-
|
|
176
|
+
ee as Chromatogram
|
|
168
177
|
};
|
|
169
178
|
//# 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 { 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
|
+
{"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 { useChartTooltip } from \"../ChartTooltip\";\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 const { bindTooltip, tooltipElement } = useChartTooltip({\n xLabel: \"Position\",\n yLabel: \"Intensity\",\n });\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 hoverinfo: \"none\" 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 hoverinfo: \"none\" 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 hoverinfo: \"none\" 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 hoverinfo: \"none\" 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 bindTooltip(plotRef.current);\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, bindTooltip]);\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 relative\" style={{ width, height }}>\n {renderSequence()}\n <div className=\"chromatogram-chart\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n </div>\n {tooltipElement}\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","bindTooltip","tooltipElement","useChartTooltip","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
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Y=require("react/jsx-runtime"),j=require("plotly.js-dist"),u=require("react"),K=require("../../../utils/colors.cjs"),Q=require("../ChartTooltip/ChartTooltip.cjs"),D=require("./annotations.cjs"),V=require("./boundaryMarkers.cjs"),s=require("./constants.cjs"),T=require("./dataProcessing.cjs"),Z=require("./peakDetection.cjs"),X=require("../../../hooks/use-plotly-theme.cjs"),w=[],$=({series:a,width:h=900,height:A=500,title:f,xAxisTitle:M="Retention Time (min)",yAxisTitle:k="Signal (mAU)",annotations:d=w,xRange:O,yRange:I,showLegend:P=!0,showGridX:v=!0,showGridY:G=!0,showMarkers:R=!1,markerSize:q=4,showCrosshairs:p=!1,baselineCorrection:N="none",baselineWindowSize:L=50,peakDetectionOptions:l,showPeakAreas:b=!1,boundaryMarkers:z="none",annotationOverlapThreshold:B=.4,showExportButton:C=!0})=>{const m=l!==void 0,E=u.useRef(null),e=X.usePlotlyTheme(),{bindTooltip:H,tooltipElement:W}=Q.useChartTooltip({xLabel:M,yLabel:k}),n=u.useMemo(()=>a.map(o=>{const r=T.validateSeriesData(o.x,o.y);return{...o,x:r.x,y:T.applyBaselineCorrection(r.y,N,L)}}),[a,N,L]),x=u.useMemo(()=>{if(d.length===0||n.length===0)return d;const{x:o,y:r}=n[0];return T.processUserAnnotations(d,o,r)},[d,n]),_=u.useMemo(()=>{const o=[];return m&&l&&n.forEach((r,c)=>{const g=Z.detectPeaks(r.x,r.y,l);g.length>0&&o.push({peaks:g,seriesIndex:c})}),o},[n,m,l]);return u.useEffect(()=>{const o=E.current;if(!o||a.length===0)return;const r=n.map((t,i)=>{const y=K.seriesColor(i,t.color),S={x:t.x,y:t.y,type:"scatter",mode:R?"lines+markers":"lines",name:t.name,line:{color:y,width:1.5},hoverinfo:"none"};return R&&(S.marker={size:q,color:y}),S});if(z!=="none"){const t=T.collectPeaksWithBoundaryData(_,x,n);if(t.length>0){const i=V.createBoundaryMarkerTraces(t);r.push(...i)}}const c=[];x.forEach(t=>{c.push({peak:t,seriesIndex:-1})}),b&&m&&_.forEach(({peaks:t,seriesIndex:i})=>{t.forEach(y=>{c.push({peak:y,seriesIndex:i})})});const g=D.groupOverlappingPeaks(c,B),U=[];for(const t of g)U.push(...D.createGroupAnnotations(t));const F={title:f?{text:f,font:{size:20,family:"Inter, sans-serif",color:e.textColor}}:void 0,width:h,height:A,margin:{l:s.CHROMATOGRAM_LAYOUT.MARGIN_LEFT,r:s.CHROMATOGRAM_LAYOUT.MARGIN_RIGHT,b:s.CHROMATOGRAM_LAYOUT.MARGIN_BOTTOM,t:f?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:O,autorange:!O,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:k,font:{size:14,color:e.textSecondary,family:"Inter, sans-serif"},standoff:10},showgrid:G,gridcolor:e.gridColor,linecolor:e.lineColor,linewidth:1,range:I,autorange:!I,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},J={responsive:!0,displayModeBar:!0,displaylogo:!1,modeBarButtonsToRemove:["lasso2d","select2d",...C?[]:["toImage"]],...C&&{toImageButtonOptions:{format:"png",filename:"chromatogram",width:h,height:A}}};return j.newPlot(o,r,F,J),H(o),()=>{o&&j.purge(o)}},[n,_,a.length,h,A,f,M,k,x,O,I,P,v,G,R,q,p,m,l,b,z,B,C,e,H]),Y.jsxs("div",{className:"chromatogram-chart-container relative",children:[Y.jsx("div",{ref:E,style:{width:"100%",height:"100%"}}),W]})};exports.ChromatogramChart=$;
|
|
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 { 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
|
+
{"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\";\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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"}
|