mintwaterfall 0.8.6

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 (38) hide show
  1. package/CHANGELOG.md +223 -0
  2. package/CONTRIBUTING.md +199 -0
  3. package/README.md +363 -0
  4. package/dist/index.d.ts +149 -0
  5. package/dist/mintwaterfall.cjs.js +7978 -0
  6. package/dist/mintwaterfall.esm.js +7907 -0
  7. package/dist/mintwaterfall.min.js +7 -0
  8. package/dist/mintwaterfall.umd.js +7978 -0
  9. package/index.d.ts +149 -0
  10. package/package.json +126 -0
  11. package/src/enterprise/enterprise-core.js +0 -0
  12. package/src/enterprise/enterprise-feature-template.js +0 -0
  13. package/src/enterprise/feature-registry.js +0 -0
  14. package/src/enterprise/features/breakdown.js +0 -0
  15. package/src/features/breakdown.js +0 -0
  16. package/src/features/conditional-formatting.js +0 -0
  17. package/src/index.js +111 -0
  18. package/src/mintwaterfall-accessibility.ts +680 -0
  19. package/src/mintwaterfall-advanced-data.ts +1034 -0
  20. package/src/mintwaterfall-advanced-interactions.ts +649 -0
  21. package/src/mintwaterfall-advanced-performance.ts +582 -0
  22. package/src/mintwaterfall-animations.ts +595 -0
  23. package/src/mintwaterfall-brush.ts +471 -0
  24. package/src/mintwaterfall-chart-core.ts +296 -0
  25. package/src/mintwaterfall-chart.ts +1915 -0
  26. package/src/mintwaterfall-data.ts +1100 -0
  27. package/src/mintwaterfall-export.ts +475 -0
  28. package/src/mintwaterfall-hierarchical-layouts.ts +724 -0
  29. package/src/mintwaterfall-layouts.ts +647 -0
  30. package/src/mintwaterfall-performance.ts +573 -0
  31. package/src/mintwaterfall-scales.ts +437 -0
  32. package/src/mintwaterfall-shapes.ts +385 -0
  33. package/src/mintwaterfall-statistics.ts +821 -0
  34. package/src/mintwaterfall-themes.ts +391 -0
  35. package/src/mintwaterfall-tooltip.ts +450 -0
  36. package/src/mintwaterfall-zoom.ts +399 -0
  37. package/src/types/js-modules.d.ts +25 -0
  38. package/src/utils/compatibility-layer.js +0 -0
@@ -0,0 +1,296 @@
1
+ // MintWaterfall Chart - TypeScript Core Module (Gradual Migration)
2
+ // This is the first module converted as part of gradual migration strategy
3
+
4
+ import * as d3 from 'd3';
5
+
6
+ // ============================================================================
7
+ // TYPE DEFINITIONS
8
+ // ============================================================================
9
+
10
+ export interface StackData {
11
+ value: number;
12
+ color: string;
13
+ label?: string;
14
+ }
15
+
16
+ export interface ChartData {
17
+ label: string;
18
+ stacks: StackData[];
19
+ }
20
+
21
+ export interface ProcessedData extends ChartData {
22
+ barTotal: number;
23
+ cumulativeTotal: number;
24
+ prevCumulativeTotal?: number;
25
+ }
26
+
27
+ export interface MarginConfig {
28
+ top: number;
29
+ right: number;
30
+ bottom: number;
31
+ left: number;
32
+ }
33
+
34
+ export interface WaterfallChartConfig {
35
+ width: number;
36
+ height: number;
37
+ margin: MarginConfig;
38
+ showTotal: boolean;
39
+ totalLabel: string;
40
+ totalColor: string;
41
+ stacked: boolean;
42
+ barPadding: number;
43
+ duration: number;
44
+ formatNumber: (n: number) => string;
45
+ }
46
+
47
+ // ============================================================================
48
+ // MAIN CHART FACTORY FUNCTION
49
+ // ============================================================================
50
+
51
+ export function waterfallChart() {
52
+ // Configuration with defaults
53
+ let config: WaterfallChartConfig = {
54
+ width: 800,
55
+ height: 400,
56
+ margin: { top: 60, right: 80, bottom: 60, left: 80 },
57
+ showTotal: false,
58
+ totalLabel: "Total",
59
+ totalColor: "#95A5A6",
60
+ stacked: true,
61
+ barPadding: 0.1,
62
+ duration: 750,
63
+ formatNumber: d3.format(".0f")
64
+ };
65
+
66
+ // Cache for performance
67
+ let lastDataHash: string | null = null;
68
+ let cachedProcessedData: ProcessedData[] | null = null;
69
+
70
+ function chart(selection: d3.Selection<any, any, any, any>): void {
71
+ selection.each(function(data: ChartData[]) {
72
+ // Basic data validation
73
+ if (!data || !Array.isArray(data) || data.length === 0) {
74
+ console.warn("MintWaterfall: Invalid or empty data provided");
75
+ return;
76
+ }
77
+
78
+ // Process data
79
+ const processedData = prepareData(data);
80
+
81
+ // Render chart
82
+ renderChart(d3.select(this), processedData);
83
+ });
84
+ }
85
+
86
+ // ========================================================================
87
+ // CORE PROCESSING FUNCTIONS
88
+ // ========================================================================
89
+
90
+ function prepareData(data: ChartData[]): ProcessedData[] {
91
+ // Quick hash for caching
92
+ const dataHash = JSON.stringify(data).slice(0, 100) + config.showTotal.toString();
93
+
94
+ if (dataHash === lastDataHash && cachedProcessedData) {
95
+ return cachedProcessedData;
96
+ }
97
+
98
+ let cumulativeTotal = 0;
99
+ const processedData: ProcessedData[] = data.map((item, i) => {
100
+ const barTotal = item.stacks.reduce((sum, stack) => sum + stack.value, 0);
101
+ const prevCumulativeTotal = cumulativeTotal;
102
+ cumulativeTotal += barTotal;
103
+
104
+ return {
105
+ ...item,
106
+ barTotal,
107
+ cumulativeTotal,
108
+ prevCumulativeTotal: i === 0 ? 0 : prevCumulativeTotal
109
+ };
110
+ });
111
+
112
+ // Add total bar if enabled
113
+ if (config.showTotal && processedData.length > 0) {
114
+ processedData.push({
115
+ label: config.totalLabel,
116
+ stacks: [{ value: cumulativeTotal, color: config.totalColor }],
117
+ barTotal: cumulativeTotal,
118
+ cumulativeTotal,
119
+ prevCumulativeTotal: 0
120
+ });
121
+ }
122
+
123
+ // Cache results
124
+ lastDataHash = dataHash;
125
+ cachedProcessedData = processedData;
126
+
127
+ return processedData;
128
+ }
129
+
130
+ function renderChart(svg: d3.Selection<any, any, any, any>, data: ProcessedData[]): void {
131
+ // Clear previous content
132
+ svg.selectAll("*").remove();
133
+
134
+ // Calculate dimensions
135
+ const { width, height, margin } = config;
136
+ const innerWidth = width - margin.left - margin.right;
137
+ const innerHeight = height - margin.top - margin.bottom;
138
+
139
+ // Create main container
140
+ const g = svg.append("g")
141
+ .attr("transform", `translate(${margin.left},${margin.top})`);
142
+
143
+ // Set up scales
144
+ const xScale = d3.scaleBand()
145
+ .domain(data.map(d => d.label))
146
+ .range([0, innerWidth])
147
+ .padding(config.barPadding);
148
+
149
+ const yExtent = d3.extent(data, d => d.cumulativeTotal) as [number, number];
150
+ const yScale = d3.scaleLinear()
151
+ .domain([Math.min(0, yExtent[0]), yExtent[1]])
152
+ .range([innerHeight, 0])
153
+ .nice();
154
+
155
+ // Create axes
156
+ const xAxis = d3.axisBottom(xScale);
157
+ const yAxis = d3.axisLeft(yScale).tickFormat((d: d3.NumberValue) => config.formatNumber(d.valueOf()));
158
+
159
+ g.append("g")
160
+ .attr("class", "x-axis")
161
+ .attr("transform", `translate(0,${innerHeight})`)
162
+ .call(xAxis);
163
+
164
+ g.append("g")
165
+ .attr("class", "y-axis")
166
+ .call(yAxis);
167
+
168
+ // Draw bars
169
+ const bars = g.selectAll(".bar")
170
+ .data(data)
171
+ .enter().append("g")
172
+ .attr("class", "bar")
173
+ .attr("transform", d => `translate(${xScale(d.label)},0)`);
174
+
175
+ if (config.stacked) {
176
+ drawStackedBars(bars, xScale, yScale);
177
+ } else {
178
+ drawWaterfallBars(bars, xScale, yScale);
179
+ }
180
+
181
+ // Add value labels
182
+ addValueLabels(bars, xScale, yScale);
183
+ }
184
+
185
+ function drawStackedBars(bars: d3.Selection<SVGGElement, ProcessedData, any, any>,
186
+ xScale: d3.ScaleBand<string>,
187
+ yScale: d3.ScaleLinear<number, number>): void {
188
+ bars.each(function(d) {
189
+ const bar = d3.select(this);
190
+ let yPos = d.prevCumulativeTotal || 0;
191
+
192
+ d.stacks.forEach(stack => {
193
+ const rectHeight = Math.abs(yScale(yPos) - yScale(yPos + stack.value));
194
+ const rectY = yScale(Math.max(yPos, yPos + stack.value));
195
+
196
+ bar.append("rect")
197
+ .attr("width", xScale.bandwidth())
198
+ .attr("height", rectHeight)
199
+ .attr("y", rectY)
200
+ .attr("fill", stack.color)
201
+ .attr("stroke", "#fff")
202
+ .attr("stroke-width", 1);
203
+
204
+ yPos += stack.value;
205
+ });
206
+ });
207
+ }
208
+
209
+ function drawWaterfallBars(bars: d3.Selection<SVGGElement, ProcessedData, any, any>,
210
+ xScale: d3.ScaleBand<string>,
211
+ yScale: d3.ScaleLinear<number, number>): void {
212
+ bars.each(function(d) {
213
+ const bar = d3.select(this);
214
+ const startY = d.prevCumulativeTotal || 0;
215
+ const endY = d.cumulativeTotal;
216
+ const rectHeight = Math.abs(yScale(startY) - yScale(endY));
217
+ const rectY = yScale(Math.max(startY, endY));
218
+
219
+ // Use first stack color or generate based on positive/negative
220
+ const color = d.stacks[0]?.color || (d.barTotal >= 0 ? "#2ecc71" : "#e74c3c");
221
+
222
+ bar.append("rect")
223
+ .attr("width", xScale.bandwidth())
224
+ .attr("height", rectHeight)
225
+ .attr("y", rectY)
226
+ .attr("fill", color)
227
+ .attr("stroke", "#fff")
228
+ .attr("stroke-width", 1);
229
+ });
230
+ }
231
+
232
+ function addValueLabels(bars: d3.Selection<SVGGElement, ProcessedData, any, any>,
233
+ xScale: d3.ScaleBand<string>,
234
+ yScale: d3.ScaleLinear<number, number>): void {
235
+ bars.append("text")
236
+ .attr("x", xScale.bandwidth() / 2)
237
+ .attr("y", d => yScale(d.cumulativeTotal) - 5)
238
+ .attr("text-anchor", "middle")
239
+ .style("font-size", "12px")
240
+ .style("font-family", "Arial, sans-serif")
241
+ .text(d => config.formatNumber(d.cumulativeTotal));
242
+ }
243
+
244
+ // ========================================================================
245
+ // GETTER/SETTER API (TypeScript style with proper overloads)
246
+ // ========================================================================
247
+
248
+ function createAccessor<T>(key: keyof WaterfallChartConfig) {
249
+ return function(value?: T): any {
250
+ if (arguments.length === 0) {
251
+ return config[key];
252
+ }
253
+ (config as any)[key] = value;
254
+ return chart;
255
+ };
256
+ }
257
+
258
+ // Public API using accessor pattern
259
+ chart.width = createAccessor<number>('width');
260
+ chart.height = createAccessor<number>('height');
261
+ chart.margin = createAccessor<MarginConfig>('margin');
262
+ chart.showTotal = createAccessor<boolean>('showTotal');
263
+ chart.totalLabel = createAccessor<string>('totalLabel');
264
+ chart.totalColor = createAccessor<string>('totalColor');
265
+ chart.stacked = createAccessor<boolean>('stacked');
266
+ chart.barPadding = createAccessor<number>('barPadding');
267
+ chart.duration = createAccessor<number>('duration');
268
+ chart.formatNumber = createAccessor<(n: number) => string>('formatNumber');
269
+
270
+ // Utility methods
271
+ chart.config = function(): WaterfallChartConfig {
272
+ return { ...config };
273
+ };
274
+
275
+ chart.reset = function() {
276
+ lastDataHash = null;
277
+ cachedProcessedData = null;
278
+ return chart;
279
+ };
280
+
281
+ return chart;
282
+ }
283
+
284
+ // ============================================================================
285
+ // INTEGRATION WITH D3 (Temporary for gradual migration)
286
+ // ============================================================================
287
+
288
+ // Add to d3 namespace for compatibility
289
+ declare module 'd3' {
290
+ interface D3 {
291
+ waterfallChart(): any;
292
+ }
293
+ }
294
+
295
+ // Extend d3 object
296
+ (d3 as any).waterfallChart = waterfallChart;