@tetrascience-npm/tetrascience-react-ui 0.6.0-beta.95.1 → 0.6.0-beta.97.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/charts/AreaGraph/AreaGraph.cjs +1 -1
- package/dist/components/charts/AreaGraph/AreaGraph.cjs.map +1 -1
- package/dist/components/charts/AreaGraph/AreaGraph.js +78 -67
- package/dist/components/charts/AreaGraph/AreaGraph.js.map +1 -1
- package/dist/components/charts/BarGraph/BarGraph.cjs +1 -1
- package/dist/components/charts/BarGraph/BarGraph.cjs.map +1 -1
- package/dist/components/charts/BarGraph/BarGraph.js +83 -73
- package/dist/components/charts/BarGraph/BarGraph.js.map +1 -1
- package/dist/components/charts/LineGraph/LineGraph.cjs +1 -1
- package/dist/components/charts/LineGraph/LineGraph.cjs.map +1 -1
- package/dist/components/charts/LineGraph/LineGraph.js +89 -80
- package/dist/components/charts/LineGraph/LineGraph.js.map +1 -1
- package/dist/components/charts/PieChart/PieChart.cjs +1 -1
- package/dist/components/charts/PieChart/PieChart.cjs.map +1 -1
- package/dist/components/charts/PieChart/PieChart.js +1 -1
- package/dist/components/charts/PieChart/PieChart.js.map +1 -1
- package/dist/index.d.ts +21 -0
- 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 V=require("react/jsx-runtime"),Y=require("plotly.js-dist"),i=require("react"),B=require("../ChartTooltip/ChartTooltip.cjs"),D=require("../../../hooks/use-plotly-theme.cjs"),j=require("../../../utils/colors.cjs"),R=require("../ChartTooltip/lines.cjs"),F=80,H=40,J=({dataSeries:a,width:A=1e3,height:_=600,xRange:h,yRange:d,variant:g="normal",xTitle:x="Columns",yTitle:k="Rows",title:p,xTickText:M})=>{const y=i.useRef(null),o=D.usePlotlyTheme(),{bindTooltip:v,tooltipElement:G}=B.useChartTooltip({getLines:t=>R.chartTooltipLines(t.map(e=>typeof e.customdata=="number"?{...e,y:e.customdata}:e),{xLabel:x,yLabel:k})}),{xMin:z,xMax:L,yMin:N,yMax:P}=i.useMemo(()=>{let t=Number.MAX_VALUE,e=Number.MIN_VALUE,n=Number.MAX_VALUE,r=Number.MIN_VALUE;a.forEach(c=>{c.x.forEach(u=>{t=Math.min(t,u),e=Math.max(e,u)}),c.y.forEach(u=>{n=Math.min(n,u),r=Math.max(r,u)})});const l=(e-t)*.1,s=(r-n)*.1;return{xMin:t-l,xMax:e+l,yMin:g==="stacked"?0:n-s,yMax:r+s}},[a,g]),f=i.useMemo(()=>h||[z,L],[h,z,L]),m=i.useMemo(()=>d||[N,P],[d,N,P]),O=i.useMemo(()=>{const t=f[1]-f[0];let e=Math.pow(10,Math.floor(Math.log10(t)));t/e>10&&(e=e*2),t/e<4&&(e=e/2);const n=[];let r=Math.ceil(f[0]/e)*e;for(;r<=f[1];)n.push(r),r+=e;return n},[f]),q=i.useMemo(()=>{const t=m[1]-m[0];let e=Math.pow(10,Math.floor(Math.log10(t)));t/e>10&&(e=e*2),t/e<4&&(e=e/2);const n=[];let r=Math.ceil(m[0]/e)*e;for(;r<=m[1];)n.push(r),r+=e;return n},[m]),w=i.useMemo(()=>[...new Set(a.flatMap(t=>t.x))].sort((t,e)=>t-e),[a]),b=!!M&&M.length===w.length,C=i.useMemo(()=>({tickcolor:o.tickColor,ticklen:12,tickwidth:1,ticks:"outside",tickfont:{size:16,color:o.textColor,family:"Inter, sans-serif",weight:400},linecolor:o.lineColor,linewidth:1,position:0,zeroline:!1}),[o]),E=i.useMemo(()=>p?{text:p,x:.5,y:.95,xanchor:"center",yanchor:"top",font:{size:32,weight:600,family:"Inter, sans-serif",color:o.textColor,lineheight:1.2,standoff:30}}:void 0,[p,o]);return i.useEffect(()=>{if(!y.current)return;let t;if(g==="stacked"){const l=new Array(a[0]?.x.length||0).fill(0);t=a.map((s,c)=>{const u=s.y.map((U,X)=>{const T=l[X]+U;return l[X]=T,T}),I=j.seriesColor(c,s.color);return{x:s.x,y:u,customdata:s.y,type:"scatter",mode:"lines+markers",name:s.name,hoverinfo:"none",fill:c===0?"tozeroy":"tonexty",fillcolor:I,line:{color:I,width:2},marker:{size:6,color:I,line:{color:o.markerOutline,width:1.5}}}})}else t=a.map((l,s)=>{const c=j.seriesColor(s,l.color);return{x:l.x,y:l.y,type:"scatter",mode:"lines+markers",name:l.name,hoverinfo:"none",fill:l.fill||"tozeroy",fillcolor:c,line:{color:c,width:2},marker:{size:6,color:c,line:{color:o.markerOutline,width:1.5}}}});const e={width:A,height:_,...E?{title:E}:{},margin:{l:80,r:40,b:80,t:p?F:H,pad:0},paper_bgcolor:o.paperBg,plot_bgcolor:o.plotBg,font:{family:"Inter, sans-serif"},dragmode:!1,xaxis:{title:{text:x,font:{size:16,color:o.textSecondary,family:"Inter, sans-serif",weight:400},standoff:15},gridcolor:o.gridColor,range:h,autorange:!h,tickmode:"array",tickvals:b?w:O,...b?{ticktext:M}:{},showgrid:!0,...C},yaxis:{title:{text:k,font:{size:16,color:o.textSecondary,family:"Inter, sans-serif",weight:400},standoff:15},gridcolor:o.gridColor,range:d,autorange:!d,tickmode:"array",tickvals:q,showgrid:!0,...C},legend:{x:.5,y:-.2,xanchor:"center",yanchor:"top",orientation:"h",font:{size:13,color:o.legendColor,family:"Inter, sans-serif",weight:500,lineheight:18}},showlegend:!0},n={responsive:!0,displayModeBar:!1,displaylogo:!1};Y.newPlot(y.current,t,e,n),v(y.current);const r=y.current;return()=>{r&&Y.purge(r)}},[a,A,_,h,d,f,m,g,x,k,p,E,C,O,q,w,b,M,o,v]),V.jsxs("div",{className:"area-graph-container relative",children:[V.jsx("div",{ref:y,style:{width:"100%",height:"100%"}}),G]})};exports.AreaGraph=J;
|
|
2
2
|
//# sourceMappingURL=AreaGraph.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AreaGraph.cjs","sources":["../../../../src/components/charts/AreaGraph/AreaGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { chartTooltipLines, useChartTooltip } from \"../ChartTooltip\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface AreaDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n fill?: \"tozeroy\" | \"tonexty\" | \"toself\";\n}\n\ntype AreaGraphVariant = \"normal\" | \"stacked\";\n\ninterface AreaGraphProps {\n dataSeries: AreaDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: AreaGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n}\n\nconst AreaGraph: React.FC<AreaGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n variant = \"normal\",\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title = \"Area Graph\",\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({\n // Stacked traces carry the original series values as customdata;\n // display those instead of the cumulative stack heights\n getLines: (points) =>\n chartTooltipLines(\n points.map((point) =>\n typeof point.customdata === \"number\"\n ? { ...point, y: point.customdata }\n : point,\n ),\n { xLabel: xTitle, yLabel: yTitle },\n ),\n });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stacked\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n const titleOptions = useMemo(\n () => ({\n text: title,\n x: 0.5,\n y: 0.95,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n font: {\n size: 32,\n weight: 600,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n lineheight: 1.2,\n standoff: 30,\n },\n }),\n [title, theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n let data;\n\n if (variant === \"stacked\") {\n // For stacked mode, we need to calculate cumulative values\n const cumulativeY = new Array(dataSeries[0]?.x.length || 0).fill(0);\n\n data = dataSeries.map((series, index) => {\n // Calculate cumulative values for this series\n const stackedY = series.y.map((value, i) => {\n const result = cumulativeY[i] + value;\n cumulativeY[i] = result;\n return result;\n });\n\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: stackedY,\n // Tooltips report the series' own values, not the stacked sums\n customdata: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: index === 0 ? (\"tozeroy\" as const) : (\"tonexty\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n } else {\n // Normal mode - each area fills independently from zero\n data = dataSeries.map((series, index) => {\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: series.fill || (\"tozeroy\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n }\n\n const layout = {\n width,\n height: height,\n title: titleOptions,\n margin: { l: 80, r: 40, b: 80, t: 80, pad: 0 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 13,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n lineheight: 18,\n },\n },\n showlegend: true,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n // Cleanup function\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, effectiveXRange, effectiveYRange, variant, xTitle, yTitle, titleOptions, tickOptions, xTicks, yTicks, theme, bindTooltip]);\n\n return (\n <div className=\"area-graph-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { AreaGraph };\nexport type { AreaDataSeries, AreaGraphVariant, AreaGraphProps };\n"],"names":["AreaGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","points","chartTooltipLines","point","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","titleOptions","useEffect","data","cumulativeY","index","stackedY","value","i","result","color","seriesColor","layout","config","Plotly","plotElement","jsxs","jsx"],"mappings":"iVA+BMA,EAAsC,CAAC,CAC3C,WAAAC,EACA,MAAAC,EAAQ,IACR,OAAAC,EAAS,IACT,OAAAC,EACA,OAAAC,EACA,QAAAC,EAAU,SACV,OAAAC,EAAS,UACT,OAAAC,EAAS,OACT,MAAAC,EAAQ,YACV,IAAM,CACJ,MAAMC,EAAUC,EAAAA,OAAuB,IAAI,EACrCC,EAAQC,EAAAA,eAAA,EACR,CAAE,YAAAC,EAAa,eAAAC,CAAA,EAAmBC,kBAAgB,CAGtD,SAAWC,GACTC,EAAAA,kBACED,EAAO,IAAKE,GACV,OAAOA,EAAM,YAAe,SACxB,CAAE,GAAGA,EAAO,EAAGA,EAAM,YACrBA,CAAA,EAEN,CAAE,OAAQZ,EAAQ,OAAQC,CAAA,CAAO,CACnC,CACH,EAEK,CAAE,KAAAY,EAAM,KAAAC,EAAM,KAAAC,EAAM,KAAAC,CAAA,EAASC,EAAAA,QAAQ,IAAM,CAC/C,IAAIC,EAAO,OAAO,UACdC,EAAO,OAAO,UACdC,EAAO,OAAO,UACdC,EAAO,OAAO,UAElB3B,EAAW,QAAS4B,GAAW,CAC7BA,EAAO,EAAE,QAASC,GAAM,CACtBL,EAAO,KAAK,IAAIA,EAAMK,CAAC,EACvBJ,EAAO,KAAK,IAAIA,EAAMI,CAAC,CACzB,CAAC,EACDD,EAAO,EAAE,QAASE,GAAM,CACtBJ,EAAO,KAAK,IAAIA,EAAMI,CAAC,EACvBH,EAAO,KAAK,IAAIA,EAAMG,CAAC,CACzB,CAAC,CACH,CAAC,EAED,MAAMC,GAAYN,EAAOD,GAAQ,GAC3BQ,GAAYL,EAAOD,GAAQ,GAEjC,MAAO,CACL,KAAMF,EAAOO,EACb,KAAMN,EAAOM,EACb,KAAM1B,IAAY,UAAY,EAAIqB,EAAOM,EACzC,KAAML,EAAOK,CAAA,CAEjB,EAAG,CAAChC,EAAYK,CAAO,CAAC,EAElB4B,EAAkBV,EAAAA,QACtB,IAAMpB,GAAU,CAACgB,EAAMC,CAAI,EAC3B,CAACjB,EAAQgB,EAAMC,CAAI,CAAA,EAEfc,EAAkBX,EAAAA,QACtB,IAAMnB,GAAU,CAACiB,EAAMC,CAAI,EAC3B,CAAClB,EAAQiB,EAAMC,CAAI,CAAA,EAGfa,EAASZ,EAAAA,QAAQ,IAAM,CAC3B,MAAMa,EAAQH,EAAgB,CAAC,EAAIA,EAAgB,CAAC,EACpD,IAAII,EAAO,KAAK,IAAI,GAAI,KAAK,MAAM,KAAK,MAAMD,CAAK,CAAC,CAAC,EAEjDA,EAAQC,EAAO,KAAIA,EAAOA,EAAO,GACjCD,EAAQC,EAAO,IAAGA,EAAOA,EAAO,GAEpC,MAAMC,EAAQ,CAAA,EACd,IAAIC,EAAU,KAAK,KAAKN,EAAgB,CAAC,EAAII,CAAI,EAAIA,EACrD,KAAOE,GAAWN,EAAgB,CAAC,GACjCK,EAAM,KAAKC,CAAO,EAClBA,GAAWF,EAEb,OAAOC,CACT,EAAG,CAACL,CAAe,CAAC,EAEdO,EAASjB,EAAAA,QAAQ,IAAM,CAC3B,MAAMa,EAAQF,EAAgB,CAAC,EAAIA,EAAgB,CAAC,EACpD,IAAIG,EAAO,KAAK,IAAI,GAAI,KAAK,MAAM,KAAK,MAAMD,CAAK,CAAC,CAAC,EAEjDA,EAAQC,EAAO,KAAIA,EAAOA,EAAO,GACjCD,EAAQC,EAAO,IAAGA,EAAOA,EAAO,GAEpC,MAAMC,EAAQ,CAAA,EACd,IAAIC,EAAU,KAAK,KAAKL,EAAgB,CAAC,EAAIG,CAAI,EAAIA,EACrD,KAAOE,GAAWL,EAAgB,CAAC,GACjCI,EAAM,KAAKC,CAAO,EAClBA,GAAWF,EAEb,OAAOC,CACT,EAAG,CAACJ,CAAe,CAAC,EAEdO,EAAclB,EAAAA,QAClB,KAAO,CACL,UAAWZ,EAAM,UACjB,QAAS,GACT,UAAW,EACX,MAAO,UACP,SAAU,CACR,KAAM,GACN,MAAOA,EAAM,UACb,OAAQ,oBACR,OAAQ,GAAA,EAEV,UAAWA,EAAM,UACjB,UAAW,EACX,SAAU,EACV,SAAU,EAAA,GAEZ,CAACA,CAAK,CAAA,EAGF+B,EAAenB,EAAAA,QACnB,KAAO,CACL,KAAMf,EACN,EAAG,GACH,EAAG,IACH,QAAS,SACT,QAAS,MACT,KAAM,CACJ,KAAM,GACN,OAAQ,IACR,OAAQ,oBACR,MAAOG,EAAM,UACb,WAAY,IACZ,SAAU,EAAA,CACZ,GAEF,CAACH,EAAOG,CAAK,CAAA,EAGfgC,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAAClC,EAAQ,QAAS,OAEtB,IAAImC,EAEJ,GAAIvC,IAAY,UAAW,CAEzB,MAAMwC,EAAc,IAAI,MAAM7C,EAAW,CAAC,GAAG,EAAE,QAAU,CAAC,EAAE,KAAK,CAAC,EAElE4C,EAAO5C,EAAW,IAAI,CAAC4B,EAAQkB,IAAU,CAEvC,MAAMC,EAAWnB,EAAO,EAAE,IAAI,CAACoB,EAAOC,IAAM,CAC1C,MAAMC,EAASL,EAAYI,CAAC,EAAID,EAChC,OAAAH,EAAYI,CAAC,EAAIC,EACVA,CACT,CAAC,EAEKC,EAAQC,EAAAA,YAAYN,EAAOlB,EAAO,KAAK,EAC7C,MAAO,CACL,EAAGA,EAAO,EACV,EAAGmB,EAEH,WAAYnB,EAAO,EACnB,KAAM,UAEN,KAAM,gBACN,KAAMA,EAAO,KACb,UAAW,OACX,KAAMkB,IAAU,EAAK,UAAuB,UAC5C,UAAWK,EACX,KAAM,CACJ,MAAAA,EACA,MAAO,CAAA,EAET,OAAQ,CACN,KAAM,EACN,MAAAA,EACA,KAAM,CAAE,MAAOxC,EAAM,cAAe,MAAO,GAAA,CAAI,CACjD,CAEJ,CAAC,CACH,MAEEiC,EAAO5C,EAAW,IAAI,CAAC4B,EAAQkB,IAAU,CACvC,MAAMK,EAAQC,EAAAA,YAAYN,EAAOlB,EAAO,KAAK,EAC7C,MAAO,CACL,EAAGA,EAAO,EACV,EAAGA,EAAO,EACV,KAAM,UAEN,KAAM,gBACN,KAAMA,EAAO,KACb,UAAW,OACX,KAAMA,EAAO,MAAS,UACtB,UAAWuB,EACX,KAAM,CACJ,MAAAA,EACA,MAAO,CAAA,EAET,OAAQ,CACN,KAAM,EACN,MAAAA,EACA,KAAM,CAAE,MAAOxC,EAAM,cAAe,MAAO,GAAA,CAAI,CACjD,CAEJ,CAAC,EAGH,MAAM0C,EAAS,CACb,MAAApD,EACA,OAAAC,EACA,MAAOwC,EACP,OAAQ,CAAE,EAAG,GAAI,EAAG,GAAI,EAAG,GAAI,EAAG,GAAI,IAAK,CAAA,EAC3C,cAAe/B,EAAM,QACrB,aAAcA,EAAM,OACpB,KAAM,CACJ,OAAQ,mBAAA,EAEV,SAAU,GACV,MAAO,CACL,MAAO,CACL,KAAML,EACN,KAAM,CACJ,KAAM,GACN,MAAOK,EAAM,cACb,OAAQ,oBACR,OAAQ,GAAA,EAEV,SAAU,EAAA,EAEZ,UAAWA,EAAM,UACjB,MAAOR,EACP,UAAW,CAACA,EACZ,SAAU,QACV,SAAUgC,EACV,SAAU,GACV,GAAGM,CAAA,EAEL,MAAO,CACL,MAAO,CACL,KAAMlC,EACN,KAAM,CACJ,KAAM,GACN,MAAOI,EAAM,cACb,OAAQ,oBACR,OAAQ,GAAA,EAEV,SAAU,EAAA,EAEZ,UAAWA,EAAM,UACjB,MAAOP,EACP,UAAW,CAACA,EACZ,SAAU,QACV,SAAUoC,EACV,SAAU,GACV,GAAGC,CAAA,EAEL,OAAQ,CACN,EAAG,GACH,EAAG,IACH,QAAS,SACT,QAAS,MACT,YAAa,IACb,KAAM,CACJ,KAAM,GACN,MAAO9B,EAAM,YACb,OAAQ,oBACR,OAAQ,IACR,WAAY,EAAA,CACd,EAEF,WAAY,EAAA,EAGR2C,EAAS,CACb,WAAY,GACZ,eAAgB,GAChB,YAAa,EAAA,EAGfC,EAAO,QAAQ9C,EAAQ,QAASmC,EAAMS,EAAQC,CAAM,EACpDzC,EAAYJ,EAAQ,OAAO,EAG3B,MAAM+C,EAAc/C,EAAQ,QAG5B,MAAO,IAAM,CACP+C,GACFD,EAAO,MAAMC,CAAW,CAE5B,CACF,EAAG,CAACxD,EAAYC,EAAOC,EAAQC,EAAQC,EAAQ6B,EAAiBC,EAAiB7B,EAASC,EAAQC,EAAQmC,EAAcD,EAAaN,EAAQK,EAAQ7B,EAAOE,CAAW,CAAC,EAGtK4C,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,IAAKjD,EAAS,MAAO,CAAE,MAAO,OAAQ,OAAQ,MAAA,CAAO,CAAG,EAC5DK,CAAA,EACH,CAEJ"}
|
|
1
|
+
{"version":3,"file":"AreaGraph.cjs","sources":["../../../../src/components/charts/AreaGraph/AreaGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { chartTooltipLines, useChartTooltip } from \"../ChartTooltip\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface AreaDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n fill?: \"tozeroy\" | \"tonexty\" | \"toself\";\n}\n\ntype AreaGraphVariant = \"normal\" | \"stacked\";\n\n/** Top margin reserving room for the 32px title; reduced when no title is set */\nconst TITLE_MARGIN_TOP = 80;\nconst NO_TITLE_MARGIN_TOP = 40;\n\ninterface AreaGraphProps {\n dataSeries: AreaDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: AreaGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n /**\n * Categorical labels for the x-axis ticks. When provided, the x data values\n * still drive area positioning but the displayed tick labels match these\n * strings in order (e.g. [\"Mon\", \"Tue\", …]). Should align 1:1 with the\n * unique, ordered x values across all series.\n */\n xTickText?: string[];\n}\n\nconst AreaGraph: React.FC<AreaGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n variant = \"normal\",\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title,\n xTickText,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({\n // Stacked traces carry the original series values as customdata;\n // display those instead of the cumulative stack heights\n getLines: (points) =>\n chartTooltipLines(\n points.map((point) =>\n typeof point.customdata === \"number\"\n ? { ...point, y: point.customdata }\n : point,\n ),\n { xLabel: xTitle, yLabel: yTitle },\n ),\n });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stacked\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n // When categorical labels are supplied, ticks must sit on the actual data\n // x-positions rather than the computed nice-step values above. Sorted\n // ascending so labels map deterministically to x regardless of series order.\n const xDataValues = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))].sort((a, b) => a - b),\n [dataSeries],\n );\n\n // Only apply categorical labels when they align 1:1 with the tick positions;\n // a mismatch would silently mis-label ticks, so fall back to numeric ticks.\n const useCategoricalX = !!xTickText && xTickText.length === xDataValues.length;\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n const titleOptions = useMemo(\n () =>\n title\n ? {\n text: title,\n x: 0.5,\n y: 0.95,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n font: {\n size: 32,\n weight: 600,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n lineheight: 1.2,\n standoff: 30,\n },\n }\n : undefined,\n [title, theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n let data;\n\n if (variant === \"stacked\") {\n // For stacked mode, we need to calculate cumulative values\n const cumulativeY = new Array(dataSeries[0]?.x.length || 0).fill(0);\n\n data = dataSeries.map((series, index) => {\n // Calculate cumulative values for this series\n const stackedY = series.y.map((value, i) => {\n const result = cumulativeY[i] + value;\n cumulativeY[i] = result;\n return result;\n });\n\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: stackedY,\n // Tooltips report the series' own values, not the stacked sums\n customdata: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: index === 0 ? (\"tozeroy\" as const) : (\"tonexty\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n } else {\n // Normal mode - each area fills independently from zero\n data = dataSeries.map((series, index) => {\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: series.fill || (\"tozeroy\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n }\n\n const layout = {\n width,\n height: height,\n ...(titleOptions ? { title: titleOptions } : {}),\n margin: {\n l: 80,\n r: 40,\n b: 80,\n t: title ? TITLE_MARGIN_TOP : NO_TITLE_MARGIN_TOP,\n pad: 0,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: useCategoricalX ? xDataValues : xTicks,\n ...(useCategoricalX ? { ticktext: xTickText } : {}),\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 13,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n lineheight: 18,\n },\n },\n showlegend: true,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n // Cleanup function\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, effectiveXRange, effectiveYRange, variant, xTitle, yTitle, title, titleOptions, tickOptions, xTicks, yTicks, xDataValues, useCategoricalX, xTickText, theme, bindTooltip]);\n\n return (\n <div className=\"area-graph-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { AreaGraph };\nexport type { AreaDataSeries, AreaGraphVariant, AreaGraphProps };\n"],"names":["TITLE_MARGIN_TOP","NO_TITLE_MARGIN_TOP","AreaGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","xTickText","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","points","chartTooltipLines","point","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","xDataValues","s","a","b","useCategoricalX","tickOptions","titleOptions","useEffect","data","cumulativeY","index","stackedY","value","i","result","color","seriesColor","layout","config","Plotly","plotElement","jsxs","jsx"],"mappings":"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"}
|
|
@@ -1,37 +1,38 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import
|
|
3
|
-
import { useRef as
|
|
4
|
-
import { useChartTooltip as
|
|
5
|
-
import { usePlotlyTheme as
|
|
6
|
-
import { seriesColor as
|
|
7
|
-
import { chartTooltipLines as
|
|
8
|
-
const
|
|
9
|
-
dataSeries:
|
|
10
|
-
width:
|
|
11
|
-
height:
|
|
1
|
+
import { jsxs as T, jsx as D } from "react/jsx-runtime";
|
|
2
|
+
import U from "plotly.js-dist";
|
|
3
|
+
import { useRef as q, useMemo as s, useEffect as F } from "react";
|
|
4
|
+
import { useChartTooltip as H } from "../ChartTooltip/ChartTooltip.js";
|
|
5
|
+
import { usePlotlyTheme as J } from "../../../hooks/use-plotly-theme.js";
|
|
6
|
+
import { seriesColor as B } from "../../../utils/colors.js";
|
|
7
|
+
import { chartTooltipLines as K } from "../ChartTooltip/lines.js";
|
|
8
|
+
const Q = 80, W = 40, rt = ({
|
|
9
|
+
dataSeries: c,
|
|
10
|
+
width: _ = 1e3,
|
|
11
|
+
height: z = 600,
|
|
12
12
|
xRange: u,
|
|
13
13
|
yRange: p,
|
|
14
14
|
variant: y = "normal",
|
|
15
|
-
xTitle:
|
|
16
|
-
yTitle:
|
|
17
|
-
title:
|
|
15
|
+
xTitle: x = "Columns",
|
|
16
|
+
yTitle: k = "Rows",
|
|
17
|
+
title: d,
|
|
18
|
+
xTickText: M
|
|
18
19
|
}) => {
|
|
19
|
-
const
|
|
20
|
+
const g = q(null), e = J(), { bindTooltip: A, tooltipElement: G } = H({
|
|
20
21
|
// Stacked traces carry the original series values as customdata;
|
|
21
22
|
// display those instead of the cumulative stack heights
|
|
22
|
-
getLines: (o) =>
|
|
23
|
+
getLines: (o) => K(
|
|
23
24
|
o.map(
|
|
24
25
|
(t) => typeof t.customdata == "number" ? { ...t, y: t.customdata } : t
|
|
25
26
|
),
|
|
26
|
-
{ xLabel:
|
|
27
|
+
{ xLabel: x, yLabel: k }
|
|
27
28
|
)
|
|
28
|
-
}), { xMin:
|
|
29
|
+
}), { xMin: L, xMax: N, yMin: v, yMax: O } = s(() => {
|
|
29
30
|
let o = Number.MAX_VALUE, t = Number.MIN_VALUE, n = Number.MAX_VALUE, r = Number.MIN_VALUE;
|
|
30
|
-
|
|
31
|
-
a.x.forEach((
|
|
32
|
-
o = Math.min(o,
|
|
33
|
-
}), a.y.forEach((
|
|
34
|
-
n = Math.min(n,
|
|
31
|
+
c.forEach((a) => {
|
|
32
|
+
a.x.forEach((f) => {
|
|
33
|
+
o = Math.min(o, f), t = Math.max(t, f);
|
|
34
|
+
}), a.y.forEach((f) => {
|
|
35
|
+
n = Math.min(n, f), r = Math.max(r, f);
|
|
35
36
|
});
|
|
36
37
|
});
|
|
37
38
|
const l = (t - o) * 0.1, i = (r - n) * 0.1;
|
|
@@ -41,13 +42,13 @@ const R = ({
|
|
|
41
42
|
yMin: y === "stacked" ? 0 : n - i,
|
|
42
43
|
yMax: r + i
|
|
43
44
|
};
|
|
44
|
-
}, [
|
|
45
|
-
() => u || [
|
|
46
|
-
[u,
|
|
45
|
+
}, [c, y]), m = s(
|
|
46
|
+
() => u || [L, N],
|
|
47
|
+
[u, L, N]
|
|
47
48
|
), h = s(
|
|
48
|
-
() => p || [v,
|
|
49
|
-
[p, v,
|
|
50
|
-
),
|
|
49
|
+
() => p || [v, O],
|
|
50
|
+
[p, v, O]
|
|
51
|
+
), P = s(() => {
|
|
51
52
|
const o = m[1] - m[0];
|
|
52
53
|
let t = Math.pow(10, Math.floor(Math.log10(o)));
|
|
53
54
|
o / t > 10 && (t = t * 2), o / t < 4 && (t = t / 2);
|
|
@@ -56,7 +57,7 @@ const R = ({
|
|
|
56
57
|
for (; r <= m[1]; )
|
|
57
58
|
n.push(r), r += t;
|
|
58
59
|
return n;
|
|
59
|
-
}, [m]),
|
|
60
|
+
}, [m]), X = s(() => {
|
|
60
61
|
const o = h[1] - h[0];
|
|
61
62
|
let t = Math.pow(10, Math.floor(Math.log10(o)));
|
|
62
63
|
o / t > 10 && (t = t * 2), o / t < 4 && (t = t / 2);
|
|
@@ -65,7 +66,10 @@ const R = ({
|
|
|
65
66
|
for (; r <= h[1]; )
|
|
66
67
|
n.push(r), r += t;
|
|
67
68
|
return n;
|
|
68
|
-
}, [h]),
|
|
69
|
+
}, [h]), w = s(
|
|
70
|
+
() => [...new Set(c.flatMap((o) => o.x))].sort((o, t) => o - t),
|
|
71
|
+
[c]
|
|
72
|
+
), E = !!M && M.length === w.length, I = s(
|
|
69
73
|
() => ({
|
|
70
74
|
tickcolor: e.tickColor,
|
|
71
75
|
ticklen: 12,
|
|
@@ -83,9 +87,9 @@ const R = ({
|
|
|
83
87
|
zeroline: !1
|
|
84
88
|
}),
|
|
85
89
|
[e]
|
|
86
|
-
),
|
|
87
|
-
() =>
|
|
88
|
-
text:
|
|
90
|
+
), b = s(
|
|
91
|
+
() => d ? {
|
|
92
|
+
text: d,
|
|
89
93
|
x: 0.5,
|
|
90
94
|
y: 0.95,
|
|
91
95
|
xanchor: "center",
|
|
@@ -98,22 +102,22 @@ const R = ({
|
|
|
98
102
|
lineheight: 1.2,
|
|
99
103
|
standoff: 30
|
|
100
104
|
}
|
|
101
|
-
}
|
|
102
|
-
[
|
|
105
|
+
} : void 0,
|
|
106
|
+
[d, e]
|
|
103
107
|
);
|
|
104
|
-
return
|
|
105
|
-
if (!
|
|
108
|
+
return F(() => {
|
|
109
|
+
if (!g.current) return;
|
|
106
110
|
let o;
|
|
107
111
|
if (y === "stacked") {
|
|
108
|
-
const l = new Array(
|
|
109
|
-
o =
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
return l[
|
|
113
|
-
}),
|
|
112
|
+
const l = new Array(c[0]?.x.length || 0).fill(0);
|
|
113
|
+
o = c.map((i, a) => {
|
|
114
|
+
const f = i.y.map((j, V) => {
|
|
115
|
+
const Y = l[V] + j;
|
|
116
|
+
return l[V] = Y, Y;
|
|
117
|
+
}), C = B(a, i.color);
|
|
114
118
|
return {
|
|
115
119
|
x: i.x,
|
|
116
|
-
y:
|
|
120
|
+
y: f,
|
|
117
121
|
// Tooltips report the series' own values, not the stacked sums
|
|
118
122
|
customdata: i.y,
|
|
119
123
|
type: "scatter",
|
|
@@ -122,21 +126,21 @@ const R = ({
|
|
|
122
126
|
name: i.name,
|
|
123
127
|
hoverinfo: "none",
|
|
124
128
|
fill: a === 0 ? "tozeroy" : "tonexty",
|
|
125
|
-
fillcolor:
|
|
129
|
+
fillcolor: C,
|
|
126
130
|
line: {
|
|
127
|
-
color:
|
|
131
|
+
color: C,
|
|
128
132
|
width: 2
|
|
129
133
|
},
|
|
130
134
|
marker: {
|
|
131
135
|
size: 6,
|
|
132
|
-
color:
|
|
136
|
+
color: C,
|
|
133
137
|
line: { color: e.markerOutline, width: 1.5 }
|
|
134
138
|
}
|
|
135
139
|
};
|
|
136
140
|
});
|
|
137
141
|
} else
|
|
138
|
-
o =
|
|
139
|
-
const a =
|
|
142
|
+
o = c.map((l, i) => {
|
|
143
|
+
const a = B(i, l.color);
|
|
140
144
|
return {
|
|
141
145
|
x: l.x,
|
|
142
146
|
y: l.y,
|
|
@@ -159,10 +163,16 @@ const R = ({
|
|
|
159
163
|
};
|
|
160
164
|
});
|
|
161
165
|
const t = {
|
|
162
|
-
width:
|
|
163
|
-
height:
|
|
164
|
-
title:
|
|
165
|
-
margin: {
|
|
166
|
+
width: _,
|
|
167
|
+
height: z,
|
|
168
|
+
...b ? { title: b } : {},
|
|
169
|
+
margin: {
|
|
170
|
+
l: 80,
|
|
171
|
+
r: 40,
|
|
172
|
+
b: 80,
|
|
173
|
+
t: d ? Q : W,
|
|
174
|
+
pad: 0
|
|
175
|
+
},
|
|
166
176
|
paper_bgcolor: e.paperBg,
|
|
167
177
|
plot_bgcolor: e.plotBg,
|
|
168
178
|
font: {
|
|
@@ -171,7 +181,7 @@ const R = ({
|
|
|
171
181
|
dragmode: !1,
|
|
172
182
|
xaxis: {
|
|
173
183
|
title: {
|
|
174
|
-
text:
|
|
184
|
+
text: x,
|
|
175
185
|
font: {
|
|
176
186
|
size: 16,
|
|
177
187
|
color: e.textSecondary,
|
|
@@ -184,13 +194,14 @@ const R = ({
|
|
|
184
194
|
range: u,
|
|
185
195
|
autorange: !u,
|
|
186
196
|
tickmode: "array",
|
|
187
|
-
tickvals:
|
|
197
|
+
tickvals: E ? w : P,
|
|
198
|
+
...E ? { ticktext: M } : {},
|
|
188
199
|
showgrid: !0,
|
|
189
|
-
...
|
|
200
|
+
...I
|
|
190
201
|
},
|
|
191
202
|
yaxis: {
|
|
192
203
|
title: {
|
|
193
|
-
text:
|
|
204
|
+
text: k,
|
|
194
205
|
font: {
|
|
195
206
|
size: 16,
|
|
196
207
|
color: e.textSecondary,
|
|
@@ -203,9 +214,9 @@ const R = ({
|
|
|
203
214
|
range: p,
|
|
204
215
|
autorange: !p,
|
|
205
216
|
tickmode: "array",
|
|
206
|
-
tickvals:
|
|
217
|
+
tickvals: X,
|
|
207
218
|
showgrid: !0,
|
|
208
|
-
...
|
|
219
|
+
...I
|
|
209
220
|
},
|
|
210
221
|
legend: {
|
|
211
222
|
x: 0.5,
|
|
@@ -227,17 +238,17 @@ const R = ({
|
|
|
227
238
|
displayModeBar: !1,
|
|
228
239
|
displaylogo: !1
|
|
229
240
|
};
|
|
230
|
-
|
|
231
|
-
const r =
|
|
241
|
+
U.newPlot(g.current, o, t, n), A(g.current);
|
|
242
|
+
const r = g.current;
|
|
232
243
|
return () => {
|
|
233
|
-
r &&
|
|
244
|
+
r && U.purge(r);
|
|
234
245
|
};
|
|
235
|
-
}, [
|
|
236
|
-
/* @__PURE__ */
|
|
237
|
-
|
|
246
|
+
}, [c, _, z, u, p, m, h, y, x, k, d, b, I, P, X, w, E, M, e, A]), /* @__PURE__ */ T("div", { className: "area-graph-container relative", children: [
|
|
247
|
+
/* @__PURE__ */ D("div", { ref: g, style: { width: "100%", height: "100%" } }),
|
|
248
|
+
G
|
|
238
249
|
] });
|
|
239
250
|
};
|
|
240
251
|
export {
|
|
241
|
-
|
|
252
|
+
rt as AreaGraph
|
|
242
253
|
};
|
|
243
254
|
//# sourceMappingURL=AreaGraph.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AreaGraph.js","sources":["../../../../src/components/charts/AreaGraph/AreaGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { chartTooltipLines, useChartTooltip } from \"../ChartTooltip\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface AreaDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n fill?: \"tozeroy\" | \"tonexty\" | \"toself\";\n}\n\ntype AreaGraphVariant = \"normal\" | \"stacked\";\n\ninterface AreaGraphProps {\n dataSeries: AreaDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: AreaGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n}\n\nconst AreaGraph: React.FC<AreaGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n variant = \"normal\",\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title = \"Area Graph\",\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({\n // Stacked traces carry the original series values as customdata;\n // display those instead of the cumulative stack heights\n getLines: (points) =>\n chartTooltipLines(\n points.map((point) =>\n typeof point.customdata === \"number\"\n ? { ...point, y: point.customdata }\n : point,\n ),\n { xLabel: xTitle, yLabel: yTitle },\n ),\n });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stacked\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n const titleOptions = useMemo(\n () => ({\n text: title,\n x: 0.5,\n y: 0.95,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n font: {\n size: 32,\n weight: 600,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n lineheight: 1.2,\n standoff: 30,\n },\n }),\n [title, theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n let data;\n\n if (variant === \"stacked\") {\n // For stacked mode, we need to calculate cumulative values\n const cumulativeY = new Array(dataSeries[0]?.x.length || 0).fill(0);\n\n data = dataSeries.map((series, index) => {\n // Calculate cumulative values for this series\n const stackedY = series.y.map((value, i) => {\n const result = cumulativeY[i] + value;\n cumulativeY[i] = result;\n return result;\n });\n\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: stackedY,\n // Tooltips report the series' own values, not the stacked sums\n customdata: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: index === 0 ? (\"tozeroy\" as const) : (\"tonexty\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n } else {\n // Normal mode - each area fills independently from zero\n data = dataSeries.map((series, index) => {\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: series.fill || (\"tozeroy\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n }\n\n const layout = {\n width,\n height: height,\n title: titleOptions,\n margin: { l: 80, r: 40, b: 80, t: 80, pad: 0 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 13,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n lineheight: 18,\n },\n },\n showlegend: true,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n // Cleanup function\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, effectiveXRange, effectiveYRange, variant, xTitle, yTitle, titleOptions, tickOptions, xTicks, yTicks, theme, bindTooltip]);\n\n return (\n <div className=\"area-graph-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { AreaGraph };\nexport type { AreaDataSeries, AreaGraphVariant, AreaGraphProps };\n"],"names":["AreaGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","points","chartTooltipLines","point","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","titleOptions","useEffect","data","cumulativeY","index","stackedY","value","i","result","color","seriesColor","layout","config","Plotly","plotElement","jsxs","jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AreaGraph.js","sources":["../../../../src/components/charts/AreaGraph/AreaGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { chartTooltipLines, useChartTooltip } from \"../ChartTooltip\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface AreaDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n fill?: \"tozeroy\" | \"tonexty\" | \"toself\";\n}\n\ntype AreaGraphVariant = \"normal\" | \"stacked\";\n\n/** Top margin reserving room for the 32px title; reduced when no title is set */\nconst TITLE_MARGIN_TOP = 80;\nconst NO_TITLE_MARGIN_TOP = 40;\n\ninterface AreaGraphProps {\n dataSeries: AreaDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: AreaGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n /**\n * Categorical labels for the x-axis ticks. When provided, the x data values\n * still drive area positioning but the displayed tick labels match these\n * strings in order (e.g. [\"Mon\", \"Tue\", …]). Should align 1:1 with the\n * unique, ordered x values across all series.\n */\n xTickText?: string[];\n}\n\nconst AreaGraph: React.FC<AreaGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n variant = \"normal\",\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title,\n xTickText,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({\n // Stacked traces carry the original series values as customdata;\n // display those instead of the cumulative stack heights\n getLines: (points) =>\n chartTooltipLines(\n points.map((point) =>\n typeof point.customdata === \"number\"\n ? { ...point, y: point.customdata }\n : point,\n ),\n { xLabel: xTitle, yLabel: yTitle },\n ),\n });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stacked\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n // When categorical labels are supplied, ticks must sit on the actual data\n // x-positions rather than the computed nice-step values above. Sorted\n // ascending so labels map deterministically to x regardless of series order.\n const xDataValues = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))].sort((a, b) => a - b),\n [dataSeries],\n );\n\n // Only apply categorical labels when they align 1:1 with the tick positions;\n // a mismatch would silently mis-label ticks, so fall back to numeric ticks.\n const useCategoricalX = !!xTickText && xTickText.length === xDataValues.length;\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n const titleOptions = useMemo(\n () =>\n title\n ? {\n text: title,\n x: 0.5,\n y: 0.95,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n font: {\n size: 32,\n weight: 600,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n lineheight: 1.2,\n standoff: 30,\n },\n }\n : undefined,\n [title, theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n let data;\n\n if (variant === \"stacked\") {\n // For stacked mode, we need to calculate cumulative values\n const cumulativeY = new Array(dataSeries[0]?.x.length || 0).fill(0);\n\n data = dataSeries.map((series, index) => {\n // Calculate cumulative values for this series\n const stackedY = series.y.map((value, i) => {\n const result = cumulativeY[i] + value;\n cumulativeY[i] = result;\n return result;\n });\n\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: stackedY,\n // Tooltips report the series' own values, not the stacked sums\n customdata: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: index === 0 ? (\"tozeroy\" as const) : (\"tonexty\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n } else {\n // Normal mode - each area fills independently from zero\n data = dataSeries.map((series, index) => {\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n // Dots mark each data point — the spots the tooltip anchors to\n mode: \"lines+markers\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: series.fill || (\"tozeroy\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n marker: {\n size: 6,\n color,\n line: { color: theme.markerOutline, width: 1.5 },\n },\n };\n });\n }\n\n const layout = {\n width,\n height: height,\n ...(titleOptions ? { title: titleOptions } : {}),\n margin: {\n l: 80,\n r: 40,\n b: 80,\n t: title ? TITLE_MARGIN_TOP : NO_TITLE_MARGIN_TOP,\n pad: 0,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: useCategoricalX ? xDataValues : xTicks,\n ...(useCategoricalX ? { ticktext: xTickText } : {}),\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 13,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n lineheight: 18,\n },\n },\n showlegend: true,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n // Cleanup function\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, effectiveXRange, effectiveYRange, variant, xTitle, yTitle, title, titleOptions, tickOptions, xTicks, yTicks, xDataValues, useCategoricalX, xTickText, theme, bindTooltip]);\n\n return (\n <div className=\"area-graph-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { AreaGraph };\nexport type { AreaDataSeries, AreaGraphVariant, AreaGraphProps };\n"],"names":["TITLE_MARGIN_TOP","NO_TITLE_MARGIN_TOP","AreaGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","xTickText","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","points","chartTooltipLines","point","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","xDataValues","s","a","b","useCategoricalX","tickOptions","titleOptions","useEffect","data","cumulativeY","index","stackedY","value","i","result","color","seriesColor","layout","config","Plotly","plotElement","jsxs","jsx"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const L=require("react/jsx-runtime"),q=require("plotly.js-dist"),l=require("react"),B=require("../ChartTooltip/ChartTooltip.cjs"),O=require("../../../hooks/use-plotly-theme.cjs"),X=require("../../../utils/colors.cjs"),j=60,G=30,T=({dataSeries:a,width:k=1e3,height:w=600,xRange:d,yRange:c,variant:m="group",xTitle:y="Columns",yTitle:M="Rows",title:h,barWidth:_=24,xTickText:g})=>{const i=l.useRef(null),t=O.usePlotlyTheme(),{bindTooltip:C,tooltipElement:z}=B.useChartTooltip({xLabel:y,yLabel:M}),{yMin:E,yMax:I}=l.useMemo(()=>{let e=Number.MAX_VALUE,o=Number.MIN_VALUE,n=Number.MAX_VALUE,r=Number.MIN_VALUE;a.forEach(A=>{A.x.forEach(f=>{e=Math.min(e,f),o=Math.max(o,f)}),A.y.forEach(f=>{n=Math.min(n,f),r=Math.max(r,f)})});const s=(o-e)*.1,p=(r-n)*.1;return{xMin:e-s,xMax:o+s,yMin:m==="stack"?0:n-p,yMax:r+p}},[a,m]),u=l.useMemo(()=>c||[E,I],[c,E,I]),x=l.useMemo(()=>[...new Set(a.flatMap(e=>e.x))].sort((e,o)=>e-o),[a]),N=!!g&&g.length===x.length,P=l.useMemo(()=>{const e=u[1]-u[0];let o=Math.pow(10,Math.floor(Math.log10(e)));e/o>10&&(o=o*2),e/o<4&&(o=o/2);const n=[];let r=Math.ceil(u[0]/o)*o;for(;r<=u[1];)n.push(r),r+=o;return n},[u]),v=l.useMemo(()=>{switch(m){case"stack":return"stack";case"overlay":return"overlay";default:return"group"}},[m]),b=l.useMemo(()=>({tickcolor:t.tickColor,ticklen:12,tickwidth:1,ticks:"outside",tickfont:{size:16,color:t.textColor,family:"Inter, sans-serif",weight:400},linecolor:t.lineColor,linewidth:1,position:0,zeroline:!1}),[t]);return l.useEffect(()=>{if(!i.current)return;const e=a.map((s,p)=>({x:s.x,y:s.y,type:"bar",name:s.name,hoverinfo:"none",marker:{color:X.seriesColor(p,s.color)},width:_,error_y:s.error_y})),o={...h?{title:{text:h,font:{size:32,family:"Inter, sans-serif",color:t.textColor}}}:{},width:k,height:w,margin:{l:80,r:30,b:80,t:h?j:G,pad:0},paper_bgcolor:t.paperBg,plot_bgcolor:t.plotBg,font:{family:"Inter, sans-serif"},barmode:v,bargap:.15,dragmode:!1,xaxis:{title:{text:y,font:{size:16,color:t.textSecondary,family:"Inter, sans-serif",weight:400},standoff:32},gridcolor:t.gridColor,range:d,autorange:!d,tickmode:"array",tickvals:x,...N?{ticktext:g}:{},showgrid:!0,...b},yaxis:{title:{text:M,font:{size:16,color:t.textSecondary,family:"Inter, sans-serif",weight:400},standoff:30},gridcolor:t.gridColor,range:c,autorange:!c,tickmode:"array",tickvals:P,showgrid:!0,...b},legend:{x:.5,y:-.2,xanchor:"center",yanchor:"top",orientation:"h",font:{size:16,color:t.legendColor,family:"Inter, sans-serif",weight:500}},showlegend:a.length>1},n={responsive:!0,displayModeBar:!1,displaylogo:!1};q.newPlot(i.current,e,o,n),C(i.current);const r=i.current;return()=>{r&&q.purge(r)}},[a,k,w,d,c,y,M,h,_,v,b,x,P,N,g,t,C]),L.jsxs("div",{className:"bar-graph-container relative",children:[L.jsx("div",{ref:i,style:{width:"100%",height:"100%"}}),z]})};exports.BarGraph=T;
|
|
2
2
|
//# sourceMappingURL=BarGraph.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BarGraph.cjs","sources":["../../../../src/components/charts/BarGraph/BarGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface BarDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n error_y?: {\n type: \"data\";\n array: number[];\n visible: boolean;\n };\n}\n\ntype BarGraphVariant = \"group\" | \"stack\" | \"overlay\";\n\ninterface BarGraphProps {\n dataSeries: BarDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: BarGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n barWidth?: number;\n}\n\nconst BarGraph: React.FC<BarGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n variant = \"group\",\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title = \"Bar Graph\",\n barWidth = 24,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n const { yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stack\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))],\n [dataSeries],\n );\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const barMode = useMemo((): \"group\" | \"stack\" | \"overlay\" => {\n switch (variant) {\n case \"stack\":\n return \"stack\";\n case \"overlay\":\n return \"overlay\";\n case \"group\":\n default:\n return \"group\";\n }\n }, [variant]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n const data = dataSeries.map((series, index) => ({\n x: series.x,\n y: series.y,\n type: \"bar\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n marker: {\n color: seriesColor(index, series.color),\n },\n width: barWidth,\n error_y: series.error_y,\n }));\n\n const layout = {\n title: {\n text: title,\n font: {\n size: 32,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n },\n width,\n height,\n margin: { l: 80, r: 30, b: 80, t: 60, pad: 0 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n barmode: barMode,\n bargap: 0.15,\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n },\n },\n showlegend: dataSeries.length > 1,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n // Cleanup function\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, xTitle, yTitle, title, barWidth, barMode, tickOptions, xTicks, yTicks, theme, bindTooltip]);\n\n return (\n <div className=\"bar-graph-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { BarGraph };\nexport type { BarDataSeries, BarGraphVariant, BarGraphProps };\n"],"names":["BarGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","barWidth","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveYRange","xTicks","s","yTicks","range","step","ticks","current","barMode","tickOptions","useEffect","data","index","seriesColor","layout","config","Plotly","plotElement","jsxs","jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BarGraph.cjs","sources":["../../../../src/components/charts/BarGraph/BarGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface BarDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n error_y?: {\n type: \"data\";\n array: number[];\n visible: boolean;\n };\n}\n\ntype BarGraphVariant = \"group\" | \"stack\" | \"overlay\";\n\n/** Top margin reserving room for the 32px title; reduced when no title is set */\nconst TITLE_MARGIN_TOP = 60;\nconst NO_TITLE_MARGIN_TOP = 30;\n\ninterface BarGraphProps {\n dataSeries: BarDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: BarGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n barWidth?: number;\n /**\n * Categorical labels for the x-axis ticks. When provided, the x data values\n * still drive bar positioning but the displayed tick labels match these\n * strings in order (e.g. [\"Mon\", \"Tue\", …]). Should align 1:1 with the\n * unique, ordered x values across all series.\n */\n xTickText?: string[];\n}\n\nconst BarGraph: React.FC<BarGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n variant = \"group\",\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title,\n barWidth = 24,\n xTickText,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n const { yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stack\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))].sort((a, b) => a - b),\n [dataSeries],\n );\n\n // Only apply categorical labels when they align 1:1 with the tick positions;\n // a mismatch would silently mis-label ticks, so fall back to numeric ticks.\n const useCategoricalX = !!xTickText && xTickText.length === xTicks.length;\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const barMode = useMemo((): \"group\" | \"stack\" | \"overlay\" => {\n switch (variant) {\n case \"stack\":\n return \"stack\";\n case \"overlay\":\n return \"overlay\";\n case \"group\":\n default:\n return \"group\";\n }\n }, [variant]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n const data = dataSeries.map((series, index) => ({\n x: series.x,\n y: series.y,\n type: \"bar\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n marker: {\n color: seriesColor(index, series.color),\n },\n width: barWidth,\n error_y: series.error_y,\n }));\n\n const layout = {\n ...(title\n ? {\n title: {\n text: title,\n font: {\n size: 32,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n },\n }\n : {}),\n width,\n height,\n margin: {\n l: 80,\n r: 30,\n b: 80,\n t: title ? TITLE_MARGIN_TOP : NO_TITLE_MARGIN_TOP,\n pad: 0,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n barmode: barMode,\n bargap: 0.15,\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n ...(useCategoricalX ? { ticktext: xTickText } : {}),\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n },\n },\n showlegend: dataSeries.length > 1,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n // Cleanup function\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, xTitle, yTitle, title, barWidth, barMode, tickOptions, xTicks, yTicks, useCategoricalX, xTickText, theme, bindTooltip]);\n\n return (\n <div className=\"bar-graph-container relative\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { BarGraph };\nexport type { BarDataSeries, BarGraphVariant, BarGraphProps };\n"],"names":["TITLE_MARGIN_TOP","NO_TITLE_MARGIN_TOP","BarGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","barWidth","xTickText","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveYRange","xTicks","s","a","b","useCategoricalX","yTicks","range","step","ticks","current","barMode","tickOptions","useEffect","data","index","seriesColor","layout","config","Plotly","plotElement","jsxs","jsx"],"mappings":"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"}
|