drizzle-cube 0.4.7 → 0.4.8
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/adapters/express/index.cjs +1 -1
- package/dist/adapters/express/index.js +2 -2
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/fastify/index.js +2 -2
- package/dist/adapters/handler-BLcxTuwi.cjs +23 -0
- package/dist/adapters/handler-odjn7MIB.js +1880 -0
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/hono/index.js +2 -2
- package/dist/adapters/{mcp-transport-DFTCWene.js → mcp-transport-CU5g9bxj.js} +3 -3
- package/dist/adapters/{mcp-transport-BB998cy5.cjs → mcp-transport-KX92EgkF.cjs} +2 -2
- package/dist/adapters/nextjs/index.cjs +2 -2
- package/dist/adapters/nextjs/index.js +3 -3
- package/dist/client/charts/chartConfigs.d.ts +2 -9
- package/dist/client/charts.js +72 -70
- package/dist/client/charts.js.map +1 -1
- package/dist/client/chunks/{RetentionCombinedChart.config-C-ILIaEb.js → RetentionCombinedChart.config-Bbp2ghim.js} +2 -1
- package/dist/client/chunks/RetentionCombinedChart.config-Bbp2ghim.js.map +1 -0
- package/dist/client/chunks/{RetentionHeatmap.config-CIvhc-GT.js → RetentionHeatmap.config-BWf_-vdj.js} +2 -1
- package/dist/client/chunks/RetentionHeatmap.config-BWf_-vdj.js.map +1 -0
- package/dist/client/chunks/{analysis-builder-Dn8xpgPQ.js → analysis-builder-Bov_gLsf.js} +1408 -1393
- package/dist/client/chunks/analysis-builder-Bov_gLsf.js.map +1 -0
- package/dist/client/chunks/{analysis-builder-shared-D3xYzXlh.js → analysis-builder-shared-NBk6y0md.js} +3 -3
- package/dist/client/chunks/{analysis-builder-shared-D3xYzXlh.js.map → analysis-builder-shared-NBk6y0md.js.map} +1 -1
- package/dist/client/chunks/{chart-activity-grid-DStNr34n.js → chart-activity-grid-CE7xGFQo.js} +2 -2
- package/dist/client/chunks/{chart-activity-grid-DStNr34n.js.map → chart-activity-grid-CE7xGFQo.js.map} +1 -1
- package/dist/client/chunks/chart-box-plot-Dja4LS3O.js +313 -0
- package/dist/client/chunks/chart-box-plot-Dja4LS3O.js.map +1 -0
- package/dist/client/chunks/{chart-config-activity-grid-CAlo1cHA.js → chart-config-activity-grid-CmOqDuOT.js} +4 -5
- package/dist/client/chunks/chart-config-activity-grid-CmOqDuOT.js.map +1 -0
- package/dist/client/chunks/{chart-config-area-CyyJOO2T.js → chart-config-area-CK_GVApT.js} +4 -5
- package/dist/client/chunks/chart-config-area-CK_GVApT.js.map +1 -0
- package/dist/client/chunks/{chart-config-bar-soxw6m2o.js → chart-config-bar-C8uzktxl.js} +4 -5
- package/dist/client/chunks/chart-config-bar-C8uzktxl.js.map +1 -0
- package/dist/client/chunks/chart-config-box-plot-D3DA7_pr.js +85 -0
- package/dist/client/chunks/chart-config-box-plot-D3DA7_pr.js.map +1 -0
- package/dist/client/chunks/{chart-config-bubble-CuSsCHZ4.js → chart-config-bubble-q3DoQX5F.js} +4 -5
- package/dist/client/chunks/chart-config-bubble-q3DoQX5F.js.map +1 -0
- package/dist/client/chunks/{chart-config-data-table-BhgqwoqT.js → chart-config-data-table-B20Y5JCm.js} +4 -5
- package/dist/client/chunks/chart-config-data-table-B20Y5JCm.js.map +1 -0
- package/dist/client/chunks/{chart-config-funnel-BlSQYng0.js → chart-config-funnel-3eYnGg8M.js} +4 -5
- package/dist/client/chunks/chart-config-funnel-3eYnGg8M.js.map +1 -0
- package/dist/client/chunks/{chart-config-heat-map-DHQGFZhX.js → chart-config-heat-map-_wEnTnRA.js} +4 -5
- package/dist/client/chunks/chart-config-heat-map-_wEnTnRA.js.map +1 -0
- package/dist/client/chunks/{chart-config-kpi-delta-yTA5ug_l.js → chart-config-kpi-delta-DLGZ2A3X.js} +4 -5
- package/dist/client/chunks/chart-config-kpi-delta-DLGZ2A3X.js.map +1 -0
- package/dist/client/chunks/{chart-config-kpi-number-nVAwDXzq.js → chart-config-kpi-number-K-wzviXF.js} +4 -5
- package/dist/client/chunks/chart-config-kpi-number-K-wzviXF.js.map +1 -0
- package/dist/client/chunks/{chart-config-kpi-text-DZjqsx-b.js → chart-config-kpi-text-BjYqwqaJ.js} +4 -5
- package/dist/client/chunks/chart-config-kpi-text-BjYqwqaJ.js.map +1 -0
- package/dist/client/chunks/{chart-config-line-D5ME6w0v.js → chart-config-line-JNagi9tf.js} +4 -5
- package/dist/client/chunks/chart-config-line-JNagi9tf.js.map +1 -0
- package/dist/client/chunks/{chart-config-markdown-BXKL5TbQ.js → chart-config-markdown-BWQSjJpy.js} +4 -5
- package/dist/client/chunks/chart-config-markdown-BWQSjJpy.js.map +1 -0
- package/dist/client/chunks/{chart-config-pie-DlHa2jTy.js → chart-config-pie-CNLXb-fr.js} +4 -5
- package/dist/client/chunks/chart-config-pie-CNLXb-fr.js.map +1 -0
- package/dist/client/chunks/{chart-config-radar-BBAVIF0S.js → chart-config-radar-oxHfRAa3.js} +4 -5
- package/dist/client/chunks/chart-config-radar-oxHfRAa3.js.map +1 -0
- package/dist/client/chunks/{chart-config-radial-bar-CTwjDRnB.js → chart-config-radial-bar-_Aw3jAEm.js} +4 -5
- package/dist/client/chunks/chart-config-radial-bar-_Aw3jAEm.js.map +1 -0
- package/dist/client/chunks/{chart-config-sankey-CNAgsMQ4.js → chart-config-sankey-C8FX9hGF.js} +4 -5
- package/dist/client/chunks/chart-config-sankey-C8FX9hGF.js.map +1 -0
- package/dist/client/chunks/{chart-config-scatter-CWvN2E-X.js → chart-config-scatter-DFKM80eO.js} +4 -5
- package/dist/client/chunks/chart-config-scatter-DFKM80eO.js.map +1 -0
- package/dist/client/chunks/{chart-config-sunburst-W_SKwaj0.js → chart-config-sunburst-BmC0NLTU.js} +4 -5
- package/dist/client/chunks/chart-config-sunburst-BmC0NLTU.js.map +1 -0
- package/dist/client/chunks/{chart-config-tree-map-IRAYf9YM.js → chart-config-tree-map-DGMbNTaa.js} +4 -5
- package/dist/client/chunks/chart-config-tree-map-DGMbNTaa.js.map +1 -0
- package/dist/client/chunks/{chart-data-table-Ch_1c1Zo.js → chart-data-table-Ba_6tuJw.js} +2 -2
- package/dist/client/chunks/{chart-data-table-Ch_1c1Zo.js.map → chart-data-table-Ba_6tuJw.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-delta-CWCmi8vL.js → chart-kpi-delta-D9XJoKuA.js} +3 -3
- package/dist/client/chunks/{chart-kpi-delta-CWCmi8vL.js.map → chart-kpi-delta-D9XJoKuA.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-number-C-5m3qt5.js → chart-kpi-number-C29Vj2g8.js} +2 -2
- package/dist/client/chunks/{chart-kpi-number-C-5m3qt5.js.map → chart-kpi-number-C29Vj2g8.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-text--t4ibPmx.js → chart-kpi-text-CgjjrurK.js} +2 -2
- package/dist/client/chunks/{chart-kpi-text--t4ibPmx.js.map → chart-kpi-text-CgjjrurK.js.map} +1 -1
- package/dist/client/chunks/{charts-loader-DcFWOUeV.js → charts-loader-HYQFVOo4.js} +13 -12
- package/dist/client/chunks/charts-loader-HYQFVOo4.js.map +1 -0
- package/dist/client/chunks/{components-Bdt1AmzS.js → components-O0hh7ooo.js} +5 -5
- package/dist/client/chunks/components-O0hh7ooo.js.map +1 -0
- package/dist/client/chunks/{icons-DRreo6m8.js → icons-DAeqv1iX.js} +7 -7
- package/dist/client/chunks/{icons-DRreo6m8.js.map → icons-DAeqv1iX.js.map} +1 -1
- package/dist/client/components/charts/BoxPlotChart.config.d.ts +11 -0
- package/dist/client/components/charts/BoxPlotChart.d.ts +4 -0
- package/dist/client/components/charts/index.d.ts +1 -0
- package/dist/client/components.js +1 -1
- package/dist/client/icons.js +1 -1
- package/dist/client/index.js +7 -7
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +1 -1
- package/dist/client/utils.js +3 -3
- package/dist/client-bundle-stats.html +4 -4
- package/dist/server/index.cjs +118 -102
- package/dist/server/index.js +6161 -4739
- package/package.json +6 -6
- package/dist/adapters/handler-D6l8AbJV.cjs +0 -7
- package/dist/adapters/handler-DsNgnIPK.js +0 -458
- package/dist/client/chunks/RetentionCombinedChart.config-C-ILIaEb.js.map +0 -1
- package/dist/client/chunks/RetentionHeatmap.config-CIvhc-GT.js.map +0 -1
- package/dist/client/chunks/analysis-builder-Dn8xpgPQ.js.map +0 -1
- package/dist/client/chunks/chart-config-activity-grid-CAlo1cHA.js.map +0 -1
- package/dist/client/chunks/chart-config-area-CyyJOO2T.js.map +0 -1
- package/dist/client/chunks/chart-config-bar-soxw6m2o.js.map +0 -1
- package/dist/client/chunks/chart-config-bubble-CuSsCHZ4.js.map +0 -1
- package/dist/client/chunks/chart-config-data-table-BhgqwoqT.js.map +0 -1
- package/dist/client/chunks/chart-config-funnel-BlSQYng0.js.map +0 -1
- package/dist/client/chunks/chart-config-heat-map-DHQGFZhX.js.map +0 -1
- package/dist/client/chunks/chart-config-kpi-delta-yTA5ug_l.js.map +0 -1
- package/dist/client/chunks/chart-config-kpi-number-nVAwDXzq.js.map +0 -1
- package/dist/client/chunks/chart-config-kpi-text-DZjqsx-b.js.map +0 -1
- package/dist/client/chunks/chart-config-line-D5ME6w0v.js.map +0 -1
- package/dist/client/chunks/chart-config-markdown-BXKL5TbQ.js.map +0 -1
- package/dist/client/chunks/chart-config-pie-DlHa2jTy.js.map +0 -1
- package/dist/client/chunks/chart-config-radar-BBAVIF0S.js.map +0 -1
- package/dist/client/chunks/chart-config-radial-bar-CTwjDRnB.js.map +0 -1
- package/dist/client/chunks/chart-config-sankey-CNAgsMQ4.js.map +0 -1
- package/dist/client/chunks/chart-config-scatter-CWvN2E-X.js.map +0 -1
- package/dist/client/chunks/chart-config-sunburst-W_SKwaj0.js.map +0 -1
- package/dist/client/chunks/chart-config-tree-map-IRAYf9YM.js.map +0 -1
- package/dist/client/chunks/chartConfigRegistry-C5dZm-ZK.js +0 -44
- package/dist/client/chunks/chartConfigRegistry-C5dZm-ZK.js.map +0 -1
- package/dist/client/chunks/charts-loader-DcFWOUeV.js.map +0 -1
- package/dist/client/chunks/components-Bdt1AmzS.js.map +0 -1
package/dist/client/chunks/{chart-activity-grid-DStNr34n.js → chart-activity-grid-CE7xGFQo.js}
RENAMED
|
@@ -277,7 +277,7 @@ const Ge = we.memo(function({
|
|
|
277
277
|
for (const [r, a] of t)
|
|
278
278
|
if (a.length > 0) {
|
|
279
279
|
const l = Math.min(...a.map((M) => Y.get(M) || 0)), w = Math.max(...a.map((M) => Y.get(M) || 0)), g = (l + w) / 2;
|
|
280
|
-
let c
|
|
280
|
+
let c;
|
|
281
281
|
if (r > 9999) {
|
|
282
282
|
const M = Math.floor(r / 100), pe = r % 100;
|
|
283
283
|
c = `${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][pe - 1]} '${M.toString().slice(-2)}`;
|
|
@@ -344,4 +344,4 @@ const Ge = we.memo(function({
|
|
|
344
344
|
export {
|
|
345
345
|
Ge as default
|
|
346
346
|
};
|
|
347
|
-
//# sourceMappingURL=chart-activity-grid-
|
|
347
|
+
//# sourceMappingURL=chart-activity-grid-CE7xGFQo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-activity-grid-DStNr34n.js","sources":["../../../src/client/components/charts/ActivityGridChart.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef, useState, useMemo, useCallback } from 'react'\nimport { select, scaleQuantize, max, min, transition as _transition } from 'd3'\n// _transition import is for side effects only - it extends Selection.prototype with .transition() method\nimport { CHART_COLORS_GRADIENT, CHART_MARGINS } from '../../utils/chartConstants'\nimport { formatTimeValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport { getTheme, watchThemeChanges, type Theme } from '../../theme'\nimport type { ChartProps } from '../../types'\n\ninterface GridCell {\n x: number\n y: number\n value: number\n date: Date\n label: string\n}\n\ninterface GridMapping {\n extractX: (date: Date) => number\n extractY: (date: Date) => number\n xLabels: string[]\n yLabels: string[]\n xFormat: (value: number) => string\n yFormat: (value: number) => string\n cellWidth: number\n cellHeight: number\n hasHierarchicalLabels?: boolean\n getYearFromX?: (value: number) => number\n}\n\nconst ActivityGridChart = React.memo(function ActivityGridChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n onDataPointClick,\n drillEnabled\n}: ChartProps) {\n const svgRef = useRef<SVGSVGElement | null>(null)\n const containerRef = useRef<HTMLDivElement | null>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n const [dimensionsReady, setDimensionsReady] = useState(false)\n const [currentTheme, setCurrentTheme] = useState<Theme>('light')\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n // Watch for theme changes\n useEffect(() => {\n setCurrentTheme(getTheme())\n const unwatch = watchThemeChanges((theme) => {\n setCurrentTheme(theme)\n })\n return unwatch\n }, [])\n\n const safeDisplayConfig = useMemo(() => ({\n showTooltip: displayConfig?.showTooltip ?? true,\n showLabels: displayConfig?.showLabels ?? true,\n fitToWidth: displayConfig?.fitToWidth ?? false\n }), [displayConfig?.showTooltip, displayConfig?.showLabels, displayConfig?.fitToWidth])\n\n // Enhanced dimension measurement with retry mechanism\n useLayoutEffect(() => {\n let retryCount = 0\n const maxRetries = 10\n let rafId: number\n let timeoutId: ReturnType<typeof setTimeout>\n \n const updateDimensions = () => {\n if (containerRef.current) {\n const { width, height } = containerRef.current.getBoundingClientRect()\n \n if (width > 0 && height > 0) {\n setDimensions({ width, height })\n setDimensionsReady(true)\n return true\n }\n }\n return false\n }\n \n const success = updateDimensions()\n \n if (!success && retryCount < maxRetries) {\n const retryWithRaf = () => {\n const rafSuccess = updateDimensions()\n \n if (!rafSuccess && retryCount < maxRetries) {\n retryCount++\n timeoutId = setTimeout(() => {\n rafId = requestAnimationFrame(retryWithRaf)\n }, 50 * retryCount)\n }\n }\n \n rafId = requestAnimationFrame(retryWithRaf)\n }\n \n return () => {\n if (rafId) cancelAnimationFrame(rafId)\n if (timeoutId) clearTimeout(timeoutId)\n }\n }, [])\n\n // ResizeObserver for dynamic resizing\n useEffect(() => {\n let resizeObserver: ResizeObserver | null = null\n \n const updateDimensions = () => {\n if (containerRef.current) {\n const { width, height } = containerRef.current.getBoundingClientRect()\n if (width > 0 && height > 0) {\n setDimensions({ width, height })\n if (!dimensionsReady) {\n setDimensionsReady(true)\n }\n }\n }\n }\n \n if (containerRef.current) {\n resizeObserver = new ResizeObserver(() => updateDimensions())\n resizeObserver.observe(containerRef.current)\n updateDimensions()\n }\n\n window.addEventListener('resize', updateDimensions)\n \n return () => {\n if (resizeObserver) {\n resizeObserver.disconnect()\n }\n window.removeEventListener('resize', updateDimensions)\n }\n }, [dimensionsReady])\n\n // Helper functions for grid coordinate extraction\n const getQuarter = (date: Date): number => {\n return Math.floor(date.getMonth() / 3) + 1 // 1-4\n }\n\n const getMonthOfQuarter = (date: Date): number => {\n return (date.getMonth() % 3) + 1 // 1-3\n }\n\n const getWeekOfMonth = (date: Date): number => {\n // Always start from week 1 for the first week of the month, regardless of day offset\n const dayOfMonth = date.getDate()\n return Math.floor((dayOfMonth - 1) / 7) + 1 // 1-5 typically\n }\n\n // Get granularity mapping based on time dimension\n const getGridMapping = useCallback((granularity: string): GridMapping | null => {\n switch (granularity?.toLowerCase()) {\n case 'year':\n // Year granularity is not useful for activity grids\n return null\n \n case 'quarter':\n // Quarter granularity: years × quarters\n return {\n extractX: (date: Date) => date.getFullYear(),\n extractY: (date: Date) => getQuarter(date) - 1, // 0-3 for indexing\n xLabels: [], // Will be determined from data\n yLabels: ['Q1', 'Q2', 'Q3', 'Q4'],\n xFormat: (value: number) => `'${value.toString().slice(-2)}`, // '24 instead of 2024\n yFormat: (value: number) => ['Q1', 'Q2', 'Q3', 'Q4'][value] || '',\n cellWidth: 16,\n cellHeight: 16\n }\n \n case 'month':\n // Month granularity: quarters × months of quarter\n // Show years above and quarters (Q1, Q2, Q3, Q4) as columns with hierarchical labels\n return {\n extractX: (date: Date) => {\n const year = date.getFullYear()\n const quarter = getQuarter(date) // 1-4\n return year * 10 + quarter // e.g., 20241, 20242, 20243, 20244 (only 4 per year)\n },\n extractY: (date: Date) => getMonthOfQuarter(date) - 1, // 0-2 for indexing\n xLabels: [], // Will be determined from data\n yLabels: ['Month 1', 'Month 2', 'Month 3'],\n xFormat: (value: number) => {\n const quarter = value % 10\n return `Q${quarter}` // Just show Q1, Q2, Q3, Q4 for individual columns\n },\n yFormat: (value: number) => ['Month 1', 'Month 2', 'Month 3'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Flag to indicate we need special handling\n getYearFromX: (value: number) => Math.floor(value / 10) // Helper to get year for grouping\n }\n \n case 'week':\n // Week granularity: months × weeks of month (same structure as quarters but with months as columns)\n return {\n extractX: (date: Date) => {\n const year = date.getFullYear()\n const month = date.getMonth() + 1\n return year * 100 + month // e.g., 202401, 202402, etc.\n },\n extractY: (date: Date) => getWeekOfMonth(date) - 1, // 0-5 for indexing\n xLabels: [], // Will be determined from data\n yLabels: ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5'],\n xFormat: (value: number) => {\n const month = value % 100\n const monthNames = ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']\n return monthNames[month - 1] || ''\n },\n yFormat: (value: number) => ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Add hierarchical labels like month view\n getYearFromX: (value: number) => Math.floor(value / 100) // Helper to get year for grouping\n }\n \n case 'day':\n // Day granularity: weeks × days of week with hierarchical year/week labels\n return {\n extractX: (date: Date) => {\n const { year, week } = getWeekOfYear(date)\n return year * 100 + week // e.g., 202401, 202402, etc.\n },\n extractY: (date: Date) => date.getDay(), // 0-6 (Sun-Sat)\n xLabels: [], // Will be determined from data\n yLabels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n xFormat: (value: number) => {\n const week = value % 100\n return `${week}`\n },\n yFormat: (value: number) => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Add hierarchical labels\n getYearFromX: (value: number) => Math.floor(value / 100) // Helper to get year for grouping\n }\n\n case 'hour':\n // Hour granularity: days × 3-hour blocks with hierarchical year/month labels\n return {\n extractX: (date: Date) => {\n // Get day as YYYYMMDD number for unique day identification\n const year = date.getFullYear()\n const month = date.getMonth() + 1\n const day = date.getDate()\n return year * 10000 + month * 100 + day // e.g., 20240115\n },\n extractY: (date: Date) => Math.floor(date.getHours() / 3), // 0-7 for 8 three-hour blocks\n xLabels: [], // Will be determined from data\n yLabels: ['00-03', '03-06', '06-09', '09-12', '12-15', '15-18', '18-21', '21-00'],\n xFormat: (value: number) => {\n // Format YYYYMMDD as just the day number\n const day = value % 100\n return `${day}`\n },\n yFormat: (value: number) => ['00-03', '03-06', '06-09', '09-12', '12-15', '15-18', '18-21', '21-00'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Show year/month grouping above\n getYearFromX: (value: number) => Math.floor(value / 100) // Extract YYYYMM for month grouping\n }\n\n default:\n return null\n }\n }, [])\n\n // Helper function to get week of year with correct year (1-53)\n const getWeekOfYear = (date: Date): { year: number, week: number } => {\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))\n const dayNum = d.getUTCDay() || 7\n d.setUTCDate(d.getUTCDate() + 4 - dayNum)\n const year = d.getUTCFullYear()\n const yearStart = new Date(Date.UTC(year, 0, 1))\n const week = Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7)\n return { year, week }\n }\n\n useEffect(() => {\n if (!data || data.length === 0 || !svgRef.current || !dimensionsReady || dimensions.width === 0) {\n return\n }\n\n // Clear previous chart\n select(svgRef.current).selectAll('*').remove()\n\n // Validate chartConfig\n if (!chartConfig?.dateField || !chartConfig?.valueField) {\n return\n }\n\n const dateField = Array.isArray(chartConfig.dateField) ? chartConfig.dateField[0] : chartConfig.dateField\n const valueField = Array.isArray(chartConfig.valueField) ? chartConfig.valueField[0] : chartConfig.valueField\n\n\n if (!dateField || !valueField) {\n return\n }\n\n // Get granularity directly from the query's time dimensions\n const getQueryGranularity = () => {\n if (!queryObject?.timeDimensions || queryObject.timeDimensions.length === 0) {\n return 'day'\n }\n \n // Find the time dimension that matches our dateField\n const timeDim = queryObject.timeDimensions.find((td: any) => \n td.dimension === dateField || td.dimension.includes(dateField)\n )\n \n if (timeDim && timeDim.granularity) {\n return timeDim.granularity\n }\n \n // Fallback to first time dimension's granularity\n const firstTimeDim = queryObject.timeDimensions[0]\n if (firstTimeDim && firstTimeDim.granularity) {\n return firstTimeDim.granularity\n }\n \n return 'day'\n }\n \n const queryGranularity = getQueryGranularity()\n const gridMapping = getGridMapping(queryGranularity)\n \n // Handle unsupported granularity\n if (!gridMapping) {\n return\n }\n \n\n // Transform data for grid\n const gridData: GridCell[] = data.map(item => {\n const dateValue = item[dateField]\n const value = typeof item[valueField] === 'string' \n ? parseFloat(item[valueField]) \n : (item[valueField] || 0)\n \n // Parse the date\n let date: Date\n if (typeof dateValue === 'string') {\n // Handle different date formats\n let isoStr = dateValue\n if (dateValue.includes(' ')) {\n isoStr = dateValue.replace(' ', 'T').replace('+00', 'Z').replace(/\\+\\d{2}:\\d{2}$/, 'Z')\n }\n if (!isoStr.endsWith('Z') && !isoStr.includes('+')) {\n isoStr = isoStr + 'Z'\n }\n date = new Date(isoStr)\n } else {\n date = new Date(dateValue)\n }\n\n // Skip invalid dates\n if (isNaN(date.getTime())) {\n return null\n }\n\n const x = gridMapping.extractX(date)\n const y = gridMapping.extractY(date)\n \n return {\n x,\n y,\n value,\n date,\n label: formatTimeValue(dateValue, queryGranularity)\n }\n }).filter((cell): cell is GridCell => cell !== null)\n\n\n if (gridData.length === 0) return\n\n // Calculate grid dimensions\n const maxY = max(gridData, d => d.y) || 0\n const minY = min(gridData, d => d.y) || 0\n\n\n // Generate complete X range first so we can calculate proper grid width\n const getCompleteXRange = (): number[] => {\n const dataXValues = [...new Set(gridData.map(cell => cell.x))].sort()\n \n if (queryGranularity === 'quarter') {\n // For quarters: only show quarters that have data to avoid gaps\n return dataXValues\n }\n \n if (queryGranularity === 'month') {\n // For months: only show quarters that have data to avoid gaps\n return dataXValues\n }\n \n if (queryGranularity === 'week') {\n // For weeks: only show months that have data to avoid gaps\n return dataXValues\n }\n \n if (queryGranularity === 'day') {\n // For days: only show the actual weeks that have data to avoid discontinuities\n return dataXValues\n }\n \n // For other granularities, use the actual data values\n return dataXValues\n }\n \n const completeXRange = getCompleteXRange()\n \n // Calculate grid dimensions based on complete X range\n const gridWidth = completeXRange.length * gridMapping.cellWidth + (completeXRange.length - 1) * 4\n const gridHeight = (maxY - minY + 1) * gridMapping.cellHeight + (maxY - minY) * 4\n\n const margin = { \n ...CHART_MARGINS, \n left: 60, // Space for Y-axis labels\n bottom: 10, // Reduced since labels are at top\n top: gridMapping.hasHierarchicalLabels ? 40 : 25, // Extra space for hierarchical labels\n right: 10\n }\n \n const availableWidth = dimensions.width - margin.left - margin.right\n const availableHeight = dimensions.height - margin.top - margin.bottom\n\n // Scale the grid to fit the available space\n let finalCellWidth: number\n let finalCellHeight: number\n\n if (safeDisplayConfig.fitToWidth) {\n // Fit to Width mode: Calculate cell size to perfectly fit both dimensions\n // Remove min/max constraints and let blocks scale to optimal size\n const scaleX = availableWidth / gridWidth\n const scaleY = availableHeight / gridHeight\n const scale = Math.min(scaleX, scaleY)\n\n // Use the scale to calculate cell size, maintaining 1:1 aspect ratio\n finalCellWidth = gridMapping.cellWidth * scale\n finalCellHeight = gridMapping.cellHeight * scale\n } else {\n // Default mode: Use minimum/maximum size constraints with scrolling\n const getMinCellSize = () => {\n return { width: 16, height: 16 } // Same size for all views\n }\n\n const minCellSize = getMinCellSize()\n const maxCellSize = 24\n\n const scaleX = availableWidth / gridWidth\n const scaleY = availableHeight / gridHeight\n const scale = Math.min(scaleX, scaleY)\n\n // Calculate final cell size with constraints\n finalCellWidth = Math.max(minCellSize.width, Math.min(maxCellSize, gridMapping.cellWidth * scale))\n finalCellHeight = Math.max(minCellSize.height, Math.min(maxCellSize, gridMapping.cellHeight * scale))\n\n // For week view, prefer scrolling over tiny cells\n if (queryGranularity === 'week' && finalCellWidth < minCellSize.width) {\n finalCellWidth = minCellSize.width\n }\n }\n \n // Calculate actual grid dimensions with the final cell sizes\n const actualGridWidth = completeXRange.length * finalCellWidth + (completeXRange.length - 1) * 4\n \n // Determine if we need horizontal scrolling\n const needsHorizontalScroll = actualGridWidth > availableWidth\n const svgWidth = needsHorizontalScroll ? actualGridWidth + margin.left + margin.right : dimensions.width\n \n\n const svg = select(svgRef.current)\n .attr('width', svgWidth)\n .attr('height', dimensions.height)\n\n const g = svg.append('g')\n .attr('transform', `translate(${margin.left},${margin.top})`)\n\n // Set up color scale\n const values = gridData.map(d => d.value)\n const minValue = min(values) || 0\n const maxValue = max(values) || 1\n\n const colorScale = scaleQuantize<string>()\n .domain([minValue, maxValue])\n .range(colorPalette?.gradient || CHART_COLORS_GRADIENT)\n\n // Create grid data map for quick lookup\n const gridMap = new Map<string, GridCell>()\n gridData.forEach(cell => {\n const key = `${cell.x}-${cell.y}`\n gridMap.set(key, cell)\n })\n\n // Get theme colors from CSS variables\n const getThemeColor = (varName: string, fallback: string) => {\n const value = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()\n return value || fallback\n }\n\n const isDark = currentTheme !== 'light'\n const textColor = isDark\n ? getThemeColor('--dc-text-muted', '#cbd5e1') // Lighter text for dark mode\n : getThemeColor('--dc-text-secondary', '#374151') // Darker text for light mode\n const lineColor = getThemeColor('--dc-border', '#e5e7eb')\n // Use theme-aware colors for empty cells: light gray in light mode, slightly lighter than bg in dark mode\n const emptyCellColor = isDark\n ? getThemeColor('--dc-bg-secondary', '#1e293b') // Slightly lighter than dark background\n : getThemeColor('--dc-bg-secondary', '#f3f4f6') // Very light gray in light mode\n const cellStrokeColor = isDark\n ? getThemeColor('--dc-border', '#334155') // Subtle border in dark mode\n : getThemeColor('--dc-bg', '#ffffff') // White border in light mode\n\n // Create tooltip\n const tooltip = select('body').append('div')\n .attr('class', 'activity-grid-tooltip')\n .style('position', 'absolute')\n .style('padding', '8px')\n .style('background', 'rgba(0, 0, 0, 0.8)')\n .style('color', 'white')\n .style('border-radius', '4px')\n .style('font-size', '12px')\n .style('pointer-events', 'none')\n .style('opacity', 0)\n .style('z-index', 1000)\n\n // Create a mapping from X values to their position indices for proper spacing\n const xValueToIndex = new Map<number, number>()\n completeXRange.forEach((x, index) => {\n xValueToIndex.set(x, index)\n })\n \n // Render grid cells for the complete X range\n for (const x of completeXRange) {\n for (let y = minY; y <= maxY; y++) {\n const key = `${x}-${y}`\n const cell = gridMap.get(key)\n const xIndex = xValueToIndex.get(x) || 0\n \n const rect = g.append('rect')\n .attr('x', xIndex * (finalCellWidth + 4))\n .attr('y', (y - minY) * (finalCellHeight + 4))\n .attr('width', finalCellWidth)\n .attr('height', finalCellHeight)\n .attr('rx', 2)\n .attr('ry', 2)\n .style('fill', cell ? colorScale(cell.value) : emptyCellColor)\n .style('stroke', cellStrokeColor)\n .style('stroke-width', 1)\n\n // Add hover effects and tooltips\n if (safeDisplayConfig.showTooltip) {\n rect\n .style('cursor', drillEnabled ? 'pointer' : 'default')\n .on('mouseover', function(event) {\n select(this)\n .style('stroke', '#000')\n .style('stroke-width', 2)\n\n if (cell) {\n const tooltipContent = [\n `<strong>${cell.label}</strong>`,\n `${getFieldLabel(valueField)}: ${cell.value}`\n ].join('<br>')\n\n tooltip\n .html(tooltipContent)\n .style('left', (event.pageX + 10) + 'px')\n .style('top', (event.pageY - 10) + 'px')\n .transition()\n .duration(200)\n .style('opacity', 1)\n }\n })\n .on('mousemove', function(event) {\n tooltip\n .style('left', (event.pageX + 10) + 'px')\n .style('top', (event.pageY - 10) + 'px')\n })\n .on('mouseout', function() {\n select(this)\n .style('stroke', cellStrokeColor)\n .style('stroke-width', 1)\n\n tooltip\n .transition()\n .duration(200)\n .style('opacity', 0)\n })\n } else if (drillEnabled) {\n // Set cursor for drill even without tooltips\n rect.style('cursor', 'pointer')\n }\n\n // Add drill click handler\n if (drillEnabled && onDataPointClick && cell) {\n rect.on('click', function(event) {\n onDataPointClick({\n dataPoint: { [valueField]: cell.value, [dateField]: cell.date },\n clickedField: valueField,\n xValue: cell.label,\n position: { x: event.pageX, y: event.pageY },\n nativeEvent: event as unknown as React.MouseEvent\n })\n })\n }\n }\n }\n\n // Add axis labels if enabled\n if (safeDisplayConfig.showLabels) {\n if (gridMapping.hasHierarchicalLabels && gridMapping.getYearFromX) {\n // Special handling for quarter view with hierarchical labels\n // Use the complete X range to show all quarters/months\n \n // Group quarters by year\n const yearGroups = new Map<number, number[]>()\n for (const x of completeXRange) {\n const year = gridMapping.getYearFromX(x)\n if (!yearGroups.has(year)) {\n yearGroups.set(year, [])\n }\n yearGroups.get(year)!.push(x)\n }\n \n \n // Draw column labels (Q1-Q4 for months, Jan-Dec for weeks)\n for (const x of completeXRange) {\n const xIndex = xValueToIndex.get(x) || 0\n g.append('text')\n .attr('x', xIndex * (finalCellWidth + 4) + finalCellWidth / 2)\n .attr('y', -8)\n .attr('text-anchor', 'middle')\n .style('font-size', '10px')\n .style('fill', textColor)\n .text(gridMapping.xFormat(x))\n }\n\n // Draw year group labels above quarters\n for (const [year, xValues] of yearGroups) {\n if (xValues.length > 0) {\n // Get the index positions for proper spacing\n const startIndex = Math.min(...xValues.map(x => xValueToIndex.get(x) || 0))\n const endIndex = Math.max(...xValues.map(x => xValueToIndex.get(x) || 0))\n const centerIndex = (startIndex + endIndex) / 2\n\n // Year label (or year/month for hour granularity)\n let labelText = ''\n if (year > 9999) {\n // For hour granularity, year is encoded as YYYYMM\n const actualYear = Math.floor(year / 100)\n const month = year % 100\n const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\n labelText = `${monthNames[month - 1]} '${actualYear.toString().slice(-2)}`\n } else {\n // For other granularities, just show the year\n labelText = `'${year.toString().slice(-2)}`\n }\n\n g.append('text')\n .attr('x', centerIndex * (finalCellWidth + 4) + finalCellWidth / 2)\n .attr('y', -25)\n .attr('text-anchor', 'middle')\n .style('font-size', '12px')\n .style('font-weight', 'bold')\n .style('fill', textColor)\n .text(labelText)\n\n // Optional: Add a subtle line to group quarters under the year\n if (xValues.length > 1) {\n g.append('line')\n .attr('x1', startIndex * (finalCellWidth + 4))\n .attr('x2', endIndex * (finalCellWidth + 4) + finalCellWidth)\n .attr('y1', -20)\n .attr('y2', -20)\n .style('stroke', lineColor)\n .style('stroke-width', 1)\n .style('opacity', 0.3)\n }\n }\n }\n } else {\n // Regular X-axis labels for other granularities\n const xLabelStep = Math.max(1, Math.floor(completeXRange.length / 10))\n for (let i = 0; i < completeXRange.length; i += xLabelStep) {\n const x = completeXRange[i]\n g.append('text')\n .attr('x', i * (finalCellWidth + 4) + finalCellWidth / 2)\n .attr('y', -8)\n .attr('text-anchor', 'middle')\n .style('font-size', '10px')\n .style('fill', textColor)\n .text(gridMapping.xFormat(x))\n }\n }\n\n // Y-axis labels (left) - same for all granularities\n for (let y = minY; y <= maxY; y++) {\n g.append('text')\n .attr('x', -8)\n .attr('y', (y - minY) * (finalCellHeight + 4) + finalCellHeight / 2)\n .attr('text-anchor', 'end')\n .attr('dy', '.35em')\n .style('font-size', '10px')\n .style('fill', textColor)\n .text(gridMapping.yFormat(y))\n }\n }\n\n // Cleanup function\n return () => {\n tooltip.remove()\n }\n }, [data, chartConfig, displayConfig, queryObject, dimensions, dimensionsReady, safeDisplayConfig, colorPalette, currentTheme, getFieldLabel, getGridMapping, drillEnabled, onDataPointClick])\n\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display in activity grid</div>\n </div>\n </div>\n )\n }\n\n // Validate that we have required fields\n const hasValidConfig = chartConfig?.dateField && chartConfig?.valueField\n if (!hasValidConfig) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Required</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Activity grid requires a time dimension and a measure</div>\n </div>\n </div>\n )\n }\n\n // Check if granularity is supported\n const dateField = Array.isArray(chartConfig.dateField) ? chartConfig.dateField[0] : chartConfig.dateField\n const granularityFromQuery = queryObject?.timeDimensions?.find((td: any) => \n td.dimension === dateField || td.dimension.includes(dateField)\n )?.granularity || 'day'\n \n if (granularityFromQuery?.toLowerCase() === 'year') {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Granularity Too High</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Activity grids work best with hour, day, week, month, or quarter granularity</div>\n <div className=\"dc:text-xs text-dc-text-secondary dc:mt-1\">Please choose a lower granularity for your time dimension</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:flex dc:flex-col dc:relative\" style={{ height, minHeight: '250px', overflow: 'hidden', width: '100%' }}>\n <div ref={containerRef} className=\"dc:w-full dc:h-full dc:relative dc:overflow-x-auto\" style={{ width: '100%' }}>\n <svg ref={svgRef} className=\"dc:h-full\" />\n {!dimensionsReady && (\n <div className=\"dc:absolute dc:inset-0 dc:flex dc:items-center dc:justify-center\">\n <div className=\"text-dc-text-muted dc:text-sm\">Measuring chart dimensions...</div>\n </div>\n )}\n </div>\n </div>\n )\n})\n\nexport default ActivityGridChart"],"names":["ActivityGridChart","React","data","chartConfig","displayConfig","queryObject","height","colorPalette","onDataPointClick","drillEnabled","svgRef","useRef","containerRef","dimensions","setDimensions","useState","dimensionsReady","setDimensionsReady","currentTheme","setCurrentTheme","getFieldLabel","useCubeFieldLabel","useEffect","getTheme","watchThemeChanges","theme","safeDisplayConfig","useMemo","useLayoutEffect","retryCount","maxRetries","rafId","timeoutId","updateDimensions","width","retryWithRaf","resizeObserver","getQuarter","date","getMonthOfQuarter","getWeekOfMonth","dayOfMonth","getGridMapping","useCallback","granularity","value","year","quarter","month","week","getWeekOfYear","day","d","dayNum","yearStart","select","dateField","valueField","queryGranularity","timeDim","td","firstTimeDim","gridMapping","gridData","item","dateValue","isoStr","x","y","formatTimeValue","cell","maxY","max","minY","min","completeXRange","dataXValues","gridWidth","gridHeight","margin","availableWidth","availableHeight","finalCellWidth","finalCellHeight","scaleX","scaleY","scale","minCellSize","maxCellSize","actualGridWidth","svgWidth","g","values","minValue","maxValue","colorScale","scaleQuantize","CHART_COLORS_GRADIENT","gridMap","key","getThemeColor","varName","fallback","isDark","textColor","lineColor","emptyCellColor","cellStrokeColor","tooltip","xValueToIndex","index","xIndex","rect","event","tooltipContent","yearGroups","xValues","startIndex","endIndex","centerIndex","labelText","actualYear","xLabelStep","i","jsx","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-activity-grid-CE7xGFQo.js","sources":["../../../src/client/components/charts/ActivityGridChart.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef, useState, useMemo, useCallback } from 'react'\nimport { select, scaleQuantize, max, min, transition as _transition } from 'd3'\n// _transition import is for side effects only - it extends Selection.prototype with .transition() method\nimport { CHART_COLORS_GRADIENT, CHART_MARGINS } from '../../utils/chartConstants'\nimport { formatTimeValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport { getTheme, watchThemeChanges, type Theme } from '../../theme'\nimport type { ChartProps } from '../../types'\n\ninterface GridCell {\n x: number\n y: number\n value: number\n date: Date\n label: string\n}\n\ninterface GridMapping {\n extractX: (date: Date) => number\n extractY: (date: Date) => number\n xLabels: string[]\n yLabels: string[]\n xFormat: (value: number) => string\n yFormat: (value: number) => string\n cellWidth: number\n cellHeight: number\n hasHierarchicalLabels?: boolean\n getYearFromX?: (value: number) => number\n}\n\nconst ActivityGridChart = React.memo(function ActivityGridChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n onDataPointClick,\n drillEnabled\n}: ChartProps) {\n const svgRef = useRef<SVGSVGElement | null>(null)\n const containerRef = useRef<HTMLDivElement | null>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n const [dimensionsReady, setDimensionsReady] = useState(false)\n const [currentTheme, setCurrentTheme] = useState<Theme>('light')\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n // Watch for theme changes\n useEffect(() => {\n setCurrentTheme(getTheme())\n const unwatch = watchThemeChanges((theme) => {\n setCurrentTheme(theme)\n })\n return unwatch\n }, [])\n\n const safeDisplayConfig = useMemo(() => ({\n showTooltip: displayConfig?.showTooltip ?? true,\n showLabels: displayConfig?.showLabels ?? true,\n fitToWidth: displayConfig?.fitToWidth ?? false\n }), [displayConfig?.showTooltip, displayConfig?.showLabels, displayConfig?.fitToWidth])\n\n // Enhanced dimension measurement with retry mechanism\n useLayoutEffect(() => {\n let retryCount = 0\n const maxRetries = 10\n let rafId: number\n let timeoutId: ReturnType<typeof setTimeout>\n \n const updateDimensions = () => {\n if (containerRef.current) {\n const { width, height } = containerRef.current.getBoundingClientRect()\n \n if (width > 0 && height > 0) {\n setDimensions({ width, height })\n setDimensionsReady(true)\n return true\n }\n }\n return false\n }\n \n const success = updateDimensions()\n \n if (!success && retryCount < maxRetries) {\n const retryWithRaf = () => {\n const rafSuccess = updateDimensions()\n \n if (!rafSuccess && retryCount < maxRetries) {\n retryCount++\n timeoutId = setTimeout(() => {\n rafId = requestAnimationFrame(retryWithRaf)\n }, 50 * retryCount)\n }\n }\n \n rafId = requestAnimationFrame(retryWithRaf)\n }\n \n return () => {\n if (rafId) cancelAnimationFrame(rafId)\n if (timeoutId) clearTimeout(timeoutId)\n }\n }, [])\n\n // ResizeObserver for dynamic resizing\n useEffect(() => {\n let resizeObserver: ResizeObserver | null = null\n \n const updateDimensions = () => {\n if (containerRef.current) {\n const { width, height } = containerRef.current.getBoundingClientRect()\n if (width > 0 && height > 0) {\n setDimensions({ width, height })\n if (!dimensionsReady) {\n setDimensionsReady(true)\n }\n }\n }\n }\n \n if (containerRef.current) {\n resizeObserver = new ResizeObserver(() => updateDimensions())\n resizeObserver.observe(containerRef.current)\n updateDimensions()\n }\n\n window.addEventListener('resize', updateDimensions)\n \n return () => {\n if (resizeObserver) {\n resizeObserver.disconnect()\n }\n window.removeEventListener('resize', updateDimensions)\n }\n }, [dimensionsReady])\n\n // Helper functions for grid coordinate extraction\n const getQuarter = (date: Date): number => {\n return Math.floor(date.getMonth() / 3) + 1 // 1-4\n }\n\n const getMonthOfQuarter = (date: Date): number => {\n return (date.getMonth() % 3) + 1 // 1-3\n }\n\n const getWeekOfMonth = (date: Date): number => {\n // Always start from week 1 for the first week of the month, regardless of day offset\n const dayOfMonth = date.getDate()\n return Math.floor((dayOfMonth - 1) / 7) + 1 // 1-5 typically\n }\n\n // Get granularity mapping based on time dimension\n const getGridMapping = useCallback((granularity: string): GridMapping | null => {\n switch (granularity?.toLowerCase()) {\n case 'year':\n // Year granularity is not useful for activity grids\n return null\n \n case 'quarter':\n // Quarter granularity: years × quarters\n return {\n extractX: (date: Date) => date.getFullYear(),\n extractY: (date: Date) => getQuarter(date) - 1, // 0-3 for indexing\n xLabels: [], // Will be determined from data\n yLabels: ['Q1', 'Q2', 'Q3', 'Q4'],\n xFormat: (value: number) => `'${value.toString().slice(-2)}`, // '24 instead of 2024\n yFormat: (value: number) => ['Q1', 'Q2', 'Q3', 'Q4'][value] || '',\n cellWidth: 16,\n cellHeight: 16\n }\n \n case 'month':\n // Month granularity: quarters × months of quarter\n // Show years above and quarters (Q1, Q2, Q3, Q4) as columns with hierarchical labels\n return {\n extractX: (date: Date) => {\n const year = date.getFullYear()\n const quarter = getQuarter(date) // 1-4\n return year * 10 + quarter // e.g., 20241, 20242, 20243, 20244 (only 4 per year)\n },\n extractY: (date: Date) => getMonthOfQuarter(date) - 1, // 0-2 for indexing\n xLabels: [], // Will be determined from data\n yLabels: ['Month 1', 'Month 2', 'Month 3'],\n xFormat: (value: number) => {\n const quarter = value % 10\n return `Q${quarter}` // Just show Q1, Q2, Q3, Q4 for individual columns\n },\n yFormat: (value: number) => ['Month 1', 'Month 2', 'Month 3'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Flag to indicate we need special handling\n getYearFromX: (value: number) => Math.floor(value / 10) // Helper to get year for grouping\n }\n \n case 'week':\n // Week granularity: months × weeks of month (same structure as quarters but with months as columns)\n return {\n extractX: (date: Date) => {\n const year = date.getFullYear()\n const month = date.getMonth() + 1\n return year * 100 + month // e.g., 202401, 202402, etc.\n },\n extractY: (date: Date) => getWeekOfMonth(date) - 1, // 0-5 for indexing\n xLabels: [], // Will be determined from data\n yLabels: ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5'],\n xFormat: (value: number) => {\n const month = value % 100\n const monthNames = ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']\n return monthNames[month - 1] || ''\n },\n yFormat: (value: number) => ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Add hierarchical labels like month view\n getYearFromX: (value: number) => Math.floor(value / 100) // Helper to get year for grouping\n }\n \n case 'day':\n // Day granularity: weeks × days of week with hierarchical year/week labels\n return {\n extractX: (date: Date) => {\n const { year, week } = getWeekOfYear(date)\n return year * 100 + week // e.g., 202401, 202402, etc.\n },\n extractY: (date: Date) => date.getDay(), // 0-6 (Sun-Sat)\n xLabels: [], // Will be determined from data\n yLabels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n xFormat: (value: number) => {\n const week = value % 100\n return `${week}`\n },\n yFormat: (value: number) => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Add hierarchical labels\n getYearFromX: (value: number) => Math.floor(value / 100) // Helper to get year for grouping\n }\n\n case 'hour':\n // Hour granularity: days × 3-hour blocks with hierarchical year/month labels\n return {\n extractX: (date: Date) => {\n // Get day as YYYYMMDD number for unique day identification\n const year = date.getFullYear()\n const month = date.getMonth() + 1\n const day = date.getDate()\n return year * 10000 + month * 100 + day // e.g., 20240115\n },\n extractY: (date: Date) => Math.floor(date.getHours() / 3), // 0-7 for 8 three-hour blocks\n xLabels: [], // Will be determined from data\n yLabels: ['00-03', '03-06', '06-09', '09-12', '12-15', '15-18', '18-21', '21-00'],\n xFormat: (value: number) => {\n // Format YYYYMMDD as just the day number\n const day = value % 100\n return `${day}`\n },\n yFormat: (value: number) => ['00-03', '03-06', '06-09', '09-12', '12-15', '15-18', '18-21', '21-00'][value] || '',\n cellWidth: 16,\n cellHeight: 16,\n hasHierarchicalLabels: true, // Show year/month grouping above\n getYearFromX: (value: number) => Math.floor(value / 100) // Extract YYYYMM for month grouping\n }\n\n default:\n return null\n }\n }, [])\n\n // Helper function to get week of year with correct year (1-53)\n const getWeekOfYear = (date: Date): { year: number, week: number } => {\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))\n const dayNum = d.getUTCDay() || 7\n d.setUTCDate(d.getUTCDate() + 4 - dayNum)\n const year = d.getUTCFullYear()\n const yearStart = new Date(Date.UTC(year, 0, 1))\n const week = Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7)\n return { year, week }\n }\n\n useEffect(() => {\n if (!data || data.length === 0 || !svgRef.current || !dimensionsReady || dimensions.width === 0) {\n return\n }\n\n // Clear previous chart\n select(svgRef.current).selectAll('*').remove()\n\n // Validate chartConfig\n if (!chartConfig?.dateField || !chartConfig?.valueField) {\n return\n }\n\n const dateField = Array.isArray(chartConfig.dateField) ? chartConfig.dateField[0] : chartConfig.dateField\n const valueField = Array.isArray(chartConfig.valueField) ? chartConfig.valueField[0] : chartConfig.valueField\n\n\n if (!dateField || !valueField) {\n return\n }\n\n // Get granularity directly from the query's time dimensions\n const getQueryGranularity = () => {\n if (!queryObject?.timeDimensions || queryObject.timeDimensions.length === 0) {\n return 'day'\n }\n \n // Find the time dimension that matches our dateField\n const timeDim = queryObject.timeDimensions.find((td: any) => \n td.dimension === dateField || td.dimension.includes(dateField)\n )\n \n if (timeDim && timeDim.granularity) {\n return timeDim.granularity\n }\n \n // Fallback to first time dimension's granularity\n const firstTimeDim = queryObject.timeDimensions[0]\n if (firstTimeDim && firstTimeDim.granularity) {\n return firstTimeDim.granularity\n }\n \n return 'day'\n }\n \n const queryGranularity = getQueryGranularity()\n const gridMapping = getGridMapping(queryGranularity)\n \n // Handle unsupported granularity\n if (!gridMapping) {\n return\n }\n \n\n // Transform data for grid\n const gridData: GridCell[] = data.map(item => {\n const dateValue = item[dateField]\n const value = typeof item[valueField] === 'string' \n ? parseFloat(item[valueField]) \n : (item[valueField] || 0)\n \n // Parse the date\n let date: Date\n if (typeof dateValue === 'string') {\n // Handle different date formats\n let isoStr = dateValue\n if (dateValue.includes(' ')) {\n isoStr = dateValue.replace(' ', 'T').replace('+00', 'Z').replace(/\\+\\d{2}:\\d{2}$/, 'Z')\n }\n if (!isoStr.endsWith('Z') && !isoStr.includes('+')) {\n isoStr = isoStr + 'Z'\n }\n date = new Date(isoStr)\n } else {\n date = new Date(dateValue)\n }\n\n // Skip invalid dates\n if (isNaN(date.getTime())) {\n return null\n }\n\n const x = gridMapping.extractX(date)\n const y = gridMapping.extractY(date)\n \n return {\n x,\n y,\n value,\n date,\n label: formatTimeValue(dateValue, queryGranularity)\n }\n }).filter((cell): cell is GridCell => cell !== null)\n\n\n if (gridData.length === 0) return\n\n // Calculate grid dimensions\n const maxY = max(gridData, d => d.y) || 0\n const minY = min(gridData, d => d.y) || 0\n\n\n // Generate complete X range first so we can calculate proper grid width\n const getCompleteXRange = (): number[] => {\n const dataXValues = [...new Set(gridData.map(cell => cell.x))].sort()\n \n if (queryGranularity === 'quarter') {\n // For quarters: only show quarters that have data to avoid gaps\n return dataXValues\n }\n \n if (queryGranularity === 'month') {\n // For months: only show quarters that have data to avoid gaps\n return dataXValues\n }\n \n if (queryGranularity === 'week') {\n // For weeks: only show months that have data to avoid gaps\n return dataXValues\n }\n \n if (queryGranularity === 'day') {\n // For days: only show the actual weeks that have data to avoid discontinuities\n return dataXValues\n }\n \n // For other granularities, use the actual data values\n return dataXValues\n }\n \n const completeXRange = getCompleteXRange()\n \n // Calculate grid dimensions based on complete X range\n const gridWidth = completeXRange.length * gridMapping.cellWidth + (completeXRange.length - 1) * 4\n const gridHeight = (maxY - minY + 1) * gridMapping.cellHeight + (maxY - minY) * 4\n\n const margin = { \n ...CHART_MARGINS, \n left: 60, // Space for Y-axis labels\n bottom: 10, // Reduced since labels are at top\n top: gridMapping.hasHierarchicalLabels ? 40 : 25, // Extra space for hierarchical labels\n right: 10\n }\n \n const availableWidth = dimensions.width - margin.left - margin.right\n const availableHeight = dimensions.height - margin.top - margin.bottom\n\n // Scale the grid to fit the available space\n let finalCellWidth: number\n let finalCellHeight: number\n\n if (safeDisplayConfig.fitToWidth) {\n // Fit to Width mode: Calculate cell size to perfectly fit both dimensions\n // Remove min/max constraints and let blocks scale to optimal size\n const scaleX = availableWidth / gridWidth\n const scaleY = availableHeight / gridHeight\n const scale = Math.min(scaleX, scaleY)\n\n // Use the scale to calculate cell size, maintaining 1:1 aspect ratio\n finalCellWidth = gridMapping.cellWidth * scale\n finalCellHeight = gridMapping.cellHeight * scale\n } else {\n // Default mode: Use minimum/maximum size constraints with scrolling\n const getMinCellSize = () => {\n return { width: 16, height: 16 } // Same size for all views\n }\n\n const minCellSize = getMinCellSize()\n const maxCellSize = 24\n\n const scaleX = availableWidth / gridWidth\n const scaleY = availableHeight / gridHeight\n const scale = Math.min(scaleX, scaleY)\n\n // Calculate final cell size with constraints\n finalCellWidth = Math.max(minCellSize.width, Math.min(maxCellSize, gridMapping.cellWidth * scale))\n finalCellHeight = Math.max(minCellSize.height, Math.min(maxCellSize, gridMapping.cellHeight * scale))\n\n // For week view, prefer scrolling over tiny cells\n if (queryGranularity === 'week' && finalCellWidth < minCellSize.width) {\n finalCellWidth = minCellSize.width\n }\n }\n \n // Calculate actual grid dimensions with the final cell sizes\n const actualGridWidth = completeXRange.length * finalCellWidth + (completeXRange.length - 1) * 4\n \n // Determine if we need horizontal scrolling\n const needsHorizontalScroll = actualGridWidth > availableWidth\n const svgWidth = needsHorizontalScroll ? actualGridWidth + margin.left + margin.right : dimensions.width\n \n\n const svg = select(svgRef.current)\n .attr('width', svgWidth)\n .attr('height', dimensions.height)\n\n const g = svg.append('g')\n .attr('transform', `translate(${margin.left},${margin.top})`)\n\n // Set up color scale\n const values = gridData.map(d => d.value)\n const minValue = min(values) || 0\n const maxValue = max(values) || 1\n\n const colorScale = scaleQuantize<string>()\n .domain([minValue, maxValue])\n .range(colorPalette?.gradient || CHART_COLORS_GRADIENT)\n\n // Create grid data map for quick lookup\n const gridMap = new Map<string, GridCell>()\n gridData.forEach(cell => {\n const key = `${cell.x}-${cell.y}`\n gridMap.set(key, cell)\n })\n\n // Get theme colors from CSS variables\n const getThemeColor = (varName: string, fallback: string) => {\n const value = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()\n return value || fallback\n }\n\n const isDark = currentTheme !== 'light'\n const textColor = isDark\n ? getThemeColor('--dc-text-muted', '#cbd5e1') // Lighter text for dark mode\n : getThemeColor('--dc-text-secondary', '#374151') // Darker text for light mode\n const lineColor = getThemeColor('--dc-border', '#e5e7eb')\n // Use theme-aware colors for empty cells: light gray in light mode, slightly lighter than bg in dark mode\n const emptyCellColor = isDark\n ? getThemeColor('--dc-bg-secondary', '#1e293b') // Slightly lighter than dark background\n : getThemeColor('--dc-bg-secondary', '#f3f4f6') // Very light gray in light mode\n const cellStrokeColor = isDark\n ? getThemeColor('--dc-border', '#334155') // Subtle border in dark mode\n : getThemeColor('--dc-bg', '#ffffff') // White border in light mode\n\n // Create tooltip\n const tooltip = select('body').append('div')\n .attr('class', 'activity-grid-tooltip')\n .style('position', 'absolute')\n .style('padding', '8px')\n .style('background', 'rgba(0, 0, 0, 0.8)')\n .style('color', 'white')\n .style('border-radius', '4px')\n .style('font-size', '12px')\n .style('pointer-events', 'none')\n .style('opacity', 0)\n .style('z-index', 1000)\n\n // Create a mapping from X values to their position indices for proper spacing\n const xValueToIndex = new Map<number, number>()\n completeXRange.forEach((x, index) => {\n xValueToIndex.set(x, index)\n })\n \n // Render grid cells for the complete X range\n for (const x of completeXRange) {\n for (let y = minY; y <= maxY; y++) {\n const key = `${x}-${y}`\n const cell = gridMap.get(key)\n const xIndex = xValueToIndex.get(x) || 0\n \n const rect = g.append('rect')\n .attr('x', xIndex * (finalCellWidth + 4))\n .attr('y', (y - minY) * (finalCellHeight + 4))\n .attr('width', finalCellWidth)\n .attr('height', finalCellHeight)\n .attr('rx', 2)\n .attr('ry', 2)\n .style('fill', cell ? colorScale(cell.value) : emptyCellColor)\n .style('stroke', cellStrokeColor)\n .style('stroke-width', 1)\n\n // Add hover effects and tooltips\n if (safeDisplayConfig.showTooltip) {\n rect\n .style('cursor', drillEnabled ? 'pointer' : 'default')\n .on('mouseover', function(event) {\n select(this)\n .style('stroke', '#000')\n .style('stroke-width', 2)\n\n if (cell) {\n const tooltipContent = [\n `<strong>${cell.label}</strong>`,\n `${getFieldLabel(valueField)}: ${cell.value}`\n ].join('<br>')\n\n tooltip\n .html(tooltipContent)\n .style('left', (event.pageX + 10) + 'px')\n .style('top', (event.pageY - 10) + 'px')\n .transition()\n .duration(200)\n .style('opacity', 1)\n }\n })\n .on('mousemove', function(event) {\n tooltip\n .style('left', (event.pageX + 10) + 'px')\n .style('top', (event.pageY - 10) + 'px')\n })\n .on('mouseout', function() {\n select(this)\n .style('stroke', cellStrokeColor)\n .style('stroke-width', 1)\n\n tooltip\n .transition()\n .duration(200)\n .style('opacity', 0)\n })\n } else if (drillEnabled) {\n // Set cursor for drill even without tooltips\n rect.style('cursor', 'pointer')\n }\n\n // Add drill click handler\n if (drillEnabled && onDataPointClick && cell) {\n rect.on('click', function(event) {\n onDataPointClick({\n dataPoint: { [valueField]: cell.value, [dateField]: cell.date },\n clickedField: valueField,\n xValue: cell.label,\n position: { x: event.pageX, y: event.pageY },\n nativeEvent: event as unknown as React.MouseEvent\n })\n })\n }\n }\n }\n\n // Add axis labels if enabled\n if (safeDisplayConfig.showLabels) {\n if (gridMapping.hasHierarchicalLabels && gridMapping.getYearFromX) {\n // Special handling for quarter view with hierarchical labels\n // Use the complete X range to show all quarters/months\n \n // Group quarters by year\n const yearGroups = new Map<number, number[]>()\n for (const x of completeXRange) {\n const year = gridMapping.getYearFromX(x)\n if (!yearGroups.has(year)) {\n yearGroups.set(year, [])\n }\n yearGroups.get(year)!.push(x)\n }\n \n \n // Draw column labels (Q1-Q4 for months, Jan-Dec for weeks)\n for (const x of completeXRange) {\n const xIndex = xValueToIndex.get(x) || 0\n g.append('text')\n .attr('x', xIndex * (finalCellWidth + 4) + finalCellWidth / 2)\n .attr('y', -8)\n .attr('text-anchor', 'middle')\n .style('font-size', '10px')\n .style('fill', textColor)\n .text(gridMapping.xFormat(x))\n }\n\n // Draw year group labels above quarters\n for (const [year, xValues] of yearGroups) {\n if (xValues.length > 0) {\n // Get the index positions for proper spacing\n const startIndex = Math.min(...xValues.map(x => xValueToIndex.get(x) || 0))\n const endIndex = Math.max(...xValues.map(x => xValueToIndex.get(x) || 0))\n const centerIndex = (startIndex + endIndex) / 2\n\n // Year label (or year/month for hour granularity)\n let labelText: string\n if (year > 9999) {\n // For hour granularity, year is encoded as YYYYMM\n const actualYear = Math.floor(year / 100)\n const month = year % 100\n const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\n labelText = `${monthNames[month - 1]} '${actualYear.toString().slice(-2)}`\n } else {\n // For other granularities, just show the year\n labelText = `'${year.toString().slice(-2)}`\n }\n\n g.append('text')\n .attr('x', centerIndex * (finalCellWidth + 4) + finalCellWidth / 2)\n .attr('y', -25)\n .attr('text-anchor', 'middle')\n .style('font-size', '12px')\n .style('font-weight', 'bold')\n .style('fill', textColor)\n .text(labelText)\n\n // Optional: Add a subtle line to group quarters under the year\n if (xValues.length > 1) {\n g.append('line')\n .attr('x1', startIndex * (finalCellWidth + 4))\n .attr('x2', endIndex * (finalCellWidth + 4) + finalCellWidth)\n .attr('y1', -20)\n .attr('y2', -20)\n .style('stroke', lineColor)\n .style('stroke-width', 1)\n .style('opacity', 0.3)\n }\n }\n }\n } else {\n // Regular X-axis labels for other granularities\n const xLabelStep = Math.max(1, Math.floor(completeXRange.length / 10))\n for (let i = 0; i < completeXRange.length; i += xLabelStep) {\n const x = completeXRange[i]\n g.append('text')\n .attr('x', i * (finalCellWidth + 4) + finalCellWidth / 2)\n .attr('y', -8)\n .attr('text-anchor', 'middle')\n .style('font-size', '10px')\n .style('fill', textColor)\n .text(gridMapping.xFormat(x))\n }\n }\n\n // Y-axis labels (left) - same for all granularities\n for (let y = minY; y <= maxY; y++) {\n g.append('text')\n .attr('x', -8)\n .attr('y', (y - minY) * (finalCellHeight + 4) + finalCellHeight / 2)\n .attr('text-anchor', 'end')\n .attr('dy', '.35em')\n .style('font-size', '10px')\n .style('fill', textColor)\n .text(gridMapping.yFormat(y))\n }\n }\n\n // Cleanup function\n return () => {\n tooltip.remove()\n }\n }, [data, chartConfig, displayConfig, queryObject, dimensions, dimensionsReady, safeDisplayConfig, colorPalette, currentTheme, getFieldLabel, getGridMapping, drillEnabled, onDataPointClick])\n\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display in activity grid</div>\n </div>\n </div>\n )\n }\n\n // Validate that we have required fields\n const hasValidConfig = chartConfig?.dateField && chartConfig?.valueField\n if (!hasValidConfig) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Required</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Activity grid requires a time dimension and a measure</div>\n </div>\n </div>\n )\n }\n\n // Check if granularity is supported\n const dateField = Array.isArray(chartConfig.dateField) ? chartConfig.dateField[0] : chartConfig.dateField\n const granularityFromQuery = queryObject?.timeDimensions?.find((td: any) => \n td.dimension === dateField || td.dimension.includes(dateField)\n )?.granularity || 'day'\n \n if (granularityFromQuery?.toLowerCase() === 'year') {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Granularity Too High</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Activity grids work best with hour, day, week, month, or quarter granularity</div>\n <div className=\"dc:text-xs text-dc-text-secondary dc:mt-1\">Please choose a lower granularity for your time dimension</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:flex dc:flex-col dc:relative\" style={{ height, minHeight: '250px', overflow: 'hidden', width: '100%' }}>\n <div ref={containerRef} className=\"dc:w-full dc:h-full dc:relative dc:overflow-x-auto\" style={{ width: '100%' }}>\n <svg ref={svgRef} className=\"dc:h-full\" />\n {!dimensionsReady && (\n <div className=\"dc:absolute dc:inset-0 dc:flex dc:items-center dc:justify-center\">\n <div className=\"text-dc-text-muted dc:text-sm\">Measuring chart dimensions...</div>\n </div>\n )}\n </div>\n </div>\n )\n})\n\nexport default ActivityGridChart"],"names":["ActivityGridChart","React","data","chartConfig","displayConfig","queryObject","height","colorPalette","onDataPointClick","drillEnabled","svgRef","useRef","containerRef","dimensions","setDimensions","useState","dimensionsReady","setDimensionsReady","currentTheme","setCurrentTheme","getFieldLabel","useCubeFieldLabel","useEffect","getTheme","watchThemeChanges","theme","safeDisplayConfig","useMemo","useLayoutEffect","retryCount","maxRetries","rafId","timeoutId","updateDimensions","width","retryWithRaf","resizeObserver","getQuarter","date","getMonthOfQuarter","getWeekOfMonth","dayOfMonth","getGridMapping","useCallback","granularity","value","year","quarter","month","week","getWeekOfYear","day","d","dayNum","yearStart","select","dateField","valueField","queryGranularity","timeDim","td","firstTimeDim","gridMapping","gridData","item","dateValue","isoStr","x","y","formatTimeValue","cell","maxY","max","minY","min","completeXRange","dataXValues","gridWidth","gridHeight","margin","availableWidth","availableHeight","finalCellWidth","finalCellHeight","scaleX","scaleY","scale","minCellSize","maxCellSize","actualGridWidth","svgWidth","g","values","minValue","maxValue","colorScale","scaleQuantize","CHART_COLORS_GRADIENT","gridMap","key","getThemeColor","varName","fallback","isDark","textColor","lineColor","emptyCellColor","cellStrokeColor","tooltip","xValueToIndex","index","xIndex","rect","event","tooltipContent","yearGroups","xValues","startIndex","endIndex","centerIndex","labelText","actualYear","xLabelStep","i","jsx","jsxs"],"mappings":"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"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { jsx as s, jsxs as v } from "react/jsx-runtime";
|
|
2
|
+
import G, { useRef as I, useState as J, useLayoutEffect as K, useMemo as j } from "react";
|
|
3
|
+
import { f as Q, c as U } from "./charts-core-DmGfleFz.js";
|
|
4
|
+
const X = 50;
|
|
5
|
+
function p(i) {
|
|
6
|
+
if (i == null) return null;
|
|
7
|
+
const n = typeof i == "number" ? i : parseFloat(String(i));
|
|
8
|
+
return isNaN(n) ? null : n;
|
|
9
|
+
}
|
|
10
|
+
function Z(i, n, r, h, c, f, d, l) {
|
|
11
|
+
const a = p(i[n]), m = p(i[r]), o = p(i[h]), g = p(i[c]), A = p(i[f]);
|
|
12
|
+
return a === null || m === null || o === null || g === null || A === null ? null : { label: d, min: a, q1: m, median: o, q3: g, max: A, color: l };
|
|
13
|
+
}
|
|
14
|
+
function ee(i, n, r, h, c, f) {
|
|
15
|
+
const d = p(i[n]), l = p(i[r]), a = p(i[h]);
|
|
16
|
+
if (d === null || l === null || a === null) return null;
|
|
17
|
+
const m = Math.abs(l);
|
|
18
|
+
return {
|
|
19
|
+
label: c,
|
|
20
|
+
min: d - 2 * m,
|
|
21
|
+
q1: d - m,
|
|
22
|
+
median: a,
|
|
23
|
+
q3: d + m,
|
|
24
|
+
max: d + 2 * m,
|
|
25
|
+
color: f
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function te({
|
|
29
|
+
x: i,
|
|
30
|
+
boxWidth: n,
|
|
31
|
+
minY: r,
|
|
32
|
+
q1Y: h,
|
|
33
|
+
medianY: c,
|
|
34
|
+
q3Y: f,
|
|
35
|
+
maxY: d,
|
|
36
|
+
color: l,
|
|
37
|
+
label: a
|
|
38
|
+
}) {
|
|
39
|
+
const m = n / 2, o = i, g = n * 0.4;
|
|
40
|
+
return /* @__PURE__ */ v("g", { "data-testid": `box-${a}`, children: [
|
|
41
|
+
/* @__PURE__ */ s("line", { x1: o, y1: r, x2: o, y2: d, stroke: l, strokeWidth: 1.5 }),
|
|
42
|
+
/* @__PURE__ */ s(
|
|
43
|
+
"line",
|
|
44
|
+
{
|
|
45
|
+
x1: o - g / 2,
|
|
46
|
+
y1: r,
|
|
47
|
+
x2: o + g / 2,
|
|
48
|
+
y2: r,
|
|
49
|
+
stroke: l,
|
|
50
|
+
strokeWidth: 1.5
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
/* @__PURE__ */ s(
|
|
54
|
+
"line",
|
|
55
|
+
{
|
|
56
|
+
x1: o - g / 2,
|
|
57
|
+
y1: d,
|
|
58
|
+
x2: o + g / 2,
|
|
59
|
+
y2: d,
|
|
60
|
+
stroke: l,
|
|
61
|
+
strokeWidth: 1.5
|
|
62
|
+
}
|
|
63
|
+
),
|
|
64
|
+
/* @__PURE__ */ s(
|
|
65
|
+
"rect",
|
|
66
|
+
{
|
|
67
|
+
x: o - m,
|
|
68
|
+
y: Math.min(h, f),
|
|
69
|
+
width: n,
|
|
70
|
+
height: Math.abs(f - h) || 2,
|
|
71
|
+
fill: l,
|
|
72
|
+
fillOpacity: 0.3,
|
|
73
|
+
stroke: l,
|
|
74
|
+
strokeWidth: 1.5
|
|
75
|
+
}
|
|
76
|
+
),
|
|
77
|
+
/* @__PURE__ */ s(
|
|
78
|
+
"line",
|
|
79
|
+
{
|
|
80
|
+
x1: o - m,
|
|
81
|
+
y1: c,
|
|
82
|
+
x2: o + m,
|
|
83
|
+
y2: c,
|
|
84
|
+
stroke: l,
|
|
85
|
+
strokeWidth: 2.5,
|
|
86
|
+
"data-testid": `median-${a}`
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
] });
|
|
90
|
+
}
|
|
91
|
+
function ne({
|
|
92
|
+
scale: i,
|
|
93
|
+
domainMin: n,
|
|
94
|
+
domainMax: r,
|
|
95
|
+
width: h,
|
|
96
|
+
tickCount: c = 5,
|
|
97
|
+
format: f
|
|
98
|
+
}) {
|
|
99
|
+
const d = j(() => {
|
|
100
|
+
const l = r - n;
|
|
101
|
+
if (l === 0) return [n];
|
|
102
|
+
const a = l / (c - 1);
|
|
103
|
+
return Array.from({ length: c }, (m, o) => n + o * a);
|
|
104
|
+
}, [n, r, c]);
|
|
105
|
+
return /* @__PURE__ */ v("g", { "data-testid": "y-axis", children: [
|
|
106
|
+
d.map((l, a) => /* @__PURE__ */ v("g", { transform: `translate(0, ${i(l)})`, children: [
|
|
107
|
+
/* @__PURE__ */ s("line", { x1: 0, x2: -6, stroke: "currentColor", strokeWidth: 1 }),
|
|
108
|
+
/* @__PURE__ */ s(
|
|
109
|
+
"text",
|
|
110
|
+
{
|
|
111
|
+
x: -10,
|
|
112
|
+
textAnchor: "end",
|
|
113
|
+
dominantBaseline: "middle",
|
|
114
|
+
fontSize: 11,
|
|
115
|
+
fill: "currentColor",
|
|
116
|
+
className: "text-dc-text-secondary",
|
|
117
|
+
children: f ? f(l) : l.toLocaleString()
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
/* @__PURE__ */ s("line", { x1: 0, x2: h, stroke: "currentColor", strokeOpacity: 0.1, strokeWidth: 1 })
|
|
121
|
+
] }, a)),
|
|
122
|
+
/* @__PURE__ */ s("line", { y1: i(d[0]), y2: i(d[d.length - 1]), stroke: "currentColor", strokeWidth: 1 })
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
const re = G.memo(function({
|
|
126
|
+
data: n,
|
|
127
|
+
chartConfig: r,
|
|
128
|
+
displayConfig: h = {},
|
|
129
|
+
height: c = "100%",
|
|
130
|
+
colorPalette: f,
|
|
131
|
+
onDataPointClick: d,
|
|
132
|
+
drillEnabled: l
|
|
133
|
+
}) {
|
|
134
|
+
const a = I(null), [m, o] = J({ width: 0, height: 0 });
|
|
135
|
+
K(() => {
|
|
136
|
+
const e = a.current;
|
|
137
|
+
if (!e) return;
|
|
138
|
+
const t = new ResizeObserver((u) => {
|
|
139
|
+
for (const y of u) {
|
|
140
|
+
const { width: S, height: q } = y.contentRect;
|
|
141
|
+
S > 0 && q > 0 && o({ width: S, height: q });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
t.observe(e);
|
|
145
|
+
const x = e.getBoundingClientRect();
|
|
146
|
+
return x.width > 0 && x.height > 0 && o({ width: x.width, height: x.height }), () => t.disconnect();
|
|
147
|
+
}, []);
|
|
148
|
+
const g = h?.leftYAxisFormat, { xField: A, mode: M, fields: F, configError: R } = j(() => {
|
|
149
|
+
const e = Array.isArray(r?.xAxis) ? r.xAxis[0] : r?.xAxis ?? r?.x, t = h, x = t?.minField && t?.q1Field && t?.medianField && t?.q3Field && t?.maxField, u = t?.avgField && t?.stddevField && t?.medianField, y = Array.isArray(r?.yAxis) ? r.yAxis : r?.yAxis ? [r.yAxis] : [];
|
|
150
|
+
return !e && !y.length && !x && !u ? {
|
|
151
|
+
xField: e,
|
|
152
|
+
mode: "none",
|
|
153
|
+
fields: {},
|
|
154
|
+
configError: "BoxPlot requires an X-Axis dimension and at least one measure"
|
|
155
|
+
} : x ? {
|
|
156
|
+
xField: e,
|
|
157
|
+
mode: "5measure",
|
|
158
|
+
fields: {
|
|
159
|
+
minField: String(t.minField),
|
|
160
|
+
q1Field: String(t.q1Field),
|
|
161
|
+
medianField: String(t.medianField),
|
|
162
|
+
q3Field: String(t.q3Field),
|
|
163
|
+
maxField: String(t.maxField)
|
|
164
|
+
},
|
|
165
|
+
configError: null
|
|
166
|
+
} : u ? {
|
|
167
|
+
xField: e,
|
|
168
|
+
mode: "3measure",
|
|
169
|
+
fields: {
|
|
170
|
+
avgField: String(t.avgField),
|
|
171
|
+
stddevField: String(t.stddevField),
|
|
172
|
+
medianField: String(t.medianField)
|
|
173
|
+
},
|
|
174
|
+
configError: null
|
|
175
|
+
} : !e || y.length === 0 ? {
|
|
176
|
+
xField: e,
|
|
177
|
+
mode: "none",
|
|
178
|
+
fields: {},
|
|
179
|
+
configError: "BoxPlot requires an X-Axis dimension and at least one measure in Y-Axis"
|
|
180
|
+
} : {
|
|
181
|
+
xField: e,
|
|
182
|
+
mode: "auto",
|
|
183
|
+
fields: { valueField: y[0] },
|
|
184
|
+
configError: null
|
|
185
|
+
};
|
|
186
|
+
}, [r, h]), $ = j(() => {
|
|
187
|
+
if (R || !n || n.length === 0 || M === "none") return [];
|
|
188
|
+
const e = n.slice(0, X), t = f?.colors ?? U, x = [];
|
|
189
|
+
for (let u = 0; u < e.length; u++) {
|
|
190
|
+
const y = e[u], S = A ? String(y[A] ?? `Row ${u + 1}`) : `Row ${u + 1}`, q = t[u % t.length];
|
|
191
|
+
let w = null;
|
|
192
|
+
if (M === "5measure")
|
|
193
|
+
w = Z(
|
|
194
|
+
y,
|
|
195
|
+
F.minField,
|
|
196
|
+
F.q1Field,
|
|
197
|
+
F.medianField,
|
|
198
|
+
F.q3Field,
|
|
199
|
+
F.maxField,
|
|
200
|
+
S,
|
|
201
|
+
q
|
|
202
|
+
);
|
|
203
|
+
else if (M === "3measure")
|
|
204
|
+
w = ee(y, F.avgField, F.stddevField, F.medianField, S, q);
|
|
205
|
+
else {
|
|
206
|
+
const k = p(y[F.valueField]);
|
|
207
|
+
k !== null && (w = { label: S, min: k, q1: k, median: k, q3: k, max: k, color: q });
|
|
208
|
+
}
|
|
209
|
+
w && x.push(w);
|
|
210
|
+
}
|
|
211
|
+
return x;
|
|
212
|
+
}, [n, A, M, F, f, R]);
|
|
213
|
+
if (!n || n.length === 0)
|
|
214
|
+
return /* @__PURE__ */ s("div", { className: "dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted", style: { height: c }, children: /* @__PURE__ */ v("div", { className: "dc:text-center", children: [
|
|
215
|
+
/* @__PURE__ */ s("div", { className: "dc:text-sm dc:font-semibold dc:mb-1", children: "No data available" }),
|
|
216
|
+
/* @__PURE__ */ s("div", { className: "dc:text-xs text-dc-text-secondary", children: "No data points to display in box plot chart" })
|
|
217
|
+
] }) });
|
|
218
|
+
if (R)
|
|
219
|
+
return /* @__PURE__ */ s("div", { className: "dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning", style: { height: c }, children: /* @__PURE__ */ v("div", { className: "dc:text-center", children: [
|
|
220
|
+
/* @__PURE__ */ s("div", { className: "dc:text-sm dc:font-semibold dc:mb-1", children: "Configuration Error" }),
|
|
221
|
+
/* @__PURE__ */ s("div", { className: "dc:text-xs", children: R })
|
|
222
|
+
] }) });
|
|
223
|
+
if ($.length === 0)
|
|
224
|
+
return /* @__PURE__ */ s("div", { className: "dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted", style: { height: c }, children: /* @__PURE__ */ v("div", { className: "dc:text-center", children: [
|
|
225
|
+
/* @__PURE__ */ s("div", { className: "dc:text-sm dc:font-semibold dc:mb-1", children: "No valid data" }),
|
|
226
|
+
/* @__PURE__ */ s("div", { className: "dc:text-xs text-dc-text-secondary", children: "Could not compute box plot statistics from the provided data" })
|
|
227
|
+
] }) });
|
|
228
|
+
const N = { top: 20, right: 20, bottom: 60, left: 60 }, _ = m.width || 600, E = typeof c == "number" ? c : m.height || 400, z = Math.max(_ - N.left - N.right, 50), W = Math.max(E - N.top - N.bottom, 50), H = $.flatMap((e) => [e.min, e.max]), L = Math.min(...H), P = Math.max(...H), V = (P - L) * 0.1 || 1, B = L - V, T = P + V, Y = T - B, b = (e) => Y === 0 ? W / 2 : W - (e - B) / Y * W, O = z / $.length, D = Math.min(O * 0.6, 40), C = n.length > X;
|
|
229
|
+
return /* @__PURE__ */ v("div", { ref: a, className: "dc:relative dc:w-full", style: { height: c }, children: [
|
|
230
|
+
/* @__PURE__ */ s(
|
|
231
|
+
"svg",
|
|
232
|
+
{
|
|
233
|
+
width: "100%",
|
|
234
|
+
height: C ? "calc(100% - 20px)" : "100%",
|
|
235
|
+
viewBox: `0 0 ${_} ${typeof E == "number" ? E : 400}`,
|
|
236
|
+
preserveAspectRatio: "none",
|
|
237
|
+
"data-testid": "boxplot-svg",
|
|
238
|
+
children: /* @__PURE__ */ v("g", { transform: `translate(${N.left}, ${N.top})`, children: [
|
|
239
|
+
/* @__PURE__ */ s(
|
|
240
|
+
ne,
|
|
241
|
+
{
|
|
242
|
+
scale: b,
|
|
243
|
+
domainMin: B,
|
|
244
|
+
domainMax: T,
|
|
245
|
+
width: z,
|
|
246
|
+
tickCount: 5,
|
|
247
|
+
format: g ? (e) => Q(e, g) : void 0
|
|
248
|
+
}
|
|
249
|
+
),
|
|
250
|
+
$.map((e, t) => {
|
|
251
|
+
const x = O * t + O / 2;
|
|
252
|
+
return /* @__PURE__ */ v(
|
|
253
|
+
"g",
|
|
254
|
+
{
|
|
255
|
+
onClick: (u) => {
|
|
256
|
+
d && l && d({
|
|
257
|
+
dataPoint: { ...e },
|
|
258
|
+
clickedField: A ?? "",
|
|
259
|
+
xValue: e.label,
|
|
260
|
+
position: { x: u.clientX, y: u.clientY },
|
|
261
|
+
nativeEvent: u
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
cursor: l ? "pointer" : void 0,
|
|
265
|
+
children: [
|
|
266
|
+
/* @__PURE__ */ s(
|
|
267
|
+
te,
|
|
268
|
+
{
|
|
269
|
+
x,
|
|
270
|
+
boxWidth: D,
|
|
271
|
+
minY: b(e.min),
|
|
272
|
+
q1Y: b(e.q1),
|
|
273
|
+
medianY: b(e.median),
|
|
274
|
+
q3Y: b(e.q3),
|
|
275
|
+
maxY: b(e.max),
|
|
276
|
+
color: e.color,
|
|
277
|
+
label: e.label
|
|
278
|
+
}
|
|
279
|
+
),
|
|
280
|
+
/* @__PURE__ */ s(
|
|
281
|
+
"text",
|
|
282
|
+
{
|
|
283
|
+
x,
|
|
284
|
+
y: W + 20,
|
|
285
|
+
textAnchor: "middle",
|
|
286
|
+
fontSize: 11,
|
|
287
|
+
fill: "currentColor",
|
|
288
|
+
className: "text-dc-text-secondary",
|
|
289
|
+
"data-testid": `x-label-${e.label}`,
|
|
290
|
+
children: e.label
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
]
|
|
294
|
+
},
|
|
295
|
+
`${e.label}-${t}`
|
|
296
|
+
);
|
|
297
|
+
})
|
|
298
|
+
] })
|
|
299
|
+
}
|
|
300
|
+
),
|
|
301
|
+
C && /* @__PURE__ */ v("div", { className: "dc:text-xs text-dc-text-muted dc:text-center dc:mt-1", children: [
|
|
302
|
+
"Data truncated to ",
|
|
303
|
+
X,
|
|
304
|
+
" groups (original: ",
|
|
305
|
+
n.length,
|
|
306
|
+
")"
|
|
307
|
+
] })
|
|
308
|
+
] });
|
|
309
|
+
});
|
|
310
|
+
export {
|
|
311
|
+
re as default
|
|
312
|
+
};
|
|
313
|
+
//# sourceMappingURL=chart-box-plot-Dja4LS3O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-box-plot-Dja4LS3O.js","sources":["../../../src/client/components/charts/BoxPlotChart.tsx"],"sourcesContent":["import React, { useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { formatAxisValue } from '../../utils/chartUtils'\nimport type { ChartProps } from '../../types'\n\nconst MAX_BOXES = 50\n\ninterface BoxStats {\n label: string\n min: number\n q1: number\n median: number\n q3: number\n max: number\n color: string\n}\n\nfunction parseNumeric(v: unknown): number | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : parseFloat(String(v))\n return isNaN(n) ? null : n\n}\n\n/** Build box stats from 5-measure mode fields */\nfunction buildFrom5Measures(\n row: Record<string, unknown>,\n minField: string,\n q1Field: string,\n medianField: string,\n q3Field: string,\n maxField: string,\n label: string,\n color: string\n): BoxStats | null {\n const min = parseNumeric(row[minField])\n const q1 = parseNumeric(row[q1Field])\n const median = parseNumeric(row[medianField])\n const q3 = parseNumeric(row[q3Field])\n const max = parseNumeric(row[maxField])\n if (min === null || q1 === null || median === null || q3 === null || max === null) return null\n return { label, min, q1, median, q3, max, color }\n}\n\n/** Build approximate box stats from 3-measure mode (avg ± stddev, median) */\nfunction buildFrom3Measures(\n row: Record<string, unknown>,\n avgField: string,\n stddevField: string,\n medianField: string,\n label: string,\n color: string\n): BoxStats | null {\n const avg = parseNumeric(row[avgField])\n const sd = parseNumeric(row[stddevField])\n const median = parseNumeric(row[medianField])\n if (avg === null || sd === null || median === null) return null\n const absSd = Math.abs(sd)\n return {\n label,\n min: avg - 2 * absSd,\n q1: avg - absSd,\n median,\n q3: avg + absSd,\n max: avg + 2 * absSd,\n color,\n }\n}\n\n// Render a single box plot element\nfunction BoxElement({\n x,\n boxWidth,\n minY,\n q1Y,\n medianY,\n q3Y,\n maxY,\n color,\n label,\n}: {\n x: number\n boxWidth: number\n minY: number\n q1Y: number\n medianY: number\n q3Y: number\n maxY: number\n color: string\n label: string\n}) {\n const halfWidth = boxWidth / 2\n const whiskerX = x\n const capWidth = boxWidth * 0.4\n\n return (\n <g data-testid={`box-${label}`}>\n {/* Whisker line (min to max) */}\n <line x1={whiskerX} y1={minY} x2={whiskerX} y2={maxY} stroke={color} strokeWidth={1.5} />\n {/* Min cap */}\n <line\n x1={whiskerX - capWidth / 2}\n y1={minY}\n x2={whiskerX + capWidth / 2}\n y2={minY}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* Max cap */}\n <line\n x1={whiskerX - capWidth / 2}\n y1={maxY}\n x2={whiskerX + capWidth / 2}\n y2={maxY}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* IQR Box (Q1 to Q3) */}\n <rect\n x={whiskerX - halfWidth}\n y={Math.min(q1Y, q3Y)}\n width={boxWidth}\n height={Math.abs(q3Y - q1Y) || 2}\n fill={color}\n fillOpacity={0.3}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* Median line */}\n <line\n x1={whiskerX - halfWidth}\n y1={medianY}\n x2={whiskerX + halfWidth}\n y2={medianY}\n stroke={color}\n strokeWidth={2.5}\n data-testid={`median-${label}`}\n />\n </g>\n )\n}\n\n// Y-axis tick renderer\nfunction YAxis({\n scale,\n domainMin,\n domainMax,\n width,\n tickCount = 5,\n format,\n}: {\n scale: (v: number) => number\n domainMin: number\n domainMax: number\n width: number\n tickCount?: number\n format?: (v: number) => string\n}) {\n const ticks = useMemo(() => {\n const range = domainMax - domainMin\n if (range === 0) return [domainMin]\n const step = range / (tickCount - 1)\n return Array.from({ length: tickCount }, (_, i) => domainMin + i * step)\n }, [domainMin, domainMax, tickCount])\n\n return (\n <g data-testid=\"y-axis\">\n {ticks.map((tick, i) => (\n <g key={i} transform={`translate(0, ${scale(tick)})`}>\n <line x1={0} x2={-6} stroke=\"currentColor\" strokeWidth={1} />\n <text\n x={-10}\n textAnchor=\"end\"\n dominantBaseline=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n >\n {format ? format(tick) : tick.toLocaleString()}\n </text>\n <line x1={0} x2={width} stroke=\"currentColor\" strokeOpacity={0.1} strokeWidth={1} />\n </g>\n ))}\n <line y1={scale(ticks[0])} y2={scale(ticks[ticks.length - 1])} stroke=\"currentColor\" strokeWidth={1} />\n </g>\n )\n}\n\nconst BoxPlotChart = React.memo(function BoxPlotChart({\n data,\n chartConfig,\n displayConfig = {},\n height = '100%',\n colorPalette,\n onDataPointClick,\n drillEnabled,\n}: ChartProps) {\n const containerRef = useRef<HTMLDivElement>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n\n useLayoutEffect(() => {\n const el = containerRef.current\n if (!el) return\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height: h } = entry.contentRect\n if (width > 0 && h > 0) setDimensions({ width, height: h })\n }\n })\n observer.observe(el)\n const rect = el.getBoundingClientRect()\n if (rect.width > 0 && rect.height > 0) setDimensions({ width: rect.width, height: rect.height })\n return () => observer.disconnect()\n }, [])\n\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\n // Determine config mode and extract fields\n const { xField, mode, fields, configError } = useMemo(() => {\n const xField = Array.isArray(chartConfig?.xAxis)\n ? chartConfig.xAxis[0]\n : chartConfig?.xAxis ?? chartConfig?.x\n\n // 5-measure mode: explicit q1/median/q3/min/max in displayConfig\n const dc = displayConfig as Record<string, unknown>\n const has5 = dc?.minField && dc?.q1Field && dc?.medianField && dc?.q3Field && dc?.maxField\n // 3-measure mode: avgField + stddevField + medianField in displayConfig\n const has3 = dc?.avgField && dc?.stddevField && dc?.medianField\n // Auto mode: single yAxis measure used as median, stddev from value if available\n const yAxisFields: string[] = Array.isArray(chartConfig?.yAxis)\n ? chartConfig.yAxis\n : chartConfig?.yAxis\n ? [chartConfig.yAxis as string]\n : []\n\n if (!xField && !yAxisFields.length && !has5 && !has3) {\n return {\n xField,\n mode: 'none' as const,\n fields: {},\n configError: 'BoxPlot requires an X-Axis dimension and at least one measure',\n }\n }\n\n if (has5) {\n return {\n xField,\n mode: '5measure' as const,\n fields: {\n minField: String(dc.minField),\n q1Field: String(dc.q1Field),\n medianField: String(dc.medianField),\n q3Field: String(dc.q3Field),\n maxField: String(dc.maxField),\n },\n configError: null,\n }\n }\n\n if (has3) {\n return {\n xField,\n mode: '3measure' as const,\n fields: {\n avgField: String(dc.avgField),\n stddevField: String(dc.stddevField),\n medianField: String(dc.medianField),\n },\n configError: null,\n }\n }\n\n // Fallback: need at least xAxis + 1 measure in yAxis\n if (!xField || yAxisFields.length === 0) {\n return {\n xField,\n mode: 'none' as const,\n fields: {},\n configError: 'BoxPlot requires an X-Axis dimension and at least one measure in Y-Axis',\n }\n }\n\n // Auto mode: use yAxis[0] as the value field (treated as median/value)\n return {\n xField,\n mode: 'auto' as const,\n fields: { valueField: yAxisFields[0] },\n configError: null,\n }\n }, [chartConfig, displayConfig])\n\n const boxes: BoxStats[] = useMemo(() => {\n if (configError || !data || data.length === 0 || mode === 'none') return []\n const rows = (data as Record<string, unknown>[]).slice(0, MAX_BOXES)\n const palette = colorPalette?.colors ?? CHART_COLORS\n\n const results: BoxStats[] = []\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]\n const label = xField ? String(row[xField] ?? `Row ${i + 1}`) : `Row ${i + 1}`\n const color = palette[i % palette.length]\n\n let box: BoxStats | null = null\n if (mode === '5measure') {\n box = buildFrom5Measures(\n row,\n fields.minField!,\n fields.q1Field!,\n fields.medianField!,\n fields.q3Field!,\n fields.maxField!,\n label,\n color\n )\n } else if (mode === '3measure') {\n box = buildFrom3Measures(row, fields.avgField!, fields.stddevField!, fields.medianField!, label, color)\n } else {\n // Auto: use value as median, build minimal box (value ± 0)\n const v = parseNumeric(row[fields.valueField!])\n if (v !== null) {\n box = { label, min: v, q1: v, median: v, q3: v, max: v, color }\n }\n }\n if (box) results.push(box)\n }\n return results\n }, [data, xField, mode, fields, colorPalette, configError])\n\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display in box plot chart</div>\n </div>\n </div>\n )\n }\n\n if (configError) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Error</div>\n <div className=\"dc:text-xs\">{configError}</div>\n </div>\n </div>\n )\n }\n\n if (boxes.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No valid data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n Could not compute box plot statistics from the provided data\n </div>\n </div>\n </div>\n )\n }\n\n // Compute layout\n const margin = { top: 20, right: 20, bottom: 60, left: 60 }\n const containerWidth = dimensions.width || 600\n const containerHeight = typeof height === 'number' ? height : (dimensions.height || 400)\n const innerWidth = Math.max(containerWidth - margin.left - margin.right, 50)\n const innerHeight = Math.max(containerHeight - margin.top - margin.bottom, 50)\n\n // Y scale: linear from min-of-all to max-of-all\n const allValues = boxes.flatMap((b) => [b.min, b.max])\n const rawMin = Math.min(...allValues)\n const rawMax = Math.max(...allValues)\n const padding = (rawMax - rawMin) * 0.1 || 1\n const domainMin = rawMin - padding\n const domainMax = rawMax + padding\n\n const domainRange = domainMax - domainMin\n const yScale = (v: number) =>\n domainRange === 0 ? innerHeight / 2 : innerHeight - ((v - domainMin) / domainRange) * innerHeight\n\n const boxSpacing = innerWidth / boxes.length\n const boxWidth = Math.min(boxSpacing * 0.6, 40)\n\n const isTruncated = (data as unknown[]).length > MAX_BOXES\n\n return (\n <div ref={containerRef} className=\"dc:relative dc:w-full\" style={{ height }}>\n <svg\n width=\"100%\"\n height={isTruncated ? `calc(100% - 20px)` : '100%'}\n viewBox={`0 0 ${containerWidth} ${typeof containerHeight === 'number' ? containerHeight : 400}`}\n preserveAspectRatio=\"none\"\n data-testid=\"boxplot-svg\"\n >\n <g transform={`translate(${margin.left}, ${margin.top})`}>\n {/* Y Axis */}\n <YAxis\n scale={yScale}\n domainMin={domainMin}\n domainMax={domainMax}\n width={innerWidth}\n tickCount={5}\n format={yAxisFormat ? (v) => formatAxisValue(v, yAxisFormat) : undefined}\n />\n\n {/* Box plot elements */}\n {boxes.map((box, i) => {\n const cx = boxSpacing * i + boxSpacing / 2\n return (\n <g\n key={`${box.label}-${i}`}\n onClick={(event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled) {\n onDataPointClick({\n dataPoint: { ...box },\n clickedField: xField ?? '',\n xValue: box.label,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event,\n })\n }\n }}\n cursor={drillEnabled ? 'pointer' : undefined}\n >\n <BoxElement\n x={cx}\n boxWidth={boxWidth}\n minY={yScale(box.min)}\n q1Y={yScale(box.q1)}\n medianY={yScale(box.median)}\n q3Y={yScale(box.q3)}\n maxY={yScale(box.max)}\n color={box.color}\n label={box.label}\n />\n {/* X axis label */}\n <text\n x={cx}\n y={innerHeight + 20}\n textAnchor=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n data-testid={`x-label-${box.label}`}\n >\n {box.label}\n </text>\n </g>\n )\n })}\n </g>\n </svg>\n {isTruncated && (\n <div className=\"dc:text-xs text-dc-text-muted dc:text-center dc:mt-1\">\n Data truncated to {MAX_BOXES} groups (original: {(data as unknown[]).length})\n </div>\n )}\n </div>\n )\n})\n\nexport default BoxPlotChart\n"],"names":["MAX_BOXES","parseNumeric","v","buildFrom5Measures","row","minField","q1Field","medianField","q3Field","maxField","label","color","min","q1","median","q3","max","buildFrom3Measures","avgField","stddevField","avg","sd","absSd","BoxElement","x","boxWidth","minY","q1Y","medianY","q3Y","maxY","halfWidth","whiskerX","capWidth","jsxs","jsx","YAxis","scale","domainMin","domainMax","width","tickCount","format","ticks","useMemo","range","step","_","i","tick","BoxPlotChart","React","data","chartConfig","displayConfig","height","colorPalette","onDataPointClick","drillEnabled","containerRef","useRef","dimensions","setDimensions","useState","useLayoutEffect","el","observer","entries","entry","h","rect","yAxisFormat","xField","mode","fields","configError","dc","has5","has3","yAxisFields","boxes","rows","palette","CHART_COLORS","results","box","margin","containerWidth","containerHeight","innerWidth","innerHeight","allValues","b","rawMin","rawMax","padding","domainRange","yScale","boxSpacing","isTruncated","formatAxisValue","cx","event"],"mappings":"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"}
|