@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.
Files changed (63) hide show
  1. package/dist/components/charts/AreaGraph/AreaGraph.cjs +1 -1
  2. package/dist/components/charts/AreaGraph/AreaGraph.cjs.map +1 -1
  3. package/dist/components/charts/AreaGraph/AreaGraph.js +112 -82
  4. package/dist/components/charts/AreaGraph/AreaGraph.js.map +1 -1
  5. package/dist/components/charts/BarGraph/BarGraph.cjs +1 -1
  6. package/dist/components/charts/BarGraph/BarGraph.cjs.map +1 -1
  7. package/dist/components/charts/BarGraph/BarGraph.js +53 -48
  8. package/dist/components/charts/BarGraph/BarGraph.js.map +1 -1
  9. package/dist/components/charts/Boxplot/Boxplot.cjs +1 -1
  10. package/dist/components/charts/Boxplot/Boxplot.cjs.map +1 -1
  11. package/dist/components/charts/Boxplot/Boxplot.js +65 -60
  12. package/dist/components/charts/Boxplot/Boxplot.js.map +1 -1
  13. package/dist/components/charts/ChartTooltip/ChartTooltip.cjs +2 -0
  14. package/dist/components/charts/ChartTooltip/ChartTooltip.cjs.map +1 -0
  15. package/dist/components/charts/ChartTooltip/ChartTooltip.js +163 -0
  16. package/dist/components/charts/ChartTooltip/ChartTooltip.js.map +1 -0
  17. package/dist/components/charts/ChartTooltip/lines.cjs +2 -0
  18. package/dist/components/charts/ChartTooltip/lines.cjs.map +1 -0
  19. package/dist/components/charts/ChartTooltip/lines.js +29 -0
  20. package/dist/components/charts/ChartTooltip/lines.js.map +1 -0
  21. package/dist/components/charts/Chromatogram/Chromatogram.cjs +1 -1
  22. package/dist/components/charts/Chromatogram/Chromatogram.cjs.map +1 -1
  23. package/dist/components/charts/Chromatogram/Chromatogram.js +75 -66
  24. package/dist/components/charts/Chromatogram/Chromatogram.js.map +1 -1
  25. package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs +1 -1
  26. package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs.map +1 -1
  27. package/dist/components/charts/ChromatogramChart/ChromatogramChart.js +107 -99
  28. package/dist/components/charts/ChromatogramChart/ChromatogramChart.js.map +1 -1
  29. package/dist/components/charts/ChromatogramChart/dataProcessing.cjs +1 -1
  30. package/dist/components/charts/ChromatogramChart/dataProcessing.cjs.map +1 -1
  31. package/dist/components/charts/ChromatogramChart/dataProcessing.js +38 -49
  32. package/dist/components/charts/ChromatogramChart/dataProcessing.js.map +1 -1
  33. package/dist/components/charts/DotPlot/DotPlot.cjs +1 -1
  34. package/dist/components/charts/DotPlot/DotPlot.cjs.map +1 -1
  35. package/dist/components/charts/DotPlot/DotPlot.js +52 -48
  36. package/dist/components/charts/DotPlot/DotPlot.js.map +1 -1
  37. package/dist/components/charts/Histogram/Histogram.cjs +1 -1
  38. package/dist/components/charts/Histogram/Histogram.cjs.map +1 -1
  39. package/dist/components/charts/Histogram/Histogram.js +96 -92
  40. package/dist/components/charts/Histogram/Histogram.js.map +1 -1
  41. package/dist/components/charts/LineGraph/LineGraph.cjs +1 -1
  42. package/dist/components/charts/LineGraph/LineGraph.cjs.map +1 -1
  43. package/dist/components/charts/LineGraph/LineGraph.js +44 -39
  44. package/dist/components/charts/LineGraph/LineGraph.js.map +1 -1
  45. package/dist/components/charts/PieChart/PieChart.cjs +1 -1
  46. package/dist/components/charts/PieChart/PieChart.cjs.map +1 -1
  47. package/dist/components/charts/PieChart/PieChart.js +58 -54
  48. package/dist/components/charts/PieChart/PieChart.js.map +1 -1
  49. package/dist/components/charts/PlateMap/PlateMap.cjs +1 -1
  50. package/dist/components/charts/PlateMap/PlateMap.cjs.map +1 -1
  51. package/dist/components/charts/PlateMap/PlateMap.js +271 -256
  52. package/dist/components/charts/PlateMap/PlateMap.js.map +1 -1
  53. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs +1 -1
  54. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs.map +1 -1
  55. package/dist/components/charts/ScatterGraph/ScatterGraph.js +112 -89
  56. package/dist/components/charts/ScatterGraph/ScatterGraph.js.map +1 -1
  57. package/dist/index.cjs +1 -1
  58. package/dist/index.css +1 -1
  59. package/dist/index.d.ts +130 -0
  60. package/dist/index.js +585 -580
  61. package/dist/index.js.map +1 -1
  62. package/dist/index.tailwind.css +1 -1
  63. package/package.json +1 -1
@@ -1,157 +1,161 @@
1
- import { jsx as S } from "react/jsx-runtime";
1
+ import { jsxs as Y, jsx as q } from "react/jsx-runtime";
2
2
  import U from "plotly.js-dist";
3
- import { useRef as F, useMemo as A, useEffect as q } from "react";
4
- import { seriesColor as J } from "../../../utils/colors.js";
5
- import { groupOverlappingPeaks as K, createGroupAnnotations as Q } from "./annotations.js";
6
- import { createBoundaryMarkerTraces as V } from "./boundaryMarkers.js";
7
- import { CHROMATOGRAM_LAYOUT as a } from "./constants.js";
8
- import { validateSeriesData as Y, applyBaselineCorrection as Z, processUserAnnotations as X, buildHoverExtraContent as w, collectPeaksWithBoundaryData as ee } from "./dataProcessing.js";
9
- import { detectPeaks as oe } from "./peakDetection.js";
10
- import { usePlotlyTheme as re } from "../../../hooks/use-plotly-theme.js";
11
- const de = ({
12
- series: s,
3
+ import { useRef as J, useMemo as v, useEffect as K } from "react";
4
+ import { seriesColor as Q } from "../../../utils/colors.js";
5
+ import { useChartTooltip as V } from "../ChartTooltip/ChartTooltip.js";
6
+ import { groupOverlappingPeaks as Z, createGroupAnnotations as $ } from "./annotations.js";
7
+ import { createBoundaryMarkerTraces as X } from "./boundaryMarkers.js";
8
+ import { CHROMATOGRAM_LAYOUT as s } from "./constants.js";
9
+ import { validateSeriesData as w, applyBaselineCorrection as oo, processUserAnnotations as eo, collectPeaksWithBoundaryData as ro } from "./dataProcessing.js";
10
+ import { detectPeaks as to } from "./peakDetection.js";
11
+ import { usePlotlyTheme as no } from "../../../hooks/use-plotly-theme.js";
12
+ const so = [], ko = ({
13
+ series: a,
13
14
  width: y = 900,
14
15
  height: h = 500,
15
16
  title: f,
16
17
  xAxisTitle: k = "Retention Time (min)",
17
- yAxisTitle: x = "Signal (mAU)",
18
- annotations: m = [],
19
- xRange: I,
20
- yRange: C,
18
+ yAxisTitle: I = "Signal (mAU)",
19
+ annotations: m = so,
20
+ xRange: x,
21
+ yRange: T,
21
22
  showLegend: M = !0,
22
- showGridX: R = !0,
23
- showGridY: z = !0,
24
- showMarkers: T = !1,
25
- markerSize: B = 4,
23
+ showGridX: N = !0,
24
+ showGridY: R = !0,
25
+ showMarkers: _ = !1,
26
+ markerSize: z = 4,
26
27
  showCrosshairs: p = !1,
27
- baselineCorrection: N = "none",
28
+ baselineCorrection: B = "none",
28
29
  baselineWindowSize: E = 50,
29
30
  peakDetectionOptions: l,
30
31
  showPeakAreas: G = !1,
31
32
  boundaryMarkers: O = "none",
32
33
  annotationOverlapThreshold: b = 0.4,
33
- showExportButton: _ = !0
34
+ showExportButton: C = !0
34
35
  }) => {
35
- const d = l !== void 0, H = F(null), e = re(), n = A(() => s.map((r) => {
36
- const t = Y(r.x, r.y);
36
+ const d = l !== void 0, L = J(null), o = no(), { bindTooltip: S, tooltipElement: W } = V({
37
+ xLabel: k,
38
+ yLabel: I
39
+ }), n = v(() => a.map((e) => {
40
+ const t = w(e.x, e.y);
37
41
  return {
38
- ...r,
42
+ ...e,
39
43
  x: t.x,
40
- y: Z(t.y, N, E)
44
+ y: oo(t.y, B, E)
41
45
  };
42
- }), [s, N, E]), v = A(() => {
46
+ }), [a, B, E]), A = v(() => {
43
47
  if (m.length === 0 || n.length === 0)
44
48
  return m;
45
- const { x: r, y: t } = n[0];
46
- return X(m, r, t);
47
- }, [m, n]), P = A(() => {
48
- const r = [];
49
+ const { x: e, y: t } = n[0];
50
+ return eo(m, e, t);
51
+ }, [m, n]), P = v(() => {
52
+ const e = [];
49
53
  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;
54
+ const u = to(t.x, t.y, l);
55
+ u.length > 0 && e.push({ peaks: u, seriesIndex: i });
56
+ }), e;
53
57
  }, [n, d, l]);
54
- return 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
- x: o.x,
60
- y: o.y,
58
+ return K(() => {
59
+ const e = L.current;
60
+ if (!e || a.length === 0) return;
61
+ const t = n.map((r, c) => {
62
+ const g = Q(c, r.color), H = {
63
+ x: r.x,
64
+ y: r.y,
61
65
  type: "scatter",
62
- mode: T ? "lines+markers" : "lines",
63
- name: o.name,
66
+ mode: _ ? "lines+markers" : "lines",
67
+ name: r.name,
64
68
  line: {
65
69
  color: g,
66
70
  width: 1.5
67
71
  },
68
- hovertemplate: `%{x:.2f} ${k}<br>%{y:.2f} ${x}<extra>${j}</extra>`
72
+ hoverinfo: "none"
69
73
  };
70
- return T && (L.marker = {
71
- size: B,
74
+ return _ && (H.marker = {
75
+ size: z,
72
76
  color: g
73
- }), L;
77
+ }), H;
74
78
  });
75
79
  if (O !== "none") {
76
- const o = ee(P, v, n);
77
- if (o.length > 0) {
78
- const c = V(o);
80
+ const r = ro(P, A, n);
81
+ if (r.length > 0) {
82
+ const c = X(r);
79
83
  t.push(...c);
80
84
  }
81
85
  }
82
86
  const i = [];
83
- v.forEach((o) => {
84
- i.push({ peak: o, seriesIndex: -1 });
85
- }), G && d && P.forEach(({ peaks: o, seriesIndex: c }) => {
86
- o.forEach((g) => {
87
+ A.forEach((r) => {
88
+ i.push({ peak: r, seriesIndex: -1 });
89
+ }), G && d && P.forEach(({ peaks: r, seriesIndex: c }) => {
90
+ r.forEach((g) => {
87
91
  i.push({ peak: g, seriesIndex: c });
88
92
  });
89
93
  });
90
- const u = K(i, b), D = [];
91
- for (const o of u)
92
- D.push(...Q(o));
93
- const W = {
94
+ const u = Z(i, b), D = [];
95
+ for (const r of u)
96
+ D.push(...$(r));
97
+ const j = {
94
98
  title: f ? {
95
99
  text: f,
96
100
  font: {
97
101
  size: 20,
98
102
  family: "Inter, sans-serif",
99
- color: e.textColor
103
+ color: o.textColor
100
104
  }
101
105
  } : void 0,
102
106
  width: y,
103
107
  height: h,
104
108
  margin: {
105
- l: a.MARGIN_LEFT,
106
- r: a.MARGIN_RIGHT,
107
- b: a.MARGIN_BOTTOM,
108
- t: f ? a.MARGIN_TOP_WITH_TITLE : a.MARGIN_TOP_NO_TITLE,
109
- pad: a.MARGIN_PAD
109
+ l: s.MARGIN_LEFT,
110
+ r: s.MARGIN_RIGHT,
111
+ b: s.MARGIN_BOTTOM,
112
+ t: f ? s.MARGIN_TOP_WITH_TITLE : s.MARGIN_TOP_NO_TITLE,
113
+ pad: s.MARGIN_PAD
110
114
  },
111
- paper_bgcolor: e.paperBg,
112
- plot_bgcolor: e.plotBg,
115
+ paper_bgcolor: o.paperBg,
116
+ plot_bgcolor: o.plotBg,
113
117
  font: { family: "Inter, sans-serif" },
114
118
  hovermode: p ? "x" : "x unified",
115
119
  dragmode: "zoom",
116
120
  xaxis: {
117
121
  title: {
118
122
  text: k,
119
- font: { size: 14, color: e.textSecondary, family: "Inter, sans-serif" },
123
+ font: { size: 14, color: o.textSecondary, family: "Inter, sans-serif" },
120
124
  standoff: 15
121
125
  },
122
- showgrid: R,
123
- gridcolor: e.gridColor,
124
- linecolor: e.lineColor,
126
+ showgrid: N,
127
+ gridcolor: o.gridColor,
128
+ linecolor: o.lineColor,
125
129
  linewidth: 1,
126
- range: I,
127
- autorange: !I,
130
+ range: x,
131
+ autorange: !x,
128
132
  zeroline: !1,
129
- tickfont: { size: 12, color: e.textColor, family: "Inter, sans-serif" },
133
+ tickfont: { size: 12, color: o.textColor, family: "Inter, sans-serif" },
130
134
  showspikes: p,
131
135
  spikemode: "across",
132
136
  spikesnap: "cursor",
133
- spikecolor: e.spikeColor,
137
+ spikecolor: o.spikeColor,
134
138
  spikethickness: 1,
135
139
  spikedash: "dot"
136
140
  },
137
141
  yaxis: {
138
142
  title: {
139
- text: x,
140
- font: { size: 14, color: e.textSecondary, family: "Inter, sans-serif" },
143
+ text: I,
144
+ font: { size: 14, color: o.textSecondary, family: "Inter, sans-serif" },
141
145
  standoff: 10
142
146
  },
143
- showgrid: z,
144
- gridcolor: e.gridColor,
145
- linecolor: e.lineColor,
147
+ showgrid: R,
148
+ gridcolor: o.gridColor,
149
+ linecolor: o.lineColor,
146
150
  linewidth: 1,
147
- range: C,
148
- autorange: !C,
151
+ range: T,
152
+ autorange: !T,
149
153
  zeroline: !1,
150
- tickfont: { size: 12, color: e.textColor, family: "Inter, sans-serif" },
154
+ tickfont: { size: 12, color: o.textColor, family: "Inter, sans-serif" },
151
155
  showspikes: p,
152
156
  spikemode: "across",
153
157
  spikesnap: "cursor",
154
- spikecolor: e.spikeColor,
158
+ spikecolor: o.spikeColor,
155
159
  spikethickness: 1,
156
160
  spikedash: "dot"
157
161
  },
@@ -161,20 +165,20 @@ const de = ({
161
165
  xanchor: "center",
162
166
  yanchor: "top",
163
167
  orientation: "h",
164
- font: { size: 12, color: e.textColor, family: "Inter, sans-serif" }
168
+ font: { size: 12, color: o.textColor, family: "Inter, sans-serif" }
165
169
  },
166
- showlegend: M && s.length > 1,
170
+ showlegend: M && a.length > 1,
167
171
  annotations: D
168
- }, $ = {
172
+ }, F = {
169
173
  responsive: !0,
170
174
  displayModeBar: !0,
171
175
  displaylogo: !1,
172
176
  modeBarButtonsToRemove: [
173
177
  "lasso2d",
174
178
  "select2d",
175
- ..._ ? [] : ["toImage"]
179
+ ...C ? [] : ["toImage"]
176
180
  ],
177
- ..._ && {
181
+ ...C && {
178
182
  toImageButtonOptions: {
179
183
  format: "png",
180
184
  filename: "chromatogram",
@@ -183,37 +187,41 @@ const de = ({
183
187
  }
184
188
  }
185
189
  };
186
- return U.newPlot(r, t, W, $), () => {
187
- r && U.purge(r);
190
+ return U.newPlot(e, t, j, F), S(e), () => {
191
+ e && U.purge(e);
188
192
  };
189
193
  }, [
190
194
  n,
191
195
  P,
192
- s.length,
196
+ a.length,
193
197
  y,
194
198
  h,
195
199
  f,
196
200
  k,
197
- x,
198
- v,
199
201
  I,
200
- C,
202
+ A,
203
+ x,
204
+ T,
201
205
  M,
206
+ N,
202
207
  R,
208
+ _,
203
209
  z,
204
- T,
205
- B,
206
210
  p,
207
211
  d,
208
212
  l,
209
213
  G,
210
214
  O,
211
215
  b,
212
- _,
213
- e
214
- ]), /* @__PURE__ */ S("div", { className: "chromatogram-chart-container", children: /* @__PURE__ */ S("div", { ref: H, style: { width: "100%", height: "100%" } }) });
216
+ C,
217
+ o,
218
+ S
219
+ ]), /* @__PURE__ */ Y("div", { className: "chromatogram-chart-container relative", children: [
220
+ /* @__PURE__ */ q("div", { ref: L, style: { width: "100%", height: "100%" } }),
221
+ W
222
+ ] });
215
223
  };
216
224
  export {
217
- de as ChromatogramChart
225
+ ko as ChromatogramChart
218
226
  };
219
227
  //# sourceMappingURL=ChromatogramChart.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChromatogramChart.js","sources":["../../../../src/components/charts/ChromatogramChart/ChromatogramChart.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useMemo, useRef } from \"react\";\n\nimport { 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.js","sources":["../../../../src/components/charts/ChromatogramChart/ChromatogramChart.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useMemo, useRef } from \"react\";\n\nimport { seriesColor } from \"../../../utils/colors\";\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport {\n groupOverlappingPeaks,\n createGroupAnnotations,\n} from \"./annotations\";\nimport { createBoundaryMarkerTraces } from \"./boundaryMarkers\";\nimport { CHROMATOGRAM_LAYOUT } from \"./constants\";\nimport {\n validateSeriesData,\n applyBaselineCorrection,\n collectPeaksWithBoundaryData,\n processUserAnnotations,\n} from \"./dataProcessing\";\nimport { detectPeaks } from \"./peakDetection\";\n\nimport type {\n ChromatogramSeries,\n PeakAnnotation,\n BaselineCorrectionMethod,\n BoundaryMarkerStyle,\n BoundaryMarkerType,\n PeakDetectionOptions,\n ChromatogramChartProps,\n PeakWithMeta,\n} from \"./types\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\n// Re-export types for external use\nexport type {\n ChromatogramSeries,\n PeakAnnotation,\n BaselineCorrectionMethod,\n BoundaryMarkerStyle,\n BoundaryMarkerType,\n PeakDetectionOptions,\n ChromatogramChartProps,\n};\n\n\n// Stable default so the no-annotations case keeps a constant identity; an\n// inline `[]` default would change every render, re-running the plot effect\n// (and tearing down the hover tooltip) on each re-render.\nconst EMPTY_ANNOTATIONS: PeakAnnotation[] = [];\n\nconst ChromatogramChart: React.FC<ChromatogramChartProps> = ({\n series,\n width = 900,\n height = 500,\n title,\n xAxisTitle = \"Retention Time (min)\",\n yAxisTitle = \"Signal (mAU)\",\n annotations = EMPTY_ANNOTATIONS,\n xRange,\n yRange,\n showLegend = true,\n showGridX = true,\n showGridY = true,\n showMarkers = false,\n markerSize = 4,\n showCrosshairs = false,\n baselineCorrection = \"none\",\n baselineWindowSize = 50,\n peakDetectionOptions,\n showPeakAreas = false,\n boundaryMarkers = \"none\",\n annotationOverlapThreshold = 0.4,\n showExportButton = true,\n}) => {\n // Derive peak detection state from options\n const enablePeakDetection = peakDetectionOptions !== undefined;\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({\n xLabel: xAxisTitle,\n yLabel: yAxisTitle,\n });\n\n // Memoize processed series with baseline correction\n const processedSeries = useMemo(() => {\n return series.map((s) => {\n const validated = validateSeriesData(s.x, s.y);\n return {\n ...s,\n x: validated.x,\n y: applyBaselineCorrection(validated.y, baselineCorrection, baselineWindowSize),\n };\n });\n }, [series, baselineCorrection, baselineWindowSize]);\n\n // Process user annotations to convert startX/endX to indices and compute areas\n const processedAnnotations = useMemo(() => {\n if (annotations.length === 0 || processedSeries.length === 0) {\n return annotations;\n }\n // Use first series data for index lookup (user annotations apply to first series)\n const { x, y } = processedSeries[0];\n return processUserAnnotations(annotations, x, y);\n }, [annotations, processedSeries]);\n\n // Memoize peak detection results\n const allDetectedPeaks = useMemo(() => {\n const peaks: { peaks: PeakAnnotation[]; seriesIndex: number }[] = [];\n if (enablePeakDetection && peakDetectionOptions) {\n processedSeries.forEach((s, index) => {\n const detected = detectPeaks(s.x, s.y, peakDetectionOptions);\n if (detected.length > 0) {\n peaks.push({ peaks: detected, seriesIndex: index });\n }\n });\n }\n return peaks;\n }, [processedSeries, enablePeakDetection, peakDetectionOptions]);\n\n useEffect(() => {\n const currentRef = plotRef.current;\n if (!currentRef || series.length === 0) return;\n\n // Build trace data with auto-assigned colors\n const plotData: Plotly.Data[] = processedSeries.map((s, index) => {\n const traceColor = seriesColor(index, s.color);\n\n const trace: Plotly.Data = {\n x: s.x,\n y: s.y,\n type: \"scatter\" as const,\n mode: showMarkers ? \"lines+markers\" as const : \"lines\" as const,\n name: s.name,\n line: {\n color: traceColor,\n width: 1.5,\n },\n hoverinfo: \"none\" as const,\n };\n if (showMarkers) {\n trace.marker = {\n size: markerSize,\n color: traceColor,\n };\n }\n return trace;\n });\n\n // Add peak boundary markers if enabled\n if (boundaryMarkers !== \"none\") {\n const peaksWithData = collectPeaksWithBoundaryData(allDetectedPeaks, processedAnnotations, processedSeries);\n if (peaksWithData.length > 0) {\n const boundaryTraces = createBoundaryMarkerTraces(peaksWithData);\n plotData.push(...boundaryTraces);\n }\n }\n\n // Collect all peaks for unified staggering logic\n const allPeaksWithMeta: PeakWithMeta[] = [];\n\n // Add user-defined annotations (seriesIndex -1 indicates user-defined)\n processedAnnotations.forEach((ann) => {\n allPeaksWithMeta.push({ peak: ann, seriesIndex: -1 });\n });\n\n // Add auto-detected peaks if enabled\n if (showPeakAreas && enablePeakDetection) {\n allDetectedPeaks.forEach(({ peaks, seriesIndex }) => {\n peaks.forEach((peak) => {\n allPeaksWithMeta.push({ peak, seriesIndex });\n });\n });\n }\n\n // Group all overlapping peaks and create annotations with staggering\n const groups = groupOverlappingPeaks(allPeaksWithMeta, annotationOverlapThreshold);\n const plotlyAnnotations: Partial<Plotly.Annotations>[] = [];\n\n for (const group of groups) {\n plotlyAnnotations.push(...createGroupAnnotations(group));\n }\n\n const layout: Partial<Plotly.Layout> = {\n title: title\n ? {\n text: title,\n font: {\n size: 20,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n }\n : undefined,\n width,\n height,\n margin: {\n l: CHROMATOGRAM_LAYOUT.MARGIN_LEFT,\n r: CHROMATOGRAM_LAYOUT.MARGIN_RIGHT,\n b: CHROMATOGRAM_LAYOUT.MARGIN_BOTTOM,\n t: title ? CHROMATOGRAM_LAYOUT.MARGIN_TOP_WITH_TITLE : CHROMATOGRAM_LAYOUT.MARGIN_TOP_NO_TITLE,\n pad: CHROMATOGRAM_LAYOUT.MARGIN_PAD,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: { family: \"Inter, sans-serif\" },\n hovermode: showCrosshairs ? \"x\" as const : \"x unified\" as const,\n dragmode: \"zoom\" as const,\n xaxis: {\n title: {\n text: xAxisTitle,\n font: { size: 14, color: theme.textSecondary, family: \"Inter, sans-serif\" },\n standoff: 15,\n },\n showgrid: showGridX,\n gridcolor: theme.gridColor,\n linecolor: theme.lineColor,\n linewidth: 1,\n range: xRange,\n autorange: !xRange,\n zeroline: false,\n tickfont: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n showspikes: showCrosshairs,\n spikemode: \"across\" as const,\n spikesnap: \"cursor\" as const,\n spikecolor: theme.spikeColor,\n spikethickness: 1,\n spikedash: \"dot\" as const,\n },\n yaxis: {\n title: {\n text: yAxisTitle,\n font: { size: 14, color: theme.textSecondary, family: \"Inter, sans-serif\" },\n standoff: 10,\n },\n showgrid: showGridY,\n gridcolor: theme.gridColor,\n linecolor: theme.lineColor,\n linewidth: 1,\n range: yRange,\n autorange: !yRange,\n zeroline: false,\n tickfont: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n showspikes: showCrosshairs,\n spikemode: \"across\" as const,\n spikesnap: \"cursor\" as const,\n spikecolor: theme.spikeColor,\n spikethickness: 1,\n spikedash: \"dot\" as const,\n },\n legend: {\n x: 0.5,\n y: -0.15,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: { size: 12, color: theme.textColor, family: \"Inter, sans-serif\" },\n },\n showlegend: showLegend && series.length > 1,\n annotations: plotlyAnnotations,\n };\n\n const config: Partial<Plotly.Config> = {\n responsive: true,\n displayModeBar: true,\n displaylogo: false,\n modeBarButtonsToRemove: [\n \"lasso2d\",\n \"select2d\",\n ...(showExportButton ? [] : [\"toImage\"] as Plotly.ModeBarDefaultButtons[]),\n ] as Plotly.ModeBarDefaultButtons[],\n ...(showExportButton && {\n toImageButtonOptions: {\n format: \"png\",\n filename: \"chromatogram\",\n width: width,\n height: height,\n },\n }),\n };\n\n Plotly.newPlot(currentRef, plotData, layout, config);\n bindTooltip(currentRef);\n\n return () => {\n if (currentRef) {\n Plotly.purge(currentRef);\n }\n };\n }, [\n processedSeries, allDetectedPeaks, series.length, width, height, title, xAxisTitle, yAxisTitle,\n processedAnnotations, xRange, yRange, showLegend, showGridX, showGridY, showMarkers, markerSize,\n showCrosshairs, enablePeakDetection, peakDetectionOptions, showPeakAreas, boundaryMarkers,\n annotationOverlapThreshold, showExportButton, theme, bindTooltip,\n ]);\n\n return (\n <div className=\"chromatogram-chart-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { ChromatogramChart };\n\n"],"names":["EMPTY_ANNOTATIONS","ChromatogramChart","series","width","height","title","xAxisTitle","yAxisTitle","annotations","xRange","yRange","showLegend","showGridX","showGridY","showMarkers","markerSize","showCrosshairs","baselineCorrection","baselineWindowSize","peakDetectionOptions","showPeakAreas","boundaryMarkers","annotationOverlapThreshold","showExportButton","enablePeakDetection","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","processedSeries","useMemo","s","validated","validateSeriesData","applyBaselineCorrection","processedAnnotations","x","y","processUserAnnotations","allDetectedPeaks","peaks","index","detected","detectPeaks","useEffect","currentRef","plotData","traceColor","seriesColor","trace","peaksWithData","collectPeaksWithBoundaryData","boundaryTraces","createBoundaryMarkerTraces","allPeaksWithMeta","ann","seriesIndex","peak","groups","groupOverlappingPeaks","plotlyAnnotations","group","createGroupAnnotations","layout","CHROMATOGRAM_LAYOUT","config","Plotly","jsxs","jsx"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("./peakDetection.cjs");function s(t,i){if(t.length===0||t.length===1)return 0;let n=0,e=t.length-1;for(;n<e;){const o=Math.floor((n+e)/2);t[o]<i?n=o+1:e=o}return n>0&&Math.abs(t[n-1]-i)<Math.abs(t[n]-i)?n-1:n}function d(t,i,n){return t.map(e=>{if(e.startX!==void 0&&e.endX!==void 0){const o=s(i,e.startX),l=s(i,e.endX),r=s(i,e.x),a=e._computed?.area??u.calculatePeakArea(i,n,o,l);return{...e,_computed:{...e._computed,index:r,startIndex:o,endIndex:l,area:a}}}return e})}function h(t,i,n){const e=[];t.forEach(({peaks:l,seriesIndex:r})=>{e.push({peaks:l,seriesIndex:r,x:n[r].x,y:n[r].y})});const o=i.filter(l=>l._computed?.startIndex!==void 0&&l._computed?.endIndex!==void 0);return o.length>0&&n.length>0&&e.push({peaks:o,seriesIndex:0,x:n[0].x,y:n[0].y}),e}function f(t,i){if(!i)return t;const n=[];for(const[e,o]of Object.entries(i))if(o!=null&&o!==""){const l=e.replace(/([A-Z])/g," $1").replace(/^./,r=>r.toUpperCase()).trim();n.push(`${l}: ${String(o)}`)}return n.length>0?`${t}<br>${n.join("<br>")}`:t}function p(t,i){const n=Math.min(t.length,i.length),e=t.slice(0,n),l=i.slice(0,n).map(a=>Number.isFinite(a)?a:0);return{x:e.map(a=>Number.isFinite(a)?a:0),y:l}}function g(t,i,n=50){if(i==="none"||t.length===0)return t;if(i==="linear"){if(t.length===1)return[0];const e=(t[t.length-1]-t[0])/(t.length-1);return t.map((o,l)=>o-(t[0]+e*l))}if(i==="rolling"){const e=[],o=Math.floor(n/2);for(let l=0;l<t.length;l++){const r=Math.max(0,l-o),a=Math.min(t.length,l+o+1),c=t.slice(r,a);e.push(Math.min(...c))}return t.map((l,r)=>l-e[r])}return t}exports.applyBaselineCorrection=g;exports.buildHoverExtraContent=f;exports.collectPeaksWithBoundaryData=h;exports.findClosestIndex=s;exports.processUserAnnotations=d;exports.validateSeriesData=p;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("./peakDetection.cjs");function c(t,o){if(t.length===0||t.length===1)return 0;let n=0,e=t.length-1;for(;n<e;){const l=Math.floor((n+e)/2);t[l]<o?n=l+1:e=l}return n>0&&Math.abs(t[n-1]-o)<Math.abs(t[n]-o)?n-1:n}function d(t,o,n){return t.map(e=>{if(e.startX!==void 0&&e.endX!==void 0){const l=c(o,e.startX),i=c(o,e.endX),a=c(o,e.x),s=e._computed?.area??u.calculatePeakArea(o,n,l,i);return{...e,_computed:{...e._computed,index:a,startIndex:l,endIndex:i,area:s}}}return e})}function h(t,o,n){const e=[];t.forEach(({peaks:i,seriesIndex:a})=>{e.push({peaks:i,seriesIndex:a,x:n[a].x,y:n[a].y})});const l=o.filter(i=>i._computed?.startIndex!==void 0&&i._computed?.endIndex!==void 0);return l.length>0&&n.length>0&&e.push({peaks:l,seriesIndex:0,x:n[0].x,y:n[0].y}),e}function f(t,o){const n=Math.min(t.length,o.length),e=t.slice(0,n),i=o.slice(0,n).map(s=>Number.isFinite(s)?s:0);return{x:e.map(s=>Number.isFinite(s)?s:0),y:i}}function p(t,o,n=50){if(o==="none"||t.length===0)return t;if(o==="linear"){if(t.length===1)return[0];const e=(t[t.length-1]-t[0])/(t.length-1);return t.map((l,i)=>l-(t[0]+e*i))}if(o==="rolling"){const e=[],l=Math.floor(n/2);for(let i=0;i<t.length;i++){const a=Math.max(0,i-l),s=Math.min(t.length,i+l+1),r=t.slice(a,s);e.push(Math.min(...r))}return t.map((i,a)=>i-e[a])}return t}exports.applyBaselineCorrection=p;exports.collectPeaksWithBoundaryData=h;exports.findClosestIndex=c;exports.processUserAnnotations=d;exports.validateSeriesData=f;
2
2
  //# sourceMappingURL=dataProcessing.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataProcessing.cjs","sources":["../../../../src/components/charts/ChromatogramChart/dataProcessing.ts"],"sourcesContent":["/**\n * Data processing utilities for ChromatogramChart\n */\n\nimport { calculatePeakArea } from \"./peakDetection\";\n\nimport type { BaselineCorrectionMethod, PeakAnnotation } from \"./types\";\n\n/**\n * Data structure for peaks with their associated series data\n */\nexport type PeakDataWithSeries = {\n peaks: PeakAnnotation[];\n seriesIndex: number;\n x: number[];\n y: number[];\n};\n\n/**\n * Find the closest index in an array for a given target value.\n * Uses binary search for efficiency.\n */\nexport function findClosestIndex(arr: number[], target: number): number {\n if (arr.length === 0) return 0;\n if (arr.length === 1) return 0;\n\n let left = 0;\n let right = arr.length - 1;\n\n while (left < right) {\n const mid = Math.floor((left + right) / 2);\n if (arr[mid] < target) {\n left = mid + 1;\n } else {\n right = mid;\n }\n }\n\n // Check if left-1 is closer\n if (left > 0 && Math.abs(arr[left - 1] - target) < Math.abs(arr[left] - target)) {\n return left - 1;\n }\n return left;\n}\n\n/**\n * Process user annotations to convert startX/endX to startIndex/endIndex\n * and compute area if boundaries are provided.\n */\nexport function processUserAnnotations(\n annotations: PeakAnnotation[],\n xArray: number[],\n yArray: number[]\n): PeakAnnotation[] {\n return annotations.map((ann) => {\n // If startX/endX are provided, convert to indices\n if (ann.startX !== undefined && ann.endX !== undefined) {\n const startIndex = findClosestIndex(xArray, ann.startX);\n const endIndex = findClosestIndex(xArray, ann.endX);\n const index = findClosestIndex(xArray, ann.x);\n\n // Calculate area if not provided\n const area = ann._computed?.area ?? calculatePeakArea(xArray, yArray, startIndex, endIndex);\n\n return {\n ...ann,\n _computed: {\n ...ann._computed,\n index,\n startIndex,\n endIndex,\n area,\n },\n };\n }\n return ann;\n });\n}\n\n/**\n * Collect peaks with boundary information from both auto-detected peaks and user-provided annotations.\n * User-provided annotations with startIndex/endIndex or startX/endX are included for boundary marker rendering.\n */\nexport function collectPeaksWithBoundaryData(\n allDetectedPeaks: { peaks: PeakAnnotation[]; seriesIndex: number }[],\n annotations: PeakAnnotation[],\n processedSeries: { x: number[]; y: number[] }[]\n): PeakDataWithSeries[] {\n const peaksWithData: PeakDataWithSeries[] = [];\n\n // Add auto-detected peaks\n allDetectedPeaks.forEach(({ peaks, seriesIndex }) => {\n peaksWithData.push({\n peaks,\n seriesIndex,\n x: processedSeries[seriesIndex].x,\n y: processedSeries[seriesIndex].y,\n });\n });\n\n // Add user-provided annotations that have boundary info (_computed.startIndex and _computed.endIndex)\n // Note: annotations with startX/endX should already be processed to have _computed fields\n const annotationsWithBoundaries = annotations.filter(\n (ann) => ann._computed?.startIndex !== undefined && ann._computed?.endIndex !== undefined\n );\n if (annotationsWithBoundaries.length > 0 && processedSeries.length > 0) {\n peaksWithData.push({\n peaks: annotationsWithBoundaries,\n seriesIndex: 0, // User annotations apply to first series by default\n x: processedSeries[0].x,\n y: processedSeries[0].y,\n });\n }\n\n return peaksWithData;\n}\n\n/**\n * Build the extra content for Plotly hovertemplate from series metadata.\n * Displays all metadata fields as key: value pairs.\n */\nexport function buildHoverExtraContent(\n seriesName: string,\n metadata?: Record<string, unknown>\n): string {\n if (!metadata) return seriesName;\n\n const metaLines: string[] = [];\n for (const [key, value] of Object.entries(metadata)) {\n if (value !== undefined && value !== null && value !== \"\") {\n // Format the key as Title Case (e.g., \"sampleName\" -> \"Sample Name\")\n const formattedKey = key\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (s) => s.toUpperCase())\n .trim();\n metaLines.push(`${formattedKey}: ${String(value)}`);\n }\n }\n\n if (metaLines.length > 0) {\n return `${seriesName}<br>${metaLines.join(\"<br>\")}`;\n }\n return seriesName;\n}\n\n/**\n * Validate and sanitize series data.\n * - Ensures x and y arrays have the same length (truncates to shorter)\n * - Replaces NaN and Infinity values with 0\n */\nexport function validateSeriesData(\n x: number[],\n y: number[]\n): { x: number[]; y: number[] } {\n // Ensure arrays have same length\n const length = Math.min(x.length, y.length);\n const validX = x.slice(0, length);\n const validY = y.slice(0, length);\n\n // Sanitize NaN and Infinity values\n const sanitizedY = validY.map((val) => (Number.isFinite(val) ? val : 0));\n const sanitizedX = validX.map((val) => (Number.isFinite(val) ? val : 0));\n\n return { x: sanitizedX, y: sanitizedY };\n}\n\n/**\n * Apply baseline correction to signal data\n */\nexport function applyBaselineCorrection(\n y: number[],\n method: BaselineCorrectionMethod,\n windowSize: number = 50\n): number[] {\n if (method === \"none\" || y.length === 0) return y;\n\n if (method === \"linear\") {\n // Linear baseline from first to last point\n // Handle single-point case to avoid division by zero\n if (y.length === 1) {\n return [0]; // Single point baseline-corrected to zero\n }\n const slope = (y[y.length - 1] - y[0]) / (y.length - 1);\n return y.map((val, i) => val - (y[0] + slope * i));\n }\n\n if (method === \"rolling\") {\n // Rolling minimum baseline\n const baseline: number[] = [];\n const halfWindow = Math.floor(windowSize / 2);\n\n for (let i = 0; i < y.length; i++) {\n const start = Math.max(0, i - halfWindow);\n const end = Math.min(y.length, i + halfWindow + 1);\n const windowSlice = y.slice(start, end);\n baseline.push(Math.min(...windowSlice));\n }\n\n return y.map((val, i) => val - baseline[i]);\n }\n\n return y;\n}\n\n"],"names":["findClosestIndex","arr","target","left","right","mid","processUserAnnotations","annotations","xArray","yArray","ann","startIndex","endIndex","index","area","calculatePeakArea","collectPeaksWithBoundaryData","allDetectedPeaks","processedSeries","peaksWithData","peaks","seriesIndex","annotationsWithBoundaries","buildHoverExtraContent","seriesName","metadata","metaLines","key","value","formattedKey","s","validateSeriesData","x","y","length","validX","sanitizedY","val","applyBaselineCorrection","method","windowSize","slope","i","baseline","halfWindow","start","end","windowSlice"],"mappings":"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"}
1
+ {"version":3,"file":"dataProcessing.cjs","sources":["../../../../src/components/charts/ChromatogramChart/dataProcessing.ts"],"sourcesContent":["/**\n * Data processing utilities for ChromatogramChart\n */\n\nimport { calculatePeakArea } from \"./peakDetection\";\n\nimport type { BaselineCorrectionMethod, PeakAnnotation } from \"./types\";\n\n/**\n * Data structure for peaks with their associated series data\n */\nexport type PeakDataWithSeries = {\n peaks: PeakAnnotation[];\n seriesIndex: number;\n x: number[];\n y: number[];\n};\n\n/**\n * Find the closest index in an array for a given target value.\n * Uses binary search for efficiency.\n */\nexport function findClosestIndex(arr: number[], target: number): number {\n if (arr.length === 0) return 0;\n if (arr.length === 1) return 0;\n\n let left = 0;\n let right = arr.length - 1;\n\n while (left < right) {\n const mid = Math.floor((left + right) / 2);\n if (arr[mid] < target) {\n left = mid + 1;\n } else {\n right = mid;\n }\n }\n\n // Check if left-1 is closer\n if (left > 0 && Math.abs(arr[left - 1] - target) < Math.abs(arr[left] - target)) {\n return left - 1;\n }\n return left;\n}\n\n/**\n * Process user annotations to convert startX/endX to startIndex/endIndex\n * and compute area if boundaries are provided.\n */\nexport function processUserAnnotations(\n annotations: PeakAnnotation[],\n xArray: number[],\n yArray: number[]\n): PeakAnnotation[] {\n return annotations.map((ann) => {\n // If startX/endX are provided, convert to indices\n if (ann.startX !== undefined && ann.endX !== undefined) {\n const startIndex = findClosestIndex(xArray, ann.startX);\n const endIndex = findClosestIndex(xArray, ann.endX);\n const index = findClosestIndex(xArray, ann.x);\n\n // Calculate area if not provided\n const area = ann._computed?.area ?? calculatePeakArea(xArray, yArray, startIndex, endIndex);\n\n return {\n ...ann,\n _computed: {\n ...ann._computed,\n index,\n startIndex,\n endIndex,\n area,\n },\n };\n }\n return ann;\n });\n}\n\n/**\n * Collect peaks with boundary information from both auto-detected peaks and user-provided annotations.\n * User-provided annotations with startIndex/endIndex or startX/endX are included for boundary marker rendering.\n */\nexport function collectPeaksWithBoundaryData(\n allDetectedPeaks: { peaks: PeakAnnotation[]; seriesIndex: number }[],\n annotations: PeakAnnotation[],\n processedSeries: { x: number[]; y: number[] }[]\n): PeakDataWithSeries[] {\n const peaksWithData: PeakDataWithSeries[] = [];\n\n // Add auto-detected peaks\n allDetectedPeaks.forEach(({ peaks, seriesIndex }) => {\n peaksWithData.push({\n peaks,\n seriesIndex,\n x: processedSeries[seriesIndex].x,\n y: processedSeries[seriesIndex].y,\n });\n });\n\n // Add user-provided annotations that have boundary info (_computed.startIndex and _computed.endIndex)\n // Note: annotations with startX/endX should already be processed to have _computed fields\n const annotationsWithBoundaries = annotations.filter(\n (ann) => ann._computed?.startIndex !== undefined && ann._computed?.endIndex !== undefined\n );\n if (annotationsWithBoundaries.length > 0 && processedSeries.length > 0) {\n peaksWithData.push({\n peaks: annotationsWithBoundaries,\n seriesIndex: 0, // User annotations apply to first series by default\n x: processedSeries[0].x,\n y: processedSeries[0].y,\n });\n }\n\n return peaksWithData;\n}\n\n/**\n * Build the extra content for Plotly hovertemplate from series metadata.\n * Displays all metadata fields as key: value pairs.\n */\nexport function buildHoverExtraContent(\n seriesName: string,\n metadata?: Record<string, unknown>\n): string {\n if (!metadata) return seriesName;\n\n const metaLines: string[] = [];\n for (const [key, value] of Object.entries(metadata)) {\n if (value !== undefined && value !== null && value !== \"\") {\n // Format the key as Title Case (e.g., \"sampleName\" -> \"Sample Name\")\n const formattedKey = key\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (s) => s.toUpperCase())\n .trim();\n metaLines.push(`${formattedKey}: ${String(value)}`);\n }\n }\n\n if (metaLines.length > 0) {\n return `${seriesName}<br>${metaLines.join(\"<br>\")}`;\n }\n return seriesName;\n}\n\n/**\n * Validate and sanitize series data.\n * - Ensures x and y arrays have the same length (truncates to shorter)\n * - Replaces NaN and Infinity values with 0\n */\nexport function validateSeriesData(\n x: number[],\n y: number[]\n): { x: number[]; y: number[] } {\n // Ensure arrays have same length\n const length = Math.min(x.length, y.length);\n const validX = x.slice(0, length);\n const validY = y.slice(0, length);\n\n // Sanitize NaN and Infinity values\n const sanitizedY = validY.map((val) => (Number.isFinite(val) ? val : 0));\n const sanitizedX = validX.map((val) => (Number.isFinite(val) ? val : 0));\n\n return { x: sanitizedX, y: sanitizedY };\n}\n\n/**\n * Apply baseline correction to signal data\n */\nexport function applyBaselineCorrection(\n y: number[],\n method: BaselineCorrectionMethod,\n windowSize: number = 50\n): number[] {\n if (method === \"none\" || y.length === 0) return y;\n\n if (method === \"linear\") {\n // Linear baseline from first to last point\n // Handle single-point case to avoid division by zero\n if (y.length === 1) {\n return [0]; // Single point baseline-corrected to zero\n }\n const slope = (y[y.length - 1] - y[0]) / (y.length - 1);\n return y.map((val, i) => val - (y[0] + slope * i));\n }\n\n if (method === \"rolling\") {\n // Rolling minimum baseline\n const baseline: number[] = [];\n const halfWindow = Math.floor(windowSize / 2);\n\n for (let i = 0; i < y.length; i++) {\n const start = Math.max(0, i - halfWindow);\n const end = Math.min(y.length, i + halfWindow + 1);\n const windowSlice = y.slice(start, end);\n baseline.push(Math.min(...windowSlice));\n }\n\n return y.map((val, i) => val - baseline[i]);\n }\n\n return y;\n}\n\n"],"names":["findClosestIndex","arr","target","left","right","mid","processUserAnnotations","annotations","xArray","yArray","ann","startIndex","endIndex","index","area","calculatePeakArea","collectPeaksWithBoundaryData","allDetectedPeaks","processedSeries","peaksWithData","peaks","seriesIndex","annotationsWithBoundaries","validateSeriesData","x","y","length","validX","sanitizedY","val","applyBaselineCorrection","method","windowSize","slope","baseline","halfWindow","start","end","windowSlice","i"],"mappings":"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"}
@@ -1,90 +1,79 @@
1
- import { calculatePeakArea as a } from "./peakDetection.js";
2
- function s(t, i) {
1
+ import { calculatePeakArea as h } from "./peakDetection.js";
2
+ function c(t, o) {
3
3
  if (t.length === 0 || t.length === 1) return 0;
4
4
  let e = 0, n = t.length - 1;
5
5
  for (; e < n; ) {
6
- const o = Math.floor((e + n) / 2);
7
- t[o] < i ? e = o + 1 : n = o;
6
+ const l = Math.floor((e + n) / 2);
7
+ t[l] < o ? e = l + 1 : n = l;
8
8
  }
9
- return e > 0 && Math.abs(t[e - 1] - i) < Math.abs(t[e] - i) ? e - 1 : e;
9
+ return e > 0 && Math.abs(t[e - 1] - o) < Math.abs(t[e] - o) ? e - 1 : e;
10
10
  }
11
- function f(t, i, e) {
11
+ function d(t, o, e) {
12
12
  return t.map((n) => {
13
13
  if (n.startX !== void 0 && n.endX !== void 0) {
14
- const o = s(i, n.startX), l = s(i, n.endX), r = s(i, n.x), c = n._computed?.area ?? a(i, e, o, l);
14
+ const l = c(o, n.startX), i = c(o, n.endX), s = c(o, n.x), a = n._computed?.area ?? h(o, e, l, i);
15
15
  return {
16
16
  ...n,
17
17
  _computed: {
18
18
  ...n._computed,
19
- index: r,
20
- startIndex: o,
21
- endIndex: l,
22
- area: c
19
+ index: s,
20
+ startIndex: l,
21
+ endIndex: i,
22
+ area: a
23
23
  }
24
24
  };
25
25
  }
26
26
  return n;
27
27
  });
28
28
  }
29
- function d(t, i, e) {
29
+ function f(t, o, e) {
30
30
  const n = [];
31
- t.forEach(({ peaks: l, seriesIndex: r }) => {
31
+ t.forEach(({ peaks: i, seriesIndex: s }) => {
32
32
  n.push({
33
- peaks: l,
34
- seriesIndex: r,
35
- x: e[r].x,
36
- y: e[r].y
33
+ peaks: i,
34
+ seriesIndex: s,
35
+ x: e[s].x,
36
+ y: e[s].y
37
37
  });
38
38
  });
39
- const o = i.filter(
40
- (l) => l._computed?.startIndex !== void 0 && l._computed?.endIndex !== void 0
39
+ const l = o.filter(
40
+ (i) => i._computed?.startIndex !== void 0 && i._computed?.endIndex !== void 0
41
41
  );
42
- return o.length > 0 && e.length > 0 && n.push({
43
- peaks: o,
42
+ return l.length > 0 && e.length > 0 && n.push({
43
+ peaks: l,
44
44
  seriesIndex: 0,
45
45
  // User annotations apply to first series by default
46
46
  x: e[0].x,
47
47
  y: e[0].y
48
48
  }), n;
49
49
  }
50
- function p(t, i) {
51
- if (!i) return t;
52
- const e = [];
53
- for (const [n, o] of Object.entries(i))
54
- if (o != null && o !== "") {
55
- const l = n.replace(/([A-Z])/g, " $1").replace(/^./, (r) => r.toUpperCase()).trim();
56
- e.push(`${l}: ${String(o)}`);
57
- }
58
- return e.length > 0 ? `${t}<br>${e.join("<br>")}` : t;
59
- }
60
- function g(t, i) {
61
- const e = Math.min(t.length, i.length), n = t.slice(0, e), l = i.slice(0, e).map((c) => Number.isFinite(c) ? c : 0);
62
- return { x: n.map((c) => Number.isFinite(c) ? c : 0), y: l };
50
+ function m(t, o) {
51
+ const e = Math.min(t.length, o.length), n = t.slice(0, e), i = o.slice(0, e).map((a) => Number.isFinite(a) ? a : 0);
52
+ return { x: n.map((a) => Number.isFinite(a) ? a : 0), y: i };
63
53
  }
64
- function m(t, i, e = 50) {
65
- if (i === "none" || t.length === 0) return t;
66
- if (i === "linear") {
54
+ function p(t, o, e = 50) {
55
+ if (o === "none" || t.length === 0) return t;
56
+ if (o === "linear") {
67
57
  if (t.length === 1)
68
58
  return [0];
69
59
  const n = (t[t.length - 1] - t[0]) / (t.length - 1);
70
- return t.map((o, l) => o - (t[0] + n * l));
60
+ return t.map((l, i) => l - (t[0] + n * i));
71
61
  }
72
- if (i === "rolling") {
73
- const n = [], o = Math.floor(e / 2);
74
- for (let l = 0; l < t.length; l++) {
75
- const r = Math.max(0, l - o), c = Math.min(t.length, l + o + 1), u = t.slice(r, c);
62
+ if (o === "rolling") {
63
+ const n = [], l = Math.floor(e / 2);
64
+ for (let i = 0; i < t.length; i++) {
65
+ const s = Math.max(0, i - l), a = Math.min(t.length, i + l + 1), u = t.slice(s, a);
76
66
  n.push(Math.min(...u));
77
67
  }
78
- return t.map((l, r) => l - n[r]);
68
+ return t.map((i, s) => i - n[s]);
79
69
  }
80
70
  return t;
81
71
  }
82
72
  export {
83
- m as applyBaselineCorrection,
84
- p as buildHoverExtraContent,
85
- d as collectPeaksWithBoundaryData,
86
- s as findClosestIndex,
87
- f as processUserAnnotations,
88
- g as validateSeriesData
73
+ p as applyBaselineCorrection,
74
+ f as collectPeaksWithBoundaryData,
75
+ c as findClosestIndex,
76
+ d as processUserAnnotations,
77
+ m as validateSeriesData
89
78
  };
90
79
  //# sourceMappingURL=dataProcessing.js.map