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,437 @@
1
+ // MintWaterfall Enhanced Scales System - TypeScript Version
2
+ // Provides advanced D3.js scale support including time and ordinal scales with full type safety
3
+
4
+ import * as d3 from 'd3';
5
+
6
+ // Type definitions for scale systems
7
+ export interface ScaleSystemOptions {
8
+ range?: [number, number];
9
+ nice?: boolean;
10
+ padding?: number;
11
+ }
12
+
13
+ export interface TimeScaleOptions {
14
+ range?: [number, number];
15
+ nice?: boolean;
16
+ tickFormat?: string | 'auto';
17
+ }
18
+
19
+ export interface OrdinalScaleOptions {
20
+ range?: string[];
21
+ unknown?: string;
22
+ }
23
+
24
+ export interface BandScaleOptions {
25
+ padding?: number;
26
+ paddingInner?: number | null;
27
+ paddingOuter?: number | null;
28
+ align?: number;
29
+ range?: [number, number];
30
+ }
31
+
32
+ export interface LinearScaleOptions {
33
+ range?: [number, number];
34
+ nice?: boolean;
35
+ zero?: boolean;
36
+ clamp?: boolean;
37
+ }
38
+
39
+ export type ScaleType = 'linear' | 'band' | 'time' | 'ordinal' | 'adaptive';
40
+ export type DimensionType = 'x' | 'y';
41
+
42
+ // Scale factory interface
43
+ export interface ScaleFactory {
44
+ createAdaptiveScale(data: any[], dimension?: DimensionType): d3.ScaleLinear<number, number> | d3.ScaleBand<string> | d3.ScaleTime<number, number>;
45
+ createTimeScale(values: Date[], options?: TimeScaleOptions): d3.ScaleTime<number, number>;
46
+ createOrdinalScale(values: any[], options?: OrdinalScaleOptions): d3.ScaleOrdinal<any, string, string>;
47
+ createBandScale(values: any[], options?: BandScaleOptions): d3.ScaleBand<string>;
48
+ createLinearScale(values: number[], options?: LinearScaleOptions): d3.ScaleLinear<number, number>;
49
+ createLogScale(values: number[], options?: LinearScaleOptions): d3.ScaleLogarithmic<number, number> | d3.ScaleLinear<number, number>;
50
+ setDefaultRange(range: [number, number]): void;
51
+ getScaleInfo(scale: any): ScaleInfo;
52
+ scaleUtils: ScaleUtilities;
53
+ }
54
+
55
+ export interface ScaleInfo {
56
+ type: string;
57
+ domain: any[];
58
+ range: any[];
59
+ bandwidth?: number;
60
+ step?: number;
61
+ }
62
+
63
+ export function createScaleSystem(): ScaleFactory {
64
+ let defaultRange: [number, number] = [0, 800];
65
+
66
+ // Enhanced scale factory with auto-detection
67
+ function createAdaptiveScale(data: any[], dimension: DimensionType = "x"): d3.ScaleLinear<number, number> | d3.ScaleBand<string> | d3.ScaleTime<number, number> {
68
+ const values = data.map(d => dimension === "x" ? d.label : d.cumulativeTotal);
69
+
70
+ // Detect data type and return appropriate scale
71
+ if (values.every(v => v instanceof Date)) {
72
+ return createTimeScale(values);
73
+ } else if (values.every(v => typeof v === "string" || isNaN(v))) {
74
+ // For categorical/string data, use band scale for positioning
75
+ return createBandScale(values);
76
+ } else if (values.every(v => typeof v === "number")) {
77
+ return createLinearScale(values);
78
+ } else {
79
+ // Mixed types - fallback to band scale
80
+ return d3.scaleBand<string>().domain(values.map(String)).range(defaultRange);
81
+ }
82
+ }
83
+
84
+ // Time scale with intelligent formatting
85
+ function createTimeScale(values: Date[], options: TimeScaleOptions = {}): d3.ScaleTime<number, number> {
86
+ const {
87
+ range = defaultRange,
88
+ nice = true,
89
+ tickFormat = "auto"
90
+ } = options;
91
+
92
+ const extent = d3.extent(values) as [Date, Date];
93
+ const scale = d3.scaleTime()
94
+ .domain(extent)
95
+ .range(range);
96
+
97
+ if (nice) {
98
+ scale.nice();
99
+ }
100
+
101
+ // Auto-detect appropriate time format
102
+ if (tickFormat === "auto" && extent[0] && extent[1] && extent[0] instanceof Date && extent[1] instanceof Date) {
103
+ const timeSpan = extent[1].getTime() - extent[0].getTime();
104
+ const days = timeSpan / (1000 * 60 * 60 * 24);
105
+
106
+ if (days < 1) {
107
+ (scale as any).tickFormat = d3.timeFormat("%H:%M");
108
+ } else if (days < 30) {
109
+ (scale as any).tickFormat = d3.timeFormat("%m/%d");
110
+ } else if (days < 365) {
111
+ (scale as any).tickFormat = d3.timeFormat("%b %Y");
112
+ } else {
113
+ (scale as any).tickFormat = d3.timeFormat("%Y");
114
+ }
115
+ } else if (typeof tickFormat === "string") {
116
+ (scale as any).tickFormat = d3.timeFormat(tickFormat);
117
+ }
118
+
119
+ return scale;
120
+ }
121
+
122
+ // Enhanced ordinal scale with color mapping
123
+ function createOrdinalScale(values: any[], options: OrdinalScaleOptions = {}): d3.ScaleOrdinal<any, string, string> {
124
+ const {
125
+ range = d3.schemeCategory10,
126
+ unknown = "#ccc"
127
+ } = options;
128
+
129
+ const uniqueValues = [...new Set(values)];
130
+
131
+ return d3.scaleOrdinal<any, string>()
132
+ .domain(uniqueValues)
133
+ .range(range)
134
+ .unknown(unknown as string) as d3.ScaleOrdinal<any, string, string>;
135
+ }
136
+
137
+ // Band scale for categorical data positioning
138
+ function createBandScale(values: any[], options: BandScaleOptions = {}): d3.ScaleBand<string> {
139
+ const {
140
+ padding = 0.1,
141
+ paddingInner = null,
142
+ paddingOuter = null,
143
+ align = 0.5,
144
+ range = defaultRange
145
+ } = options;
146
+
147
+ const uniqueValues = [...new Set(values.map(String))];
148
+ const scale = d3.scaleBand<string>()
149
+ .domain(uniqueValues)
150
+ .range(range)
151
+ .align(align);
152
+
153
+ if (paddingInner !== null) {
154
+ scale.paddingInner(paddingInner);
155
+ }
156
+ if (paddingOuter !== null) {
157
+ scale.paddingOuter(paddingOuter);
158
+ }
159
+ if (paddingInner === null && paddingOuter === null) {
160
+ scale.padding(padding);
161
+ }
162
+
163
+ return scale;
164
+ }
165
+
166
+ // Linear scale with enhanced options
167
+ function createLinearScale(values: number[], options: LinearScaleOptions = {}): d3.ScaleLinear<number, number> {
168
+ const {
169
+ range = defaultRange,
170
+ nice = true,
171
+ zero = false,
172
+ clamp = false
173
+ } = options;
174
+
175
+ let domain = d3.extent(values) as [number, number];
176
+
177
+ // Include zero in domain if requested
178
+ if (zero) {
179
+ domain = [Math.min(0, domain[0]), Math.max(0, domain[1])];
180
+ }
181
+
182
+ const scale = d3.scaleLinear()
183
+ .domain(domain)
184
+ .range(range);
185
+
186
+ if (nice) {
187
+ scale.nice();
188
+ }
189
+
190
+ if (clamp) {
191
+ scale.clamp(true);
192
+ }
193
+
194
+ return scale;
195
+ }
196
+
197
+ function setDefaultRange(range: [number, number]): void {
198
+ defaultRange = range;
199
+ }
200
+
201
+ function getScaleInfo(scale: any): ScaleInfo {
202
+ const info: ScaleInfo = {
203
+ type: 'unknown',
204
+ domain: [],
205
+ range: []
206
+ };
207
+
208
+ try {
209
+ info.domain = scale.domain();
210
+ info.range = scale.range();
211
+
212
+ // Detect scale type
213
+ if (typeof scale.bandwidth === 'function') {
214
+ info.type = 'band';
215
+ info.bandwidth = scale.bandwidth();
216
+ if (typeof scale.step === 'function') {
217
+ info.step = scale.step();
218
+ }
219
+ } else if (typeof scale.nice === 'function') {
220
+ // Check if it's a time scale by testing if domain contains dates
221
+ if (info.domain.length > 0 && info.domain[0] instanceof Date) {
222
+ info.type = 'time';
223
+ } else {
224
+ info.type = 'linear';
225
+ }
226
+ } else if (typeof scale.unknown === 'function') {
227
+ info.type = 'ordinal';
228
+ }
229
+ } catch (e) {
230
+ // Fallback for scales that don't support these methods
231
+ console.warn('Could not extract complete scale info:', e);
232
+ }
233
+
234
+ return info;
235
+ }
236
+
237
+ // Log scale with fallback to linear for non-positive values
238
+ function createLogScale(values: number[], options: LinearScaleOptions = {}): d3.ScaleLogarithmic<number, number> | d3.ScaleLinear<number, number> {
239
+ // Check if all values are positive for log scale
240
+ const hasNonPositive = values.some(v => v <= 0);
241
+
242
+ if (hasNonPositive) {
243
+ // Fallback to linear scale
244
+ return createLinearScale(values, options);
245
+ }
246
+
247
+ const {
248
+ range = defaultRange,
249
+ nice = true,
250
+ clamp = false
251
+ } = options;
252
+
253
+ const domain = d3.extent(values) as [number, number];
254
+ const scale = d3.scaleLog()
255
+ .domain(domain)
256
+ .range(range);
257
+
258
+ if (nice) {
259
+ scale.nice();
260
+ }
261
+
262
+ if (clamp) {
263
+ scale.clamp(true);
264
+ }
265
+
266
+ return scale;
267
+ }
268
+
269
+ return {
270
+ createAdaptiveScale,
271
+ createTimeScale,
272
+ createOrdinalScale,
273
+ createBandScale,
274
+ createLinearScale,
275
+ createLogScale,
276
+ setDefaultRange,
277
+ getScaleInfo,
278
+ scaleUtils: createScaleUtilities()
279
+ };
280
+ }
281
+
282
+ // Standalone scale creation functions for backward compatibility
283
+ export function createTimeScale(values: Date[], options: TimeScaleOptions = {}): d3.ScaleTime<number, number> {
284
+ const factory = createScaleSystem();
285
+ if (options.range) {
286
+ factory.setDefaultRange(options.range);
287
+ }
288
+ return factory.createTimeScale(values, options);
289
+ }
290
+
291
+ export function createOrdinalScale(values: any[], options: OrdinalScaleOptions = {}): d3.ScaleOrdinal<any, string, string> {
292
+ const factory = createScaleSystem();
293
+ const scale = factory.createOrdinalScale(values, options);
294
+ // Ensure the scale is properly configured and callable
295
+ return scale as d3.ScaleOrdinal<any, string, string>;
296
+ }
297
+
298
+ export function createBandScale(values: any[], options: BandScaleOptions = {}): d3.ScaleBand<string> {
299
+ const factory = createScaleSystem();
300
+ // Set a default range for band scales if not provided
301
+ const range = options.range || [0, 400];
302
+ factory.setDefaultRange(range as [number, number]);
303
+ return factory.createBandScale(values, options);
304
+ }
305
+
306
+ export function createLinearScale(values: number[], options: LinearScaleOptions = {}): d3.ScaleLinear<number, number> {
307
+ const factory = createScaleSystem();
308
+ if (options.range) {
309
+ factory.setDefaultRange(options.range);
310
+ }
311
+ return factory.createLinearScale(values, options);
312
+ }
313
+
314
+ // Enhanced scale utilities
315
+ export interface ScaleUtilities {
316
+ formatTickValue(scale: any, value: any): string;
317
+ getTickCount(scale: any, targetSize: number): number;
318
+ createColorScale(domain: any[], scheme?: readonly string[]): d3.ScaleOrdinal<any, string, string>;
319
+ invertScale(scale: any, pixel: number): any;
320
+ detectScaleType(values: any[]): ScaleType;
321
+ createAxis(scale: any, orientation?: 'top' | 'bottom' | 'left' | 'right'): any;
322
+ }
323
+
324
+ export function createScaleUtilities(): ScaleUtilities {
325
+
326
+ function formatTickValue(scale: any, value: any): string {
327
+ if (typeof scale.tickFormat === 'function') {
328
+ // Time scales
329
+ return scale.tickFormat()(value);
330
+ } else if (scale.tickFormat) {
331
+ // Scales with custom formatters
332
+ return scale.tickFormat(value);
333
+ } else if (typeof value === 'number') {
334
+ // Default number formatting
335
+ if (Math.abs(value) >= 1000000) {
336
+ return `${(value / 1000000).toFixed(1)}M`;
337
+ } else if (Math.abs(value) >= 1000) {
338
+ return `${(value / 1000).toFixed(1)}K`;
339
+ } else {
340
+ return value.toFixed(0);
341
+ }
342
+ } else {
343
+ return String(value);
344
+ }
345
+ }
346
+
347
+ function getTickCount(scale: any, targetSize: number): number {
348
+ const range = scale.range();
349
+ const rangeSize = Math.abs(range[1] - range[0]);
350
+
351
+ // Aim for ticks every 50-100 pixels
352
+ const idealTickCount = Math.max(2, Math.floor(rangeSize / 75));
353
+
354
+ // Cap at reasonable limits
355
+ return Math.min(10, Math.max(2, idealTickCount));
356
+ }
357
+
358
+ function createColorScale(domain: any[], scheme: readonly string[] = d3.schemeCategory10): d3.ScaleOrdinal<any, string, string> {
359
+ return d3.scaleOrdinal<any, string, string>()
360
+ .domain(domain)
361
+ .range([...scheme]);
362
+ }
363
+
364
+ function invertScale(scale: any, pixel: number): any {
365
+ if (typeof scale.invert === 'function') {
366
+ // Linear and time scales
367
+ return scale.invert(pixel);
368
+ } else if (typeof scale.bandwidth === 'function') {
369
+ // Band scales - find the band that contains the pixel
370
+ const domain = scale.domain();
371
+ const bandwidth = scale.bandwidth();
372
+ const step = scale.step();
373
+
374
+ for (let i = 0; i < domain.length; i++) {
375
+ const bandStart = scale(domain[i]);
376
+ if (pixel >= bandStart && pixel <= bandStart + bandwidth) {
377
+ return domain[i];
378
+ }
379
+ }
380
+
381
+ // If not in any band, return closest
382
+ const distances = domain.map((d: any) => Math.abs(scale(d) + bandwidth / 2 - pixel));
383
+ const minIndex = distances.indexOf(Math.min(...distances));
384
+ return domain[minIndex];
385
+ } else {
386
+ // Ordinal scales - return undefined for pixel-based inversion
387
+ return undefined;
388
+ }
389
+ }
390
+
391
+ function detectScaleType(values: any[]): ScaleType {
392
+ if (values.every(v => v instanceof Date)) {
393
+ return 'time';
394
+ } else if (values.every(v => typeof v === "string" || isNaN(v))) {
395
+ return 'band';
396
+ } else if (values.every(v => typeof v === "number")) {
397
+ return 'linear';
398
+ } else {
399
+ return 'adaptive';
400
+ }
401
+ }
402
+
403
+ function createAxis(scale: any, orientation: 'top' | 'bottom' | 'left' | 'right' = 'bottom'): any {
404
+ let axis;
405
+
406
+ switch (orientation) {
407
+ case 'top':
408
+ axis = d3.axisTop(scale);
409
+ break;
410
+ case 'bottom':
411
+ axis = d3.axisBottom(scale);
412
+ break;
413
+ case 'left':
414
+ axis = d3.axisLeft(scale);
415
+ break;
416
+ case 'right':
417
+ axis = d3.axisRight(scale);
418
+ break;
419
+ default:
420
+ axis = d3.axisBottom(scale);
421
+ }
422
+
423
+ return axis;
424
+ }
425
+
426
+ return {
427
+ formatTickValue,
428
+ getTickCount,
429
+ createColorScale,
430
+ invertScale,
431
+ detectScaleType,
432
+ createAxis
433
+ };
434
+ }
435
+
436
+ // Export default instance for convenience
437
+ export const scaleUtilities = createScaleUtilities();