@tetrascience-npm/tetrascience-react-ui 0.7.0-beta.107.1 → 0.7.0-beta.108.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/ChromatogramChart/ChromatogramChart.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.js +221 -207
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.js +99 -36
- package/dist/components/charts/ChromatogramChart/annotations.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.js +12 -12
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/constants.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/constants.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/constants.js +11 -5
- package/dist/components/charts/ChromatogramChart/constants.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.js +49 -38
- package/dist/components/charts/ChromatogramChart/dataProcessing.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/plotBuilder.cjs +2 -0
- package/dist/components/charts/ChromatogramChart/plotBuilder.cjs.map +1 -0
- package/dist/components/charts/ChromatogramChart/plotBuilder.js +207 -0
- package/dist/components/charts/ChromatogramChart/plotBuilder.js.map +1 -0
- package/dist/components/charts/ChromatogramChart/regionOverlays.cjs +2 -0
- package/dist/components/charts/ChromatogramChart/regionOverlays.cjs.map +1 -0
- package/dist/components/charts/ChromatogramChart/regionOverlays.js +26 -0
- package/dist/components/charts/ChromatogramChart/regionOverlays.js.map +1 -0
- package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.cjs +2 -0
- package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.cjs.map +1 -0
- package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.js +40 -0
- package/dist/components/charts/StackedChromatogramChart/StackedChromatogramChart.js.map +1 -0
- package/dist/components/charts/StackedChromatogramChart/transforms.cjs +2 -0
- package/dist/components/charts/StackedChromatogramChart/transforms.cjs.map +1 -0
- package/dist/components/charts/StackedChromatogramChart/transforms.js +31 -0
- package/dist/components/charts/StackedChromatogramChart/transforms.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +141 -0
- package/dist/index.js +562 -558
- package/dist/index.js.map +1 -1
- package/dist/index.tailwind.css +1 -1
- package/package.json +1 -1
|
@@ -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 E=require("react/jsx-runtime"),_=require("plotly.js-dist"),r=require("react"),ie=require("../ChartTooltip/ChartTooltip.cjs"),B=require("./annotations.cjs"),D=require("./dataProcessing.cjs"),de=require("./peakDetection.cjs"),h=require("./plotBuilder.cjs"),fe=require("../../composed/EmptyState/EmptyState.cjs"),pe=require("../../../hooks/use-plotly-theme.cjs"),me=[],he=({series:n,width:y=900,height:g=500,title:$,xAxisTitle:v="Retention Time (min)",yAxisTitle:k="Signal (mAU)",annotations:C=me,xRange:H,yRange:T,showLegend:U=!0,showGridX:W=!0,showGridY:A=!0,showMarkers:x=!1,markerSize:F=4,showCrosshairs:I=!1,baselineCorrection:J="none",baselineWindowSize:K=50,peakDetectionOptions:f,showPeakAreas:R=!1,boundaryMarkers:Q="none",annotationOverlapThreshold:P=.4,showExportButton:V=!0,selectedPeakIds:q,onPeakClick:Y,onPeakHover:Z,selectionAppearance:p,annotationStyle:G="arrow",titleFontSize:O=20,titleTopMargin:X})=>{const m=f!==void 0,M=r.useRef(null),z=pe.usePlotlyTheme(),{bindTooltip:w,tooltipElement:ae}=ie.useChartTooltip({xLabel:v,yLabel:k}),N=r.useRef(Y),S=r.useRef(Z);N.current=Y,S.current=Z;const j=r.useRef(null),ee=r.useRef([]),u=r.useMemo(()=>n.map(e=>{const t=D.validateSeriesData(e.x,e.y);return{...e,x:t.x,y:D.applyBaselineCorrection(t.y,J,K)}}),[n,J,K]),l=r.useMemo(()=>{if(C.length===0||u.length===0)return C;const{x:e,y:t}=u[0];return D.processUserAnnotations(C,e,t)},[C,u]),s=r.useMemo(()=>{const e=[];return m&&f&&u.forEach((t,o)=>{const a=de.detectPeaks(t.x,t.y,f);a.length>0&&e.push({peaks:a,seriesIndex:o})}),e},[u,m,f]),te=p?.selected?.borderColor,oe=p?.selected?.backgroundColor,re=p?.selected?.bold,ne=p?.unselected?.opacity,ce=p?.hoverLineWidthMultiplier,b=r.useMemo(()=>B.resolveSelectionAppearance({selected:{borderColor:te,backgroundColor:oe,bold:re},unselected:{opacity:ne},hoverLineWidthMultiplier:ce}),[te,oe,re,ne,ce]),ue=r.useMemo(()=>{const e=[];return l.forEach((t,o)=>{e.push({peak:{...t,id:t.id??`user-ann-${o}`},seriesIndex:0,seriesName:n[0]?.name??"",isAutoDetected:!1})}),s.forEach(({peaks:t,seriesIndex:o})=>{t.forEach((a,i)=>{e.push({peak:{...a,id:`peak-${o}-${i}`},seriesIndex:o,seriesName:n[o]?.name??`Series ${o+1}`,isAutoDetected:!0})})}),e},[l,s,n]),L=r.useMemo(()=>{const e=(q?.length??0)>0,t={selectedPeakIds:q??[],anySelected:e,appearance:b,annotationStyle:G},o=[];l.forEach((c,d)=>{o.push({peak:{...c,id:c.id??`user-ann-${d}`},seriesIndex:-1})}),R&&m&&s.forEach(({peaks:c,seriesIndex:d})=>{c.forEach((le,se)=>{o.push({peak:{...le,id:`peak-${d}-${se}`},seriesIndex:d})})});const a=B.groupOverlappingPeaks(o,P),i=[];for(const c of a)i.push(...B.createGroupAnnotations(c,t));return i},[l,s,R,m,P,q,b,G]);return ee.current=L,r.useEffect(()=>{const e=M.current;if(!e||n.length===0)return;const t=h.buildTraceData({processedSeries:u,processedAnnotations:l,allDetectedPeaks:s,allPeaksForInteraction:ue,showMarkers:x,markerSize:F,xAxisTitle:v,yAxisTitle:k,boundaryMarkers:Q}),o=h.buildLayout({title:$,titleFontSize:O,titleTopMargin:X,width:y,height:g,xAxisTitle:v,yAxisTitle:k,xRange:H,yRange:T,showLegend:U,seriesCount:n.length,showGridX:W,showGridY:A,showCrosshairs:I,theme:z,peakAnnotations:ee.current}),a=h.buildConfig({showExportButton:V,width:y,height:g});return _.newPlot(e,t,o,a),w(e),e.on("plotly_click",i=>{if(!N.current)return;const c=i.points.find(d=>d.customdata!=null);c&&N.current(c.customdata)}),e.on("plotly_hover",h.createHoverHandler(e,u.length,j,S,b.hoverLineWidthMultiplier)),e.on("plotly_unhover",h.createUnhoverHandler(e,j,S)),()=>{j.current=null,e&&_.purge(e)}},[u,s,ue,n.length,y,g,$,O,X,v,k,l,H,T,U,W,A,x,F,I,m,f,R,Q,P,V,z,w,b]),r.useEffect(()=>{const e=M.current;e&&e._fullLayout&&_.relayout(e,{annotations:L})},[L]),n.length===0?E.jsx("div",{className:"chromatogram-chart-container relative flex items-center justify-center",style:{width:y,height:g},children:E.jsx(fe.EmptyState,{variant:"no-data",title:"No chromatogram data",description:"There is no signal data to display yet."})}):E.jsxs("div",{className:"chromatogram-chart-container relative",children:[E.jsx("div",{ref:M,style:{width:"100%",height:"100%"}}),ae]})};exports.ChromatogramChart=he;
|
|
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\";\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
|
+
{"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 { useChartTooltip } from \"../ChartTooltip\";\n\nimport {\n groupOverlappingPeaks,\n createGroupAnnotations,\n resolveSelectionAppearance,\n} from \"./annotations\";\nimport {\n validateSeriesData,\n applyBaselineCorrection,\n processUserAnnotations,\n} from \"./dataProcessing\";\nimport { detectPeaks } from \"./peakDetection\";\nimport {\n buildTraceData,\n buildLayout,\n buildConfig,\n createHoverHandler,\n createUnhoverHandler,\n} from \"./plotBuilder\";\n\nimport type {\n ChromatogramSeries,\n PeakAnnotation,\n PeakSelectEvent,\n PeakSelectionAppearance,\n BaselineCorrectionMethod,\n BoundaryMarkerStyle,\n BoundaryMarkerType,\n PeakDetectionOptions,\n ChromatogramChartProps,\n PeakWithMeta,\n} from \"./types\";\n\nimport { EmptyState } from \"@/components/composed/EmptyState\";\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\n// Re-export types for external use\nexport type {\n ChromatogramSeries,\n PeakAnnotation,\n PeakSelectEvent,\n PeakSelectionAppearance,\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 selectedPeakIds,\n onPeakClick,\n onPeakHover,\n selectionAppearance,\n annotationStyle = \"arrow\",\n titleFontSize = 20,\n titleTopMargin,\n}) => {\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 // Stable refs for callbacks — avoids including them in effect dep arrays\n // (consumers often pass arrow functions that change identity every render).\n const onPeakClickRef = useRef(onPeakClick);\n const onPeakHoverRef = useRef(onPeakHover);\n onPeakClickRef.current = onPeakClick;\n onPeakHoverRef.current = onPeakHover;\n\n // Tracks the series index whose line is currently thickened on hover.\n const thickenedSeriesRef = useRef<number | null>(null);\n\n // Holds the latest peak Plotly annotations so that closures in effects always\n // read the latest selection-styled annotations.\n const peakAnnotationsRef = useRef<Partial<Plotly.Annotations>[]>([]);\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 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 // Normalize the selection appearance into primitive fields up front so the\n // memo below depends on stable values rather than the (possibly unstable)\n // selectionAppearance object reference. This keeps the dependency array\n // exhaustive-deps clean without requiring callers to memoize the prop.\n const selectedBorderColor = selectionAppearance?.selected?.borderColor;\n const selectedBackgroundColor = selectionAppearance?.selected?.backgroundColor;\n const selectedBold = selectionAppearance?.selected?.bold;\n const unselectedOpacity = selectionAppearance?.unselected?.opacity;\n const hoverLineWidthMultiplier = selectionAppearance?.hoverLineWidthMultiplier;\n\n // Resolve selection appearance defaults once (stable as long as the\n // individual fields above don't change).\n const resolvedAppearance = useMemo(\n () =>\n resolveSelectionAppearance({\n selected: {\n borderColor: selectedBorderColor,\n backgroundColor: selectedBackgroundColor,\n bold: selectedBold,\n },\n unselected: { opacity: unselectedOpacity },\n hoverLineWidthMultiplier,\n }),\n [\n selectedBorderColor,\n selectedBackgroundColor,\n selectedBold,\n unselectedOpacity,\n hoverLineWidthMultiplier,\n ]\n );\n\n // All peaks that can be interacted with (clicked / hovered / selected),\n // each with a stable ID and the metadata needed for PeakSelectEvent.\n const allPeaksForInteraction = useMemo(() => {\n const result: Array<{\n peak: PeakAnnotation & { id: string };\n seriesIndex: number;\n seriesName: string;\n isAutoDetected: boolean;\n }> = [];\n\n processedAnnotations.forEach((ann, i) => {\n result.push({\n peak: { ...ann, id: ann.id ?? `user-ann-${i}` },\n seriesIndex: 0,\n seriesName: series[0]?.name ?? \"\",\n isAutoDetected: false,\n });\n });\n\n allDetectedPeaks.forEach(({ peaks, seriesIndex }) => {\n peaks.forEach((peak, peakIndex) => {\n result.push({\n peak: { ...peak, id: `peak-${seriesIndex}-${peakIndex}` },\n seriesIndex,\n seriesName: series[seriesIndex]?.name ?? `Series ${seriesIndex + 1}`,\n isAutoDetected: true,\n });\n });\n });\n\n return result;\n }, [processedAnnotations, allDetectedPeaks, series]);\n\n // Build Plotly annotation objects for all peaks, applying selection styling.\n // This memo re-runs when selectedPeakIds or resolvedAppearance changes so the\n // selection effect can call Plotly.relayout with updated annotations without\n // triggering a full chart rebuild.\n const peakAnnotations = useMemo(() => {\n const anySelected = (selectedPeakIds?.length ?? 0) > 0;\n const options = {\n selectedPeakIds: selectedPeakIds ?? [],\n anySelected,\n appearance: resolvedAppearance,\n annotationStyle,\n };\n\n const allPeaksWithMeta: PeakWithMeta[] = [];\n\n processedAnnotations.forEach((ann, i) => {\n allPeaksWithMeta.push({\n peak: { ...ann, id: ann.id ?? `user-ann-${i}` },\n seriesIndex: -1,\n });\n });\n\n if (showPeakAreas && enablePeakDetection) {\n allDetectedPeaks.forEach(({ peaks, seriesIndex }) => {\n peaks.forEach((peak, peakIndex) => {\n allPeaksWithMeta.push({\n peak: { ...peak, id: `peak-${seriesIndex}-${peakIndex}` },\n seriesIndex,\n });\n });\n });\n }\n\n const groups = groupOverlappingPeaks(allPeaksWithMeta, annotationOverlapThreshold);\n const result: Partial<Plotly.Annotations>[] = [];\n for (const group of groups) {\n result.push(...createGroupAnnotations(group, options));\n }\n return result;\n }, [\n processedAnnotations,\n allDetectedPeaks,\n showPeakAreas,\n enablePeakDetection,\n annotationOverlapThreshold,\n selectedPeakIds,\n resolvedAppearance,\n annotationStyle,\n ]);\n\n // Keep the ref in sync every render so that closures in effects always read\n // the latest selection-styled annotations.\n peakAnnotationsRef.current = peakAnnotations;\n\n // ── Main chart effect ──────────────────────────────────────────────────────\n // Rebuilds the full chart when structural props change (data, size, axes, …).\n // selectedPeakIds and selectionAppearance are intentionally excluded from\n // deps — selection changes are handled by the lightweight selection effect\n // below via Plotly.relayout, which preserves the user's current zoom/pan.\n useEffect(() => {\n const currentRef = plotRef.current;\n if (!currentRef || series.length === 0) return;\n\n // Build trace data (line traces + boundary markers + region overlays +\n // the invisible hit-area trace that carries peak customdata for\n // click/hover interaction).\n const plotData = buildTraceData({\n processedSeries,\n processedAnnotations,\n allDetectedPeaks,\n allPeaksForInteraction,\n showMarkers,\n markerSize,\n xAxisTitle,\n yAxisTitle,\n boundaryMarkers,\n });\n\n const layout = buildLayout({\n title,\n titleFontSize,\n titleTopMargin,\n width,\n height,\n xAxisTitle,\n yAxisTitle,\n xRange,\n yRange,\n showLegend,\n seriesCount: series.length,\n showGridX,\n showGridY,\n showCrosshairs,\n theme,\n peakAnnotations: peakAnnotationsRef.current,\n });\n\n const config = buildConfig({ showExportButton, width, height });\n\n Plotly.newPlot(currentRef, plotData, layout, config);\n bindTooltip(currentRef);\n\n // ── Event: peak click ──────────────────────────────────────────────────\n (currentRef as unknown as Plotly.PlotlyHTMLElement).on(\n \"plotly_click\",\n (eventData: Plotly.PlotMouseEvent) => {\n if (!onPeakClickRef.current) return;\n const peakPoint = eventData.points.find((p) => p.customdata != null);\n if (!peakPoint) return;\n onPeakClickRef.current(peakPoint.customdata as unknown as PeakSelectEvent);\n }\n );\n\n (currentRef as unknown as Plotly.PlotlyHTMLElement).on(\n \"plotly_hover\",\n createHoverHandler(currentRef, processedSeries.length, thickenedSeriesRef, onPeakHoverRef, resolvedAppearance.hoverLineWidthMultiplier)\n );\n\n (currentRef as unknown as Plotly.PlotlyHTMLElement).on(\n \"plotly_unhover\",\n createUnhoverHandler(currentRef, thickenedSeriesRef, onPeakHoverRef)\n );\n\n return () => {\n thickenedSeriesRef.current = null;\n if (currentRef) Plotly.purge(currentRef);\n };\n }, [\n processedSeries, allDetectedPeaks, allPeaksForInteraction, series.length,\n width, height, title, titleFontSize, titleTopMargin, xAxisTitle, yAxisTitle,\n processedAnnotations, xRange, yRange, showLegend, showGridX, showGridY,\n showMarkers, markerSize, showCrosshairs, enablePeakDetection, peakDetectionOptions,\n showPeakAreas, boundaryMarkers, annotationOverlapThreshold, showExportButton,\n theme, bindTooltip,\n // resolvedAppearance included so hover multiplier stays in sync with the\n // event handler closure without it being in a ref itself.\n resolvedAppearance,\n ]);\n\n // ── Selection update effect ────────────────────────────────────────────────\n // Runs when selectedPeakIds / selectionAppearance change (peakAnnotations\n // recomputes). Uses Plotly.relayout so the user's zoom/pan state is preserved.\n useEffect(() => {\n const el = plotRef.current;\n if (!el) return;\n // Guard: skip if the chart hasn't been initialized by the main effect yet.\n if (!(el as { _fullLayout?: unknown })._fullLayout) return;\n\n Plotly.relayout(el, {\n annotations: peakAnnotations,\n } as unknown as Partial<Plotly.Layout>);\n }, [peakAnnotations]);\n\n // No data: render an explicit empty state instead of an uninitialized\n // (blank) Plotly container, so the chart reads as \"no data yet\" rather\n // than looking broken while data is still loading.\n if (series.length === 0) {\n return (\n <div\n className=\"chromatogram-chart-container relative flex items-center justify-center\"\n style={{ width, height }}\n >\n <EmptyState\n variant=\"no-data\"\n title=\"No chromatogram data\"\n description=\"There is no signal data to display yet.\"\n />\n </div>\n );\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"],"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","selectedPeakIds","onPeakClick","onPeakHover","selectionAppearance","annotationStyle","titleFontSize","titleTopMargin","enablePeakDetection","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","onPeakClickRef","onPeakHoverRef","thickenedSeriesRef","peakAnnotationsRef","processedSeries","useMemo","s","validated","validateSeriesData","applyBaselineCorrection","processedAnnotations","x","y","processUserAnnotations","allDetectedPeaks","peaks","index","detected","detectPeaks","selectedBorderColor","selectedBackgroundColor","selectedBold","unselectedOpacity","hoverLineWidthMultiplier","resolvedAppearance","resolveSelectionAppearance","allPeaksForInteraction","result","ann","i","seriesIndex","peak","peakIndex","peakAnnotations","anySelected","options","allPeaksWithMeta","groups","groupOverlappingPeaks","group","createGroupAnnotations","useEffect","currentRef","plotData","buildTraceData","layout","buildLayout","config","buildConfig","Plotly","eventData","peakPoint","p","createHoverHandler","createUnhoverHandler","el","jsx","EmptyState","jsxs"],"mappings":"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"}
|
|
@@ -1,227 +1,241 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { useRef as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
series: a,
|
|
1
|
+
import { jsx as j, jsxs as st } from "react/jsx-runtime";
|
|
2
|
+
import B from "plotly.js-dist";
|
|
3
|
+
import { useRef as h, useMemo as f, useEffect as ct } from "react";
|
|
4
|
+
import { useChartTooltip as dt } from "../ChartTooltip/ChartTooltip.js";
|
|
5
|
+
import { resolveSelectionAppearance as ft, groupOverlappingPeaks as it, createGroupAnnotations as pt } from "./annotations.js";
|
|
6
|
+
import { validateSeriesData as mt, applyBaselineCorrection as ht, processUserAnnotations as yt } from "./dataProcessing.js";
|
|
7
|
+
import { detectPeaks as gt } from "./peakDetection.js";
|
|
8
|
+
import { buildTraceData as vt, buildLayout as kt, buildConfig as bt, createHoverHandler as Ct, createUnhoverHandler as Et } from "./plotBuilder.js";
|
|
9
|
+
import { EmptyState as Nt } from "../../composed/EmptyState/EmptyState.js";
|
|
10
|
+
import { usePlotlyTheme as Pt } from "../../../hooks/use-plotly-theme.js";
|
|
11
|
+
const $t = [], Wt = ({
|
|
12
|
+
series: o,
|
|
14
13
|
width: y = 900,
|
|
15
|
-
height:
|
|
16
|
-
title:
|
|
17
|
-
xAxisTitle:
|
|
18
|
-
yAxisTitle:
|
|
19
|
-
annotations:
|
|
20
|
-
xRange:
|
|
21
|
-
yRange:
|
|
22
|
-
showLegend:
|
|
23
|
-
showGridX:
|
|
24
|
-
showGridY:
|
|
25
|
-
showMarkers:
|
|
26
|
-
markerSize:
|
|
27
|
-
showCrosshairs:
|
|
28
|
-
baselineCorrection:
|
|
29
|
-
baselineWindowSize:
|
|
30
|
-
peakDetectionOptions:
|
|
31
|
-
showPeakAreas:
|
|
32
|
-
boundaryMarkers:
|
|
33
|
-
annotationOverlapThreshold:
|
|
34
|
-
showExportButton:
|
|
14
|
+
height: g = 500,
|
|
15
|
+
title: D,
|
|
16
|
+
xAxisTitle: v = "Retention Time (min)",
|
|
17
|
+
yAxisTitle: k = "Signal (mAU)",
|
|
18
|
+
annotations: b = $t,
|
|
19
|
+
xRange: H,
|
|
20
|
+
yRange: M,
|
|
21
|
+
showLegend: U = !0,
|
|
22
|
+
showGridX: W = !0,
|
|
23
|
+
showGridY: A = !0,
|
|
24
|
+
showMarkers: q = !1,
|
|
25
|
+
markerSize: F = 4,
|
|
26
|
+
showCrosshairs: I = !1,
|
|
27
|
+
baselineCorrection: J = "none",
|
|
28
|
+
baselineWindowSize: K = 50,
|
|
29
|
+
peakDetectionOptions: i,
|
|
30
|
+
showPeakAreas: E = !1,
|
|
31
|
+
boundaryMarkers: Q = "none",
|
|
32
|
+
annotationOverlapThreshold: N = 0.4,
|
|
33
|
+
showExportButton: T = !0,
|
|
34
|
+
selectedPeakIds: P,
|
|
35
|
+
onPeakClick: V,
|
|
36
|
+
onPeakHover: Y,
|
|
37
|
+
selectionAppearance: p,
|
|
38
|
+
annotationStyle: Z = "arrow",
|
|
39
|
+
titleFontSize: G = 20,
|
|
40
|
+
titleTopMargin: X
|
|
35
41
|
}) => {
|
|
36
|
-
const
|
|
37
|
-
xLabel:
|
|
38
|
-
yLabel:
|
|
39
|
-
}),
|
|
40
|
-
|
|
42
|
+
const m = i !== void 0, $ = h(null), x = Pt(), { bindTooltip: O, tooltipElement: lt } = dt({
|
|
43
|
+
xLabel: v,
|
|
44
|
+
yLabel: k
|
|
45
|
+
}), L = h(V), R = h(Y);
|
|
46
|
+
L.current = V, R.current = Y;
|
|
47
|
+
const S = h(null), z = h([]), c = f(() => o.map((t) => {
|
|
48
|
+
const e = mt(t.x, t.y);
|
|
41
49
|
return {
|
|
42
|
-
...
|
|
43
|
-
x:
|
|
44
|
-
y:
|
|
50
|
+
...t,
|
|
51
|
+
x: e.x,
|
|
52
|
+
y: ht(e.y, J, K)
|
|
45
53
|
};
|
|
46
|
-
}), [
|
|
47
|
-
if (
|
|
48
|
-
return
|
|
49
|
-
const { x:
|
|
50
|
-
return
|
|
51
|
-
}, [
|
|
52
|
-
const
|
|
53
|
-
return
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
}),
|
|
57
|
-
}, [
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
54
|
+
}), [o, J, K]), a = f(() => {
|
|
55
|
+
if (b.length === 0 || c.length === 0)
|
|
56
|
+
return b;
|
|
57
|
+
const { x: t, y: e } = c[0];
|
|
58
|
+
return yt(b, t, e);
|
|
59
|
+
}, [b, c]), u = f(() => {
|
|
60
|
+
const t = [];
|
|
61
|
+
return m && i && c.forEach((e, r) => {
|
|
62
|
+
const l = gt(e.x, e.y, i);
|
|
63
|
+
l.length > 0 && t.push({ peaks: l, seriesIndex: r });
|
|
64
|
+
}), t;
|
|
65
|
+
}, [c, m, i]), w = p?.selected?.borderColor, tt = p?.selected?.backgroundColor, et = p?.selected?.bold, rt = p?.unselected?.opacity, ot = p?.hoverLineWidthMultiplier, C = f(
|
|
66
|
+
() => ft({
|
|
67
|
+
selected: {
|
|
68
|
+
borderColor: w,
|
|
69
|
+
backgroundColor: tt,
|
|
70
|
+
bold: et
|
|
71
|
+
},
|
|
72
|
+
unselected: { opacity: rt },
|
|
73
|
+
hoverLineWidthMultiplier: ot
|
|
74
|
+
}),
|
|
75
|
+
[
|
|
76
|
+
w,
|
|
77
|
+
tt,
|
|
78
|
+
et,
|
|
79
|
+
rt,
|
|
80
|
+
ot
|
|
81
|
+
]
|
|
82
|
+
), nt = f(() => {
|
|
83
|
+
const t = [];
|
|
84
|
+
return a.forEach((e, r) => {
|
|
85
|
+
t.push({
|
|
86
|
+
peak: { ...e, id: e.id ?? `user-ann-${r}` },
|
|
87
|
+
seriesIndex: 0,
|
|
88
|
+
seriesName: o[0]?.name ?? "",
|
|
89
|
+
isAutoDetected: !1
|
|
90
|
+
});
|
|
91
|
+
}), u.forEach(({ peaks: e, seriesIndex: r }) => {
|
|
92
|
+
e.forEach((l, s) => {
|
|
93
|
+
t.push({
|
|
94
|
+
peak: { ...l, id: `peak-${r}-${s}` },
|
|
95
|
+
seriesIndex: r,
|
|
96
|
+
seriesName: o[r]?.name ?? `Series ${r + 1}`,
|
|
97
|
+
isAutoDetected: !0
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}), t;
|
|
101
|
+
}, [a, u, o]), _ = f(() => {
|
|
102
|
+
const t = (P?.length ?? 0) > 0, e = {
|
|
103
|
+
selectedPeakIds: P ?? [],
|
|
104
|
+
anySelected: t,
|
|
105
|
+
appearance: C,
|
|
106
|
+
annotationStyle: Z
|
|
107
|
+
}, r = [];
|
|
108
|
+
a.forEach((n, d) => {
|
|
109
|
+
r.push({
|
|
110
|
+
peak: { ...n, id: n.id ?? `user-ann-${d}` },
|
|
111
|
+
seriesIndex: -1
|
|
112
|
+
});
|
|
113
|
+
}), E && m && u.forEach(({ peaks: n, seriesIndex: d }) => {
|
|
114
|
+
n.forEach((at, ut) => {
|
|
115
|
+
r.push({
|
|
116
|
+
peak: { ...at, id: `peak-${d}-${ut}` },
|
|
117
|
+
seriesIndex: d
|
|
118
|
+
});
|
|
92
119
|
});
|
|
93
120
|
});
|
|
94
|
-
const
|
|
95
|
-
for (const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
121
|
+
const l = it(r, N), s = [];
|
|
122
|
+
for (const n of l)
|
|
123
|
+
s.push(...pt(n, e));
|
|
124
|
+
return s;
|
|
125
|
+
}, [
|
|
126
|
+
a,
|
|
127
|
+
u,
|
|
128
|
+
E,
|
|
129
|
+
m,
|
|
130
|
+
N,
|
|
131
|
+
P,
|
|
132
|
+
C,
|
|
133
|
+
Z
|
|
134
|
+
]);
|
|
135
|
+
return z.current = _, ct(() => {
|
|
136
|
+
const t = $.current;
|
|
137
|
+
if (!t || o.length === 0) return;
|
|
138
|
+
const e = vt({
|
|
139
|
+
processedSeries: c,
|
|
140
|
+
processedAnnotations: a,
|
|
141
|
+
allDetectedPeaks: u,
|
|
142
|
+
allPeaksForInteraction: nt,
|
|
143
|
+
showMarkers: q,
|
|
144
|
+
markerSize: F,
|
|
145
|
+
xAxisTitle: v,
|
|
146
|
+
yAxisTitle: k,
|
|
147
|
+
boundaryMarkers: Q
|
|
148
|
+
}), r = kt({
|
|
149
|
+
title: D,
|
|
150
|
+
titleFontSize: G,
|
|
151
|
+
titleTopMargin: X,
|
|
106
152
|
width: y,
|
|
107
|
-
height:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
showgrid: N,
|
|
127
|
-
gridcolor: o.gridColor,
|
|
128
|
-
linecolor: o.lineColor,
|
|
129
|
-
linewidth: 1,
|
|
130
|
-
range: x,
|
|
131
|
-
autorange: !x,
|
|
132
|
-
zeroline: !1,
|
|
133
|
-
tickfont: { size: 12, color: o.textColor, family: "Inter, sans-serif" },
|
|
134
|
-
showspikes: p,
|
|
135
|
-
spikemode: "across",
|
|
136
|
-
spikesnap: "cursor",
|
|
137
|
-
spikecolor: o.spikeColor,
|
|
138
|
-
spikethickness: 1,
|
|
139
|
-
spikedash: "dot"
|
|
140
|
-
},
|
|
141
|
-
yaxis: {
|
|
142
|
-
title: {
|
|
143
|
-
text: I,
|
|
144
|
-
font: { size: 14, color: o.textSecondary, family: "Inter, sans-serif" },
|
|
145
|
-
standoff: 10
|
|
146
|
-
},
|
|
147
|
-
showgrid: R,
|
|
148
|
-
gridcolor: o.gridColor,
|
|
149
|
-
linecolor: o.lineColor,
|
|
150
|
-
linewidth: 1,
|
|
151
|
-
range: T,
|
|
152
|
-
autorange: !T,
|
|
153
|
-
zeroline: !1,
|
|
154
|
-
tickfont: { size: 12, color: o.textColor, family: "Inter, sans-serif" },
|
|
155
|
-
showspikes: p,
|
|
156
|
-
spikemode: "across",
|
|
157
|
-
spikesnap: "cursor",
|
|
158
|
-
spikecolor: o.spikeColor,
|
|
159
|
-
spikethickness: 1,
|
|
160
|
-
spikedash: "dot"
|
|
161
|
-
},
|
|
162
|
-
legend: {
|
|
163
|
-
x: 0.5,
|
|
164
|
-
y: -0.15,
|
|
165
|
-
xanchor: "center",
|
|
166
|
-
yanchor: "top",
|
|
167
|
-
orientation: "h",
|
|
168
|
-
font: { size: 12, color: o.textColor, family: "Inter, sans-serif" }
|
|
169
|
-
},
|
|
170
|
-
showlegend: M && a.length > 1,
|
|
171
|
-
annotations: D
|
|
172
|
-
}, F = {
|
|
173
|
-
responsive: !0,
|
|
174
|
-
displayModeBar: !0,
|
|
175
|
-
displaylogo: !1,
|
|
176
|
-
modeBarButtonsToRemove: [
|
|
177
|
-
"lasso2d",
|
|
178
|
-
"select2d",
|
|
179
|
-
...C ? [] : ["toImage"]
|
|
180
|
-
],
|
|
181
|
-
...C && {
|
|
182
|
-
toImageButtonOptions: {
|
|
183
|
-
format: "png",
|
|
184
|
-
filename: "chromatogram",
|
|
185
|
-
width: y,
|
|
186
|
-
height: h
|
|
187
|
-
}
|
|
153
|
+
height: g,
|
|
154
|
+
xAxisTitle: v,
|
|
155
|
+
yAxisTitle: k,
|
|
156
|
+
xRange: H,
|
|
157
|
+
yRange: M,
|
|
158
|
+
showLegend: U,
|
|
159
|
+
seriesCount: o.length,
|
|
160
|
+
showGridX: W,
|
|
161
|
+
showGridY: A,
|
|
162
|
+
showCrosshairs: I,
|
|
163
|
+
theme: x,
|
|
164
|
+
peakAnnotations: z.current
|
|
165
|
+
}), l = bt({ showExportButton: T, width: y, height: g });
|
|
166
|
+
return B.newPlot(t, e, r, l), O(t), t.on(
|
|
167
|
+
"plotly_click",
|
|
168
|
+
(s) => {
|
|
169
|
+
if (!L.current) return;
|
|
170
|
+
const n = s.points.find((d) => d.customdata != null);
|
|
171
|
+
n && L.current(n.customdata);
|
|
188
172
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
173
|
+
), t.on(
|
|
174
|
+
"plotly_hover",
|
|
175
|
+
Ct(t, c.length, S, R, C.hoverLineWidthMultiplier)
|
|
176
|
+
), t.on(
|
|
177
|
+
"plotly_unhover",
|
|
178
|
+
Et(t, S, R)
|
|
179
|
+
), () => {
|
|
180
|
+
S.current = null, t && B.purge(t);
|
|
192
181
|
};
|
|
193
182
|
}, [
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
183
|
+
c,
|
|
184
|
+
u,
|
|
185
|
+
nt,
|
|
186
|
+
o.length,
|
|
197
187
|
y,
|
|
198
|
-
|
|
199
|
-
|
|
188
|
+
g,
|
|
189
|
+
D,
|
|
190
|
+
G,
|
|
191
|
+
X,
|
|
192
|
+
v,
|
|
200
193
|
k,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
x,
|
|
204
|
-
T,
|
|
194
|
+
a,
|
|
195
|
+
H,
|
|
205
196
|
M,
|
|
197
|
+
U,
|
|
198
|
+
W,
|
|
199
|
+
A,
|
|
200
|
+
q,
|
|
201
|
+
F,
|
|
202
|
+
I,
|
|
203
|
+
m,
|
|
204
|
+
i,
|
|
205
|
+
E,
|
|
206
|
+
Q,
|
|
206
207
|
N,
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
z,
|
|
210
|
-
p,
|
|
211
|
-
d,
|
|
212
|
-
l,
|
|
213
|
-
G,
|
|
208
|
+
T,
|
|
209
|
+
x,
|
|
214
210
|
O,
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
211
|
+
// resolvedAppearance included so hover multiplier stays in sync with the
|
|
212
|
+
// event handler closure without it being in a ref itself.
|
|
213
|
+
C
|
|
214
|
+
]), ct(() => {
|
|
215
|
+
const t = $.current;
|
|
216
|
+
t && t._fullLayout && B.relayout(t, {
|
|
217
|
+
annotations: _
|
|
218
|
+
});
|
|
219
|
+
}, [_]), o.length === 0 ? /* @__PURE__ */ j(
|
|
220
|
+
"div",
|
|
221
|
+
{
|
|
222
|
+
className: "chromatogram-chart-container relative flex items-center justify-center",
|
|
223
|
+
style: { width: y, height: g },
|
|
224
|
+
children: /* @__PURE__ */ j(
|
|
225
|
+
Nt,
|
|
226
|
+
{
|
|
227
|
+
variant: "no-data",
|
|
228
|
+
title: "No chromatogram data",
|
|
229
|
+
description: "There is no signal data to display yet."
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
) : /* @__PURE__ */ st("div", { className: "chromatogram-chart-container relative", children: [
|
|
234
|
+
/* @__PURE__ */ j("div", { ref: $, style: { width: "100%", height: "100%" } }),
|
|
235
|
+
lt
|
|
222
236
|
] });
|
|
223
237
|
};
|
|
224
238
|
export {
|
|
225
|
-
|
|
239
|
+
Wt as ChromatogramChart
|
|
226
240
|
};
|
|
227
241
|
//# sourceMappingURL=ChromatogramChart.js.map
|