@matthieumordrel/chart-studio 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +1 -1
  2. package/dist/core/chart-capabilities.d.mts +48 -0
  3. package/dist/core/chart-capabilities.mjs +55 -0
  4. package/dist/core/{colors.d.ts → colors.d.mts} +5 -3
  5. package/dist/core/colors.mjs +55 -0
  6. package/dist/core/config-utils.mjs +79 -0
  7. package/dist/core/date-utils.mjs +49 -0
  8. package/dist/core/define-chart-schema.d.mts +106 -0
  9. package/dist/core/define-chart-schema.mjs +47 -0
  10. package/dist/core/formatting.mjs +349 -0
  11. package/dist/core/infer-columns.d.mts +9 -0
  12. package/dist/core/infer-columns.mjs +481 -0
  13. package/dist/core/metric-utils.d.mts +13 -0
  14. package/dist/core/metric-utils.mjs +121 -0
  15. package/dist/core/pipeline-data-points.mjs +212 -0
  16. package/dist/core/pipeline-helpers.mjs +85 -0
  17. package/dist/core/{pipeline.d.ts → pipeline.d.mts} +21 -24
  18. package/dist/core/pipeline.mjs +153 -0
  19. package/dist/core/types.d.mts +957 -0
  20. package/dist/core/use-chart-options.d.mts +64 -0
  21. package/dist/core/use-chart-options.mjs +7 -0
  22. package/dist/core/use-chart-resolvers.mjs +34 -0
  23. package/dist/core/{use-chart.d.ts → use-chart.d.mts} +12 -9
  24. package/dist/core/use-chart.mjs +299 -0
  25. package/dist/index.d.mts +10 -0
  26. package/dist/index.mjs +8 -0
  27. package/dist/ui/chart-axis-ticks.mjs +65 -0
  28. package/dist/ui/{chart-canvas.d.ts → chart-canvas.d.mts} +13 -6
  29. package/dist/ui/chart-canvas.mjs +461 -0
  30. package/dist/ui/chart-context.d.mts +92 -0
  31. package/dist/ui/chart-context.mjs +112 -0
  32. package/dist/ui/{chart-date-range-badge.d.ts → chart-date-range-badge.d.mts} +10 -4
  33. package/dist/ui/chart-date-range-badge.mjs +49 -0
  34. package/dist/ui/chart-date-range-panel.d.mts +18 -0
  35. package/dist/ui/chart-date-range-panel.mjs +208 -0
  36. package/dist/ui/{chart-date-range.d.ts → chart-date-range.d.mts} +10 -4
  37. package/dist/ui/chart-date-range.mjs +67 -0
  38. package/dist/ui/chart-debug.d.mts +17 -0
  39. package/dist/ui/chart-debug.mjs +169 -0
  40. package/dist/ui/chart-dropdown.mjs +92 -0
  41. package/dist/ui/{chart-filters-panel.d.ts → chart-filters-panel.d.mts} +12 -5
  42. package/dist/ui/chart-filters-panel.mjs +132 -0
  43. package/dist/ui/{chart-filters.d.ts → chart-filters.d.mts} +10 -4
  44. package/dist/ui/chart-filters.mjs +48 -0
  45. package/dist/ui/chart-group-by-selector.d.mts +14 -0
  46. package/dist/ui/chart-group-by-selector.mjs +29 -0
  47. package/dist/ui/{chart-metric-panel.d.ts → chart-metric-panel.d.mts} +12 -5
  48. package/dist/ui/chart-metric-panel.mjs +172 -0
  49. package/dist/ui/chart-metric-selector.d.mts +16 -0
  50. package/dist/ui/chart-metric-selector.mjs +50 -0
  51. package/dist/ui/chart-select.mjs +62 -0
  52. package/dist/ui/{chart-source-switcher.d.ts → chart-source-switcher.d.mts} +10 -4
  53. package/dist/ui/chart-source-switcher.mjs +54 -0
  54. package/dist/ui/chart-time-bucket-selector.d.mts +15 -0
  55. package/dist/ui/chart-time-bucket-selector.mjs +34 -0
  56. package/dist/ui/chart-toolbar-overflow.d.mts +28 -0
  57. package/dist/ui/chart-toolbar-overflow.mjs +209 -0
  58. package/dist/ui/chart-toolbar.d.mts +29 -0
  59. package/dist/ui/chart-toolbar.mjs +56 -0
  60. package/dist/ui/chart-type-selector.d.mts +14 -0
  61. package/dist/ui/chart-type-selector.mjs +33 -0
  62. package/dist/ui/chart-x-axis-selector.d.mts +14 -0
  63. package/dist/ui/chart-x-axis-selector.mjs +25 -0
  64. package/dist/ui/index.d.mts +19 -0
  65. package/dist/ui/index.mjs +18 -0
  66. package/dist/ui/toolbar-types.d.mts +7 -0
  67. package/dist/ui/toolbar-types.mjs +83 -0
  68. package/package.json +11 -10
  69. package/dist/core/chart-capabilities.d.ts +0 -60
  70. package/dist/core/chart-capabilities.d.ts.map +0 -1
  71. package/dist/core/chart-capabilities.js +0 -54
  72. package/dist/core/colors.d.ts.map +0 -1
  73. package/dist/core/colors.js +0 -54
  74. package/dist/core/config-utils.d.ts +0 -43
  75. package/dist/core/config-utils.d.ts.map +0 -1
  76. package/dist/core/config-utils.js +0 -80
  77. package/dist/core/date-utils.d.ts +0 -29
  78. package/dist/core/date-utils.d.ts.map +0 -1
  79. package/dist/core/date-utils.js +0 -58
  80. package/dist/core/define-chart-schema.d.ts +0 -105
  81. package/dist/core/define-chart-schema.d.ts.map +0 -1
  82. package/dist/core/define-chart-schema.js +0 -44
  83. package/dist/core/formatting.d.ts +0 -47
  84. package/dist/core/formatting.d.ts.map +0 -1
  85. package/dist/core/formatting.js +0 -396
  86. package/dist/core/index.d.ts +0 -17
  87. package/dist/core/index.d.ts.map +0 -1
  88. package/dist/core/index.js +0 -12
  89. package/dist/core/infer-columns.d.ts +0 -6
  90. package/dist/core/infer-columns.d.ts.map +0 -1
  91. package/dist/core/infer-columns.js +0 -512
  92. package/dist/core/metric-utils.d.ts +0 -43
  93. package/dist/core/metric-utils.d.ts.map +0 -1
  94. package/dist/core/metric-utils.js +0 -141
  95. package/dist/core/pipeline-data-points.d.ts +0 -23
  96. package/dist/core/pipeline-data-points.d.ts.map +0 -1
  97. package/dist/core/pipeline-data-points.js +0 -235
  98. package/dist/core/pipeline-helpers.d.ts +0 -38
  99. package/dist/core/pipeline-helpers.d.ts.map +0 -1
  100. package/dist/core/pipeline-helpers.js +0 -97
  101. package/dist/core/pipeline.d.ts.map +0 -1
  102. package/dist/core/pipeline.js +0 -156
  103. package/dist/core/types.d.ts +0 -1109
  104. package/dist/core/types.d.ts.map +0 -1
  105. package/dist/core/types.js +0 -14
  106. package/dist/core/use-chart-options.d.ts +0 -66
  107. package/dist/core/use-chart-options.d.ts.map +0 -1
  108. package/dist/core/use-chart-options.js +0 -4
  109. package/dist/core/use-chart-resolvers.d.ts +0 -14
  110. package/dist/core/use-chart-resolvers.d.ts.map +0 -1
  111. package/dist/core/use-chart-resolvers.js +0 -41
  112. package/dist/core/use-chart.d.ts.map +0 -1
  113. package/dist/core/use-chart.js +0 -265
  114. package/dist/index.d.ts +0 -36
  115. package/dist/index.d.ts.map +0 -1
  116. package/dist/index.js +0 -35
  117. package/dist/ui/chart-axis-ticks.d.ts +0 -35
  118. package/dist/ui/chart-axis-ticks.d.ts.map +0 -1
  119. package/dist/ui/chart-axis-ticks.js +0 -79
  120. package/dist/ui/chart-canvas.d.ts.map +0 -1
  121. package/dist/ui/chart-canvas.js +0 -337
  122. package/dist/ui/chart-context.d.ts +0 -89
  123. package/dist/ui/chart-context.d.ts.map +0 -1
  124. package/dist/ui/chart-context.js +0 -128
  125. package/dist/ui/chart-date-range-badge.d.ts.map +0 -1
  126. package/dist/ui/chart-date-range-badge.js +0 -30
  127. package/dist/ui/chart-date-range-panel.d.ts +0 -25
  128. package/dist/ui/chart-date-range-panel.d.ts.map +0 -1
  129. package/dist/ui/chart-date-range-panel.js +0 -125
  130. package/dist/ui/chart-date-range.d.ts.map +0 -1
  131. package/dist/ui/chart-date-range.js +0 -37
  132. package/dist/ui/chart-debug.d.ts +0 -10
  133. package/dist/ui/chart-debug.d.ts.map +0 -1
  134. package/dist/ui/chart-debug.js +0 -126
  135. package/dist/ui/chart-dropdown.d.ts +0 -35
  136. package/dist/ui/chart-dropdown.d.ts.map +0 -1
  137. package/dist/ui/chart-dropdown.js +0 -76
  138. package/dist/ui/chart-filters-panel.d.ts.map +0 -1
  139. package/dist/ui/chart-filters-panel.js +0 -46
  140. package/dist/ui/chart-filters.d.ts.map +0 -1
  141. package/dist/ui/chart-filters.js +0 -26
  142. package/dist/ui/chart-group-by-selector.d.ts +0 -8
  143. package/dist/ui/chart-group-by-selector.d.ts.map +0 -1
  144. package/dist/ui/chart-group-by-selector.js +0 -19
  145. package/dist/ui/chart-metric-panel.d.ts.map +0 -1
  146. package/dist/ui/chart-metric-panel.js +0 -118
  147. package/dist/ui/chart-metric-selector.d.ts +0 -10
  148. package/dist/ui/chart-metric-selector.d.ts.map +0 -1
  149. package/dist/ui/chart-metric-selector.js +0 -27
  150. package/dist/ui/chart-select.d.ts +0 -25
  151. package/dist/ui/chart-select.d.ts.map +0 -1
  152. package/dist/ui/chart-select.js +0 -35
  153. package/dist/ui/chart-source-switcher.d.ts.map +0 -1
  154. package/dist/ui/chart-source-switcher.js +0 -31
  155. package/dist/ui/chart-time-bucket-selector.d.ts +0 -9
  156. package/dist/ui/chart-time-bucket-selector.d.ts.map +0 -1
  157. package/dist/ui/chart-time-bucket-selector.js +0 -25
  158. package/dist/ui/chart-toolbar-overflow.d.ts +0 -29
  159. package/dist/ui/chart-toolbar-overflow.d.ts.map +0 -1
  160. package/dist/ui/chart-toolbar-overflow.js +0 -109
  161. package/dist/ui/chart-toolbar.d.ts +0 -45
  162. package/dist/ui/chart-toolbar.d.ts.map +0 -1
  163. package/dist/ui/chart-toolbar.js +0 -44
  164. package/dist/ui/chart-type-selector.d.ts +0 -8
  165. package/dist/ui/chart-type-selector.d.ts.map +0 -1
  166. package/dist/ui/chart-type-selector.js +0 -22
  167. package/dist/ui/chart-x-axis-selector.d.ts +0 -8
  168. package/dist/ui/chart-x-axis-selector.d.ts.map +0 -1
  169. package/dist/ui/chart-x-axis-selector.js +0 -14
  170. package/dist/ui/index.d.ts +0 -25
  171. package/dist/ui/index.d.ts.map +0 -1
  172. package/dist/ui/index.js +0 -23
  173. package/dist/ui/toolbar-types.d.ts +0 -43
  174. package/dist/ui/toolbar-types.d.ts.map +0 -1
  175. package/dist/ui/toolbar-types.js +0 -50
@@ -1,141 +0,0 @@
1
- /**
2
- * Default metric used when no numeric aggregation is selected.
3
- */
4
- export const DEFAULT_METRIC = { kind: 'count' };
5
- /**
6
- * Type guard for aggregate metrics.
7
- */
8
- export function isAggregateMetric(metric) {
9
- return metric.kind === 'aggregate';
10
- }
11
- /**
12
- * Compare two metric definitions for semantic equality.
13
- */
14
- export function isSameMetric(left, right) {
15
- if (left.kind !== right.kind) {
16
- return false;
17
- }
18
- if (left.kind === 'count') {
19
- return true;
20
- }
21
- return (right.kind === 'aggregate'
22
- && left.columnId === right.columnId
23
- && left.aggregate === right.aggregate
24
- && (left.includeZeros ?? true) === (right.includeZeros ?? true));
25
- }
26
- /**
27
- * Human-readable label for a numeric aggregate.
28
- */
29
- export function getAggregateMetricLabel(columnLabel, aggregate) {
30
- switch (aggregate) {
31
- case 'sum':
32
- return `Sum of ${columnLabel}`;
33
- case 'avg':
34
- return `Avg ${columnLabel}`;
35
- case 'min':
36
- return `Min ${columnLabel}`;
37
- case 'max':
38
- return `Max ${columnLabel}`;
39
- }
40
- }
41
- /**
42
- * Human-readable label for a metric.
43
- */
44
- export function getMetricLabel(metric, columns) {
45
- if (!isAggregateMetric(metric)) {
46
- return 'Count';
47
- }
48
- const column = columns.find((candidate) => candidate.type === 'number' && candidate.id === metric.columnId);
49
- if (!column) {
50
- return 'Count';
51
- }
52
- return getAggregateMetricLabel(column.label, metric.aggregate);
53
- }
54
- /**
55
- * Build the metric options available for a set of columns.
56
- */
57
- export function buildAvailableMetrics(columns) {
58
- const metrics = [DEFAULT_METRIC];
59
- const numberColumns = columns.filter((column) => column.type === 'number');
60
- for (const column of numberColumns) {
61
- metrics.push({ kind: 'aggregate', columnId: column.id, aggregate: 'sum' }, { kind: 'aggregate', columnId: column.id, aggregate: 'avg' }, { kind: 'aggregate', columnId: column.id, aggregate: 'min' }, { kind: 'aggregate', columnId: column.id, aggregate: 'max' });
62
- }
63
- return metrics;
64
- }
65
- /**
66
- * Expand declarative metric restriction entries into the normalized metric list
67
- * used by the runtime and typed chart state.
68
- */
69
- export function normalizeMetricAllowances(allowedMetrics) {
70
- if (!allowedMetrics) {
71
- return undefined;
72
- }
73
- const normalized = [];
74
- for (const allowedMetric of allowedMetrics) {
75
- if (allowedMetric.kind === 'count') {
76
- normalized.push(allowedMetric);
77
- continue;
78
- }
79
- const aggregates = Array.isArray(allowedMetric.aggregate)
80
- ? allowedMetric.aggregate
81
- : [allowedMetric.aggregate];
82
- for (const aggregate of aggregates) {
83
- normalized.push({
84
- kind: 'aggregate',
85
- columnId: allowedMetric.columnId,
86
- aggregate,
87
- includeZeros: allowedMetric.includeZeros,
88
- });
89
- }
90
- }
91
- return normalized;
92
- }
93
- /**
94
- * Apply a declarative metric whitelist to the inferred metric options.
95
- *
96
- * Metrics are matched structurally so callers can safely pass fresh object
97
- * literals in `config.metric.allowed`. The final order follows the declarative
98
- * restriction list, so the first allowed metric becomes the default.
99
- */
100
- export function restrictAvailableMetrics(metrics, config) {
101
- const normalizedAllowedMetrics = normalizeMetricAllowances(config?.allowed);
102
- if (!normalizedAllowedMetrics) {
103
- const hiddenMetrics = config?.hidden;
104
- if (!hiddenMetrics || hiddenMetrics.length === 0) {
105
- return [...metrics];
106
- }
107
- const visibleMetrics = metrics.filter(metric => hiddenMetrics.every(hiddenMetric => !isSameMetric(metric, hiddenMetric)));
108
- return visibleMetrics.length > 0 ? visibleMetrics : [metrics[0] ?? DEFAULT_METRIC];
109
- }
110
- const allowedMetrics = normalizedAllowedMetrics.filter(allowedMetric => metrics.some(metric => isSameMetric(metric, allowedMetric)));
111
- const hiddenMetrics = config?.hidden;
112
- const restricted = !hiddenMetrics || hiddenMetrics.length === 0
113
- ? allowedMetrics
114
- : allowedMetrics.filter(metric => hiddenMetrics.every(hiddenMetric => !isSameMetric(metric, hiddenMetric)));
115
- // A chart always needs one active metric. Fall back to the inferred default if
116
- // the whitelist ends up empty or does not match the active source.
117
- return restricted.length > 0 ? restricted : [metrics[0] ?? DEFAULT_METRIC];
118
- }
119
- /**
120
- * Validate a metric against the active source.
121
- */
122
- export function resolveMetric(metric, columns, availableMetrics, configuredDefaultMetric) {
123
- if (availableMetrics && availableMetrics.length > 0) {
124
- const selectedMetric = availableMetrics.find(candidate => isSameMetric(candidate, metric));
125
- if (selectedMetric) {
126
- return selectedMetric;
127
- }
128
- const defaultMetric = configuredDefaultMetric
129
- ? availableMetrics.find(candidate => isSameMetric(candidate, configuredDefaultMetric))
130
- : undefined;
131
- return defaultMetric ?? availableMetrics[0];
132
- }
133
- if (!isAggregateMetric(metric)) {
134
- return DEFAULT_METRIC;
135
- }
136
- const column = columns.find((candidate) => candidate.type === 'number' && candidate.id === metric.columnId);
137
- if (!column) {
138
- return DEFAULT_METRIC;
139
- }
140
- return metric;
141
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * Bucket and aggregation steps for the chart transformation pipeline.
3
- */
4
- import type { ChartColumn, Metric, NumberColumn, TimeBucket, TransformedDataPoint } from './types.js';
5
- type DataPointResult = {
6
- data: TransformedDataPoint[];
7
- groups: string[];
8
- };
9
- /**
10
- * Build chart-ready data points by bucketing the X-axis, pivoting groups, and
11
- * aggregating the selected metric.
12
- *
13
- * @param items - Filtered source data
14
- * @param xColumn - Active X-axis column
15
- * @param groupByColumn - Optional group-by column
16
- * @param metric - Selected metric configuration
17
- * @param numberColumns - Number columns available for metric lookup
18
- * @param timeBucket - Time bucket used for date X-axes
19
- * @returns Aggregated chart data points and group labels
20
- */
21
- export declare function buildDataPoints<T, TColumnId extends string>(items: T[], xColumn: ChartColumn<T, TColumnId>, groupByColumn: ChartColumn<T, TColumnId> | null, metric: Metric<TColumnId>, numberColumns: NumberColumn<T, TColumnId>[], timeBucket: TimeBucket): DataPointResult;
22
- export {};
23
- //# sourceMappingURL=pipeline-data-points.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipeline-data-points.d.ts","sourceRoot":"","sources":["../../src/core/pipeline-data-points.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACV,WAAW,EAEX,MAAM,EACN,YAAY,EACZ,UAAU,EACV,oBAAoB,EACrB,MAAM,YAAY,CAAA;AAOnB,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,oBAAoB,EAAE,CAAA;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,SAAS,MAAM,EACzD,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,EAClC,aAAa,EAAE,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,EAC/C,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,EACzB,aAAa,EAAE,YAAY,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,EAC3C,UAAU,EAAE,UAAU,GACrB,eAAe,CAkBjB"}
@@ -1,235 +0,0 @@
1
- /**
2
- * Bucket and aggregation steps for the chart transformation pipeline.
3
- */
4
- import { isAggregateMetric } from './metric-utils.js';
5
- import { aggregate, dateBucketKey, dateBucketLabel, getStringValue } from './pipeline-helpers.js';
6
- /**
7
- * Build chart-ready data points by bucketing the X-axis, pivoting groups, and
8
- * aggregating the selected metric.
9
- *
10
- * @param items - Filtered source data
11
- * @param xColumn - Active X-axis column
12
- * @param groupByColumn - Optional group-by column
13
- * @param metric - Selected metric configuration
14
- * @param numberColumns - Number columns available for metric lookup
15
- * @param timeBucket - Time bucket used for date X-axes
16
- * @returns Aggregated chart data points and group labels
17
- */
18
- export function buildDataPoints(items, xColumn, groupByColumn, metric, numberColumns, timeBucket) {
19
- const groupSet = new Set();
20
- if (groupByColumn) {
21
- for (const item of items) {
22
- groupSet.add(getStringValue(item, groupByColumn));
23
- }
24
- }
25
- const groups = groupByColumn ? [...groupSet].toSorted() : ['value'];
26
- const metricColumn = isAggregateMetric(metric)
27
- ? (numberColumns.find((column) => column.id === metric.columnId) ?? null)
28
- : null;
29
- if (xColumn.type === 'date') {
30
- return buildTimeBuckets(items, xColumn, groupByColumn, groups, metric, metricColumn, timeBucket);
31
- }
32
- return buildCategoryBuckets(items, xColumn, groupByColumn, groups, metric, metricColumn);
33
- }
34
- /**
35
- * Generate a continuous sequence of date buckets from the minimum to maximum
36
- * date found in the data.
37
- *
38
- * @param items - Filtered source data
39
- * @param xColumn - Active date column
40
- * @param bucket - Time bucket granularity
41
- * @returns Every bucket between the first and last date in the dataset
42
- */
43
- function generateBucketsFromData(items, xColumn, bucket) {
44
- let min = null;
45
- let max = null;
46
- for (const item of items) {
47
- const rawValue = xColumn.accessor(item);
48
- if (rawValue == null)
49
- continue;
50
- const date = new Date(rawValue);
51
- if (Number.isNaN(date.getTime()))
52
- continue;
53
- if (!min || date < min)
54
- min = date;
55
- if (!max || date > max)
56
- max = date;
57
- }
58
- if (!min || !max)
59
- return [];
60
- const buckets = [];
61
- const cursor = startOfBucket(min, bucket);
62
- const seenKeys = new Set();
63
- const maxBuckets = 500;
64
- for (let bucketCount = 0; bucketCount < maxBuckets; bucketCount += 1) {
65
- if (cursor > max)
66
- break;
67
- const key = dateBucketKey(cursor, bucket);
68
- if (!seenKeys.has(key)) {
69
- seenKeys.add(key);
70
- buckets.push({ key, label: dateBucketLabel(key, bucket) });
71
- }
72
- advanceBucketCursor(cursor, bucket);
73
- }
74
- return buckets;
75
- }
76
- /**
77
- * Normalize a date to the start of its containing bucket.
78
- *
79
- * @param date - Source date
80
- * @param bucket - Time bucket granularity
81
- * @returns Start boundary for the bucket containing the source date
82
- */
83
- function startOfBucket(date, bucket) {
84
- const normalized = new Date(date);
85
- normalized.setHours(0, 0, 0, 0);
86
- switch (bucket) {
87
- case 'day':
88
- return normalized;
89
- case 'week': {
90
- const day = normalized.getDay();
91
- normalized.setDate(normalized.getDate() - ((day + 6) % 7));
92
- return normalized;
93
- }
94
- case 'month':
95
- normalized.setDate(1);
96
- return normalized;
97
- case 'quarter':
98
- normalized.setMonth(Math.floor(normalized.getMonth() / 3) * 3, 1);
99
- return normalized;
100
- case 'year':
101
- normalized.setMonth(0, 1);
102
- return normalized;
103
- }
104
- }
105
- /**
106
- * Advance a mutable cursor by a single bucket interval.
107
- *
108
- * @param cursor - Current date cursor
109
- * @param bucket - Time bucket granularity
110
- */
111
- function advanceBucketCursor(cursor, bucket) {
112
- switch (bucket) {
113
- case 'day':
114
- cursor.setDate(cursor.getDate() + 1);
115
- break;
116
- case 'week':
117
- cursor.setDate(cursor.getDate() + 7);
118
- break;
119
- case 'month':
120
- cursor.setMonth(cursor.getMonth() + 1);
121
- break;
122
- case 'quarter':
123
- cursor.setMonth(cursor.getMonth() + 3);
124
- break;
125
- case 'year':
126
- cursor.setFullYear(cursor.getFullYear() + 1);
127
- break;
128
- }
129
- }
130
- /**
131
- * Build data points for a date X-axis.
132
- *
133
- * @param items - Filtered source data
134
- * @param xColumn - Active date column
135
- * @param groupByColumn - Optional group-by column
136
- * @param groups - Resolved group labels
137
- * @param metric - Selected metric configuration
138
- * @param metricColumn - Resolved numeric metric column
139
- * @param timeBucket - Time bucket granularity
140
- * @returns Aggregated date-bucketed data points
141
- */
142
- function buildTimeBuckets(items, xColumn, groupByColumn, groups, metric, metricColumn, timeBucket) {
143
- const allBuckets = generateBucketsFromData(items, xColumn, timeBucket);
144
- const accumulator = new Map();
145
- for (const { key } of allBuckets) {
146
- const groupMap = new Map();
147
- for (const group of groups) {
148
- groupMap.set(group, []);
149
- }
150
- accumulator.set(key, groupMap);
151
- }
152
- for (const item of items) {
153
- const rawValue = xColumn.accessor(item);
154
- if (rawValue == null)
155
- continue;
156
- const date = new Date(rawValue);
157
- const key = dateBucketKey(date, timeBucket);
158
- const groupMap = accumulator.get(key);
159
- if (!groupMap)
160
- continue;
161
- const group = groupByColumn ? getStringValue(item, groupByColumn) : 'value';
162
- const values = groupMap.get(group);
163
- if (!values)
164
- continue;
165
- if (metricColumn) {
166
- const metricValue = metricColumn.accessor(item);
167
- if (metricValue != null)
168
- values.push(metricValue);
169
- }
170
- else {
171
- values.push(1);
172
- }
173
- }
174
- const data = allBuckets.map(({ key, label }) => {
175
- const point = { xLabel: label, xKey: key };
176
- const groupMap = accumulator.get(key);
177
- for (const group of groups) {
178
- point[group] = aggregate(groupMap.get(group) ?? [], metric.kind === 'aggregate' ? metric.aggregate : 'count', metric.kind === 'aggregate' ? (metric.includeZeros ?? true) : true);
179
- }
180
- return point;
181
- });
182
- return { data, groups };
183
- }
184
- /**
185
- * Build data points for a categorical or boolean X-axis.
186
- *
187
- * @param items - Filtered source data
188
- * @param xColumn - Active X-axis column
189
- * @param groupByColumn - Optional group-by column
190
- * @param groups - Resolved group labels
191
- * @param metric - Selected metric configuration
192
- * @param metricColumn - Resolved numeric metric column
193
- * @returns Aggregated category-bucketed data points
194
- */
195
- function buildCategoryBuckets(items, xColumn, groupByColumn, groups, metric, metricColumn) {
196
- const xValues = new Set();
197
- for (const item of items) {
198
- xValues.add(getStringValue(item, xColumn));
199
- }
200
- const accumulator = new Map();
201
- for (const xValue of xValues) {
202
- const groupMap = new Map();
203
- for (const group of groups) {
204
- groupMap.set(group, []);
205
- }
206
- accumulator.set(xValue, groupMap);
207
- }
208
- for (const item of items) {
209
- const xValue = getStringValue(item, xColumn);
210
- const groupMap = accumulator.get(xValue);
211
- if (!groupMap)
212
- continue;
213
- const group = groupByColumn ? getStringValue(item, groupByColumn) : 'value';
214
- const values = groupMap.get(group);
215
- if (!values)
216
- continue;
217
- if (metricColumn) {
218
- const metricValue = metricColumn.accessor(item);
219
- if (metricValue != null)
220
- values.push(metricValue);
221
- }
222
- else {
223
- values.push(1);
224
- }
225
- }
226
- const data = [...xValues].map((xValue) => {
227
- const point = { xLabel: xValue, xKey: xValue };
228
- const groupMap = accumulator.get(xValue);
229
- for (const group of groups) {
230
- point[group] = aggregate(groupMap.get(group) ?? [], metric.kind === 'aggregate' ? metric.aggregate : 'count', metric.kind === 'aggregate' ? (metric.includeZeros ?? true) : true);
231
- }
232
- return point;
233
- });
234
- return { data, groups };
235
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * Shared helpers for the chart transformation pipeline.
3
- */
4
- import type { AggregateFunction, ChartColumn, TimeBucket } from './types.js';
5
- /**
6
- * Format a stable key for a date bucket.
7
- *
8
- * @param date - Source date
9
- * @param bucket - Time bucket granularity
10
- * @returns Machine-friendly bucket key
11
- */
12
- export declare function dateBucketKey(date: Date, bucket: TimeBucket): string;
13
- /**
14
- * Format a bucket key into a human-readable label.
15
- *
16
- * @param key - Bucket key
17
- * @param bucket - Time bucket granularity
18
- * @returns Display label for the chart axis
19
- */
20
- export declare function dateBucketLabel(key: string, bucket: TimeBucket): string;
21
- /**
22
- * Extract a comparable string value from an item using a column definition.
23
- *
24
- * @param item - Raw data item
25
- * @param column - Column definition to read from
26
- * @returns String value used by filters and groups
27
- */
28
- export declare function getStringValue<T>(item: T, column: ChartColumn<T>): string;
29
- /**
30
- * Aggregate numeric values using the requested function.
31
- *
32
- * @param values - Numeric values to aggregate
33
- * @param fn - Aggregation strategy
34
- * @param includeZeros - Whether zero values should participate in avg/min/max
35
- * @returns Aggregated numeric result
36
- */
37
- export declare function aggregate(values: number[], fn: AggregateFunction, includeZeros?: boolean): number;
38
- //# sourceMappingURL=pipeline-helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipeline-helpers.d.ts","sourceRoot":"","sources":["../../src/core/pipeline-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAC,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAC,MAAM,YAAY,CAAA;AAE1E;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAoBpE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAEvE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM,CAqBzE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,iBAAiB,EAAE,YAAY,UAAO,GAAG,MAAM,CAkB9F"}
@@ -1,97 +0,0 @@
1
- /**
2
- * Shared helpers for the chart transformation pipeline.
3
- */
4
- import { formatTimeBucketLabel } from './formatting.js';
5
- /**
6
- * Format a stable key for a date bucket.
7
- *
8
- * @param date - Source date
9
- * @param bucket - Time bucket granularity
10
- * @returns Machine-friendly bucket key
11
- */
12
- export function dateBucketKey(date, bucket) {
13
- const year = date.getFullYear();
14
- const month = date.getMonth();
15
- switch (bucket) {
16
- case 'day':
17
- return `${year}-${String(month + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
18
- case 'week': {
19
- const day = date.getDay();
20
- const monday = new Date(date);
21
- monday.setDate(date.getDate() - ((day + 6) % 7));
22
- return `${monday.getFullYear()}-${String(monday.getMonth() + 1).padStart(2, '0')}-${String(monday.getDate()).padStart(2, '0')}`;
23
- }
24
- case 'month':
25
- return `${year}-${String(month + 1).padStart(2, '0')}`;
26
- case 'quarter':
27
- return `${year}-Q${Math.floor(month / 3) + 1}`;
28
- case 'year':
29
- return `${year}`;
30
- }
31
- }
32
- /**
33
- * Format a bucket key into a human-readable label.
34
- *
35
- * @param key - Bucket key
36
- * @param bucket - Time bucket granularity
37
- * @returns Display label for the chart axis
38
- */
39
- export function dateBucketLabel(key, bucket) {
40
- return formatTimeBucketLabel(key, bucket, 'axis');
41
- }
42
- /**
43
- * Extract a comparable string value from an item using a column definition.
44
- *
45
- * @param item - Raw data item
46
- * @param column - Column definition to read from
47
- * @returns String value used by filters and groups
48
- */
49
- export function getStringValue(item, column) {
50
- switch (column.type) {
51
- case 'boolean': {
52
- const value = column.accessor(item);
53
- if (value === true)
54
- return column.trueLabel;
55
- if (value === false)
56
- return column.falseLabel;
57
- return 'Unknown';
58
- }
59
- case 'category': {
60
- const value = column.accessor(item);
61
- return value ?? 'Unknown';
62
- }
63
- case 'date': {
64
- const value = column.accessor(item);
65
- return value != null ? String(value) : 'Unknown';
66
- }
67
- case 'number': {
68
- const value = column.accessor(item);
69
- return value != null ? String(value) : 'Unknown';
70
- }
71
- }
72
- }
73
- /**
74
- * Aggregate numeric values using the requested function.
75
- *
76
- * @param values - Numeric values to aggregate
77
- * @param fn - Aggregation strategy
78
- * @param includeZeros - Whether zero values should participate in avg/min/max
79
- * @returns Aggregated numeric result
80
- */
81
- export function aggregate(values, fn, includeZeros = true) {
82
- if (fn === 'count')
83
- return values.length;
84
- const effectiveValues = !includeZeros && fn !== 'sum' ? values.filter((value) => value !== 0) : values;
85
- if (effectiveValues.length === 0)
86
- return 0;
87
- switch (fn) {
88
- case 'sum':
89
- return effectiveValues.reduce((sum, value) => sum + value, 0);
90
- case 'avg':
91
- return effectiveValues.reduce((sum, value) => sum + value, 0) / effectiveValues.length;
92
- case 'min':
93
- return Math.min(...effectiveValues);
94
- case 'max':
95
- return Math.max(...effectiveValues);
96
- }
97
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EACV,eAAe,EAGf,WAAW,EACX,WAAW,EACX,WAAW,EACX,MAAM,EAEN,UAAU,EACV,UAAU,EACV,oBAAoB,EACrB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI;IAChE,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,OAAO,EAAE,SAAS,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAA;IAC7C,OAAO,EAAE,SAAS,CAAA;IAClB,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IACzB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IAC/B,OAAO,EAAE,UAAU,GAAG,IAAI,CAAA;CAC3B,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,oBAAoB,EAAE,CAAA;IAC5B,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,SAAS,SAAS,MAAM,EACtD,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,OAAO,EAAE,SAAS,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,EAC7C,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAC9B,CAAC,EAAE,CAiBL;AAgED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,SAAS,MAAM,EACrD,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,SAAS,CAAC,GACjC,cAAc,CA2BhB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,SAAS,SAAS,MAAM,EACjE,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,OAAO,EAAE,SAAS,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,GAC5C,eAAe,CAAC,SAAS,CAAC,EAAE,CA+B9B"}