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.
- package/CHANGELOG.md +223 -0
- package/CONTRIBUTING.md +199 -0
- package/README.md +363 -0
- package/dist/index.d.ts +149 -0
- package/dist/mintwaterfall.cjs.js +7978 -0
- package/dist/mintwaterfall.esm.js +7907 -0
- package/dist/mintwaterfall.min.js +7 -0
- package/dist/mintwaterfall.umd.js +7978 -0
- package/index.d.ts +149 -0
- package/package.json +126 -0
- package/src/enterprise/enterprise-core.js +0 -0
- package/src/enterprise/enterprise-feature-template.js +0 -0
- package/src/enterprise/feature-registry.js +0 -0
- package/src/enterprise/features/breakdown.js +0 -0
- package/src/features/breakdown.js +0 -0
- package/src/features/conditional-formatting.js +0 -0
- package/src/index.js +111 -0
- package/src/mintwaterfall-accessibility.ts +680 -0
- package/src/mintwaterfall-advanced-data.ts +1034 -0
- package/src/mintwaterfall-advanced-interactions.ts +649 -0
- package/src/mintwaterfall-advanced-performance.ts +582 -0
- package/src/mintwaterfall-animations.ts +595 -0
- package/src/mintwaterfall-brush.ts +471 -0
- package/src/mintwaterfall-chart-core.ts +296 -0
- package/src/mintwaterfall-chart.ts +1915 -0
- package/src/mintwaterfall-data.ts +1100 -0
- package/src/mintwaterfall-export.ts +475 -0
- package/src/mintwaterfall-hierarchical-layouts.ts +724 -0
- package/src/mintwaterfall-layouts.ts +647 -0
- package/src/mintwaterfall-performance.ts +573 -0
- package/src/mintwaterfall-scales.ts +437 -0
- package/src/mintwaterfall-shapes.ts +385 -0
- package/src/mintwaterfall-statistics.ts +821 -0
- package/src/mintwaterfall-themes.ts +391 -0
- package/src/mintwaterfall-tooltip.ts +450 -0
- package/src/mintwaterfall-zoom.ts +399 -0
- package/src/types/js-modules.d.ts +25 -0
- package/src/utils/compatibility-layer.js +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// MintWaterfall Zoom & Pan System - TypeScript Version
|
|
2
|
+
// Provides interactive zoom and pan functionality with smooth performance and full type safety
|
|
3
|
+
|
|
4
|
+
import * as d3 from 'd3';
|
|
5
|
+
|
|
6
|
+
// Type definitions for zoom system
|
|
7
|
+
export interface ZoomConfig {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
scaleExtent: [number, number];
|
|
10
|
+
translateExtent: [[number, number], [number, number]] | null;
|
|
11
|
+
wheelDelta: ((event: WheelEvent) => number) | null;
|
|
12
|
+
touchable: boolean;
|
|
13
|
+
filter: ((event: any) => boolean) | null;
|
|
14
|
+
constrain: {
|
|
15
|
+
x: boolean;
|
|
16
|
+
y: boolean;
|
|
17
|
+
};
|
|
18
|
+
duration: number;
|
|
19
|
+
ease: (t: number) => number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ChartDimensions {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
margin: {
|
|
26
|
+
top: number;
|
|
27
|
+
right: number;
|
|
28
|
+
bottom: number;
|
|
29
|
+
left: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ZoomEventData {
|
|
34
|
+
transform: d3.ZoomTransform;
|
|
35
|
+
sourceEvent: any;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ZoomTransition {
|
|
39
|
+
to: d3.ZoomTransform;
|
|
40
|
+
duration?: number;
|
|
41
|
+
ease?: (t: number) => number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ZoomBounds {
|
|
45
|
+
x: [number, number];
|
|
46
|
+
y: [number, number];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ZoomSystem {
|
|
50
|
+
enable(): ZoomSystem;
|
|
51
|
+
disable(): ZoomSystem;
|
|
52
|
+
attach(container: d3.Selection<any, any, any, any>): ZoomSystem;
|
|
53
|
+
detach(): ZoomSystem;
|
|
54
|
+
transform(selection: d3.Selection<any, any, any, any>, transform: d3.ZoomTransform, duration?: number): ZoomSystem;
|
|
55
|
+
reset(duration?: number): ZoomSystem;
|
|
56
|
+
zoomTo(bounds: ZoomBounds, duration?: number): ZoomSystem;
|
|
57
|
+
setDimensions(dimensions: ChartDimensions): ZoomSystem;
|
|
58
|
+
configure(newConfig: Partial<ZoomConfig>): ZoomSystem;
|
|
59
|
+
getCurrentTransform(): d3.ZoomTransform;
|
|
60
|
+
isEnabled(): boolean;
|
|
61
|
+
on(type: string, callback: (event: ZoomEventData) => void): ZoomSystem;
|
|
62
|
+
off(type: string, callback?: (event: ZoomEventData) => void): ZoomSystem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type ZoomEventType = 'zoomstart' | 'zoom' | 'zoomend' | 'reset';
|
|
66
|
+
|
|
67
|
+
export function createZoomSystem(): ZoomSystem {
|
|
68
|
+
|
|
69
|
+
// Zoom configuration
|
|
70
|
+
const config: ZoomConfig = {
|
|
71
|
+
enabled: true,
|
|
72
|
+
scaleExtent: [0.1, 10],
|
|
73
|
+
translateExtent: null, // Auto-calculated based on chart dimensions
|
|
74
|
+
wheelDelta: null, // Use D3 default for proper zoom in/out
|
|
75
|
+
touchable: true,
|
|
76
|
+
filter: null, // Custom filter function
|
|
77
|
+
constrain: {
|
|
78
|
+
x: true,
|
|
79
|
+
y: true
|
|
80
|
+
},
|
|
81
|
+
duration: 250,
|
|
82
|
+
ease: d3.easeQuadOut
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
let zoomBehavior: d3.ZoomBehavior<any, any> | null = null;
|
|
86
|
+
let currentTransform: d3.ZoomTransform = d3.zoomIdentity;
|
|
87
|
+
let chartContainer: d3.Selection<any, any, any, any> | null = null;
|
|
88
|
+
let chartDimensions: ChartDimensions = {
|
|
89
|
+
width: 800,
|
|
90
|
+
height: 400,
|
|
91
|
+
margin: { top: 60, right: 80, bottom: 60, left: 80 }
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Event listeners
|
|
95
|
+
const listeners = d3.dispatch("zoomstart", "zoom", "zoomend", "reset");
|
|
96
|
+
|
|
97
|
+
function createZoomBehavior(): d3.ZoomBehavior<any, any> {
|
|
98
|
+
if (zoomBehavior) return zoomBehavior;
|
|
99
|
+
|
|
100
|
+
zoomBehavior = d3.zoom<any, any>()
|
|
101
|
+
.scaleExtent(config.scaleExtent)
|
|
102
|
+
.touchable(config.touchable)
|
|
103
|
+
.filter(config.filter || defaultFilter)
|
|
104
|
+
.on("start", handleZoomStart)
|
|
105
|
+
.on("zoom", handleZoom)
|
|
106
|
+
.on("end", handleZoomEnd);
|
|
107
|
+
|
|
108
|
+
// Only set wheelDelta if explicitly configured (null means use D3 default)
|
|
109
|
+
if (config.wheelDelta !== null) {
|
|
110
|
+
zoomBehavior.wheelDelta(config.wheelDelta);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
updateTranslateExtent();
|
|
114
|
+
return zoomBehavior;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function defaultFilter(event: any): boolean {
|
|
118
|
+
// Allow zoom on wheel, but prevent on right-click
|
|
119
|
+
return (!event.ctrlKey || event.type === "wheel") && !event.button;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function updateTranslateExtent(): void {
|
|
123
|
+
if (!zoomBehavior || !chartDimensions) return;
|
|
124
|
+
|
|
125
|
+
const { width, height, margin } = chartDimensions;
|
|
126
|
+
const chartWidth = width - margin.left - margin.right;
|
|
127
|
+
const chartHeight = height - margin.top - margin.bottom;
|
|
128
|
+
|
|
129
|
+
// Calculate translate extent based on zoom constraints
|
|
130
|
+
const extent: [[number, number], [number, number]] = config.translateExtent || [
|
|
131
|
+
[-chartWidth * 2, -chartHeight * 2],
|
|
132
|
+
[chartWidth * 3, chartHeight * 3]
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
zoomBehavior.translateExtent(extent);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function handleZoomStart(event: d3.D3ZoomEvent<any, any>): void {
|
|
139
|
+
const eventData: ZoomEventData = {
|
|
140
|
+
transform: event.transform,
|
|
141
|
+
sourceEvent: event.sourceEvent
|
|
142
|
+
};
|
|
143
|
+
listeners.call("zoomstart", undefined, eventData);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function handleZoom(event: d3.D3ZoomEvent<any, any>): void {
|
|
147
|
+
currentTransform = event.transform;
|
|
148
|
+
|
|
149
|
+
// Apply constraints if specified
|
|
150
|
+
if (!config.constrain.x) {
|
|
151
|
+
currentTransform = currentTransform.translate(-currentTransform.x, 0);
|
|
152
|
+
}
|
|
153
|
+
if (!config.constrain.y) {
|
|
154
|
+
currentTransform = currentTransform.translate(0, -currentTransform.y);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Apply transform to chart elements
|
|
158
|
+
if (chartContainer) {
|
|
159
|
+
applyTransform(chartContainer, currentTransform);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const eventData: ZoomEventData = {
|
|
163
|
+
transform: currentTransform,
|
|
164
|
+
sourceEvent: event.sourceEvent
|
|
165
|
+
};
|
|
166
|
+
listeners.call("zoom", undefined, eventData);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function handleZoomEnd(event: d3.D3ZoomEvent<any, any>): void {
|
|
170
|
+
const eventData: ZoomEventData = {
|
|
171
|
+
transform: event.transform,
|
|
172
|
+
sourceEvent: event.sourceEvent
|
|
173
|
+
};
|
|
174
|
+
listeners.call("zoomend", undefined, eventData);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function applyTransform(container: d3.Selection<any, any, any, any>, transform: d3.ZoomTransform): void {
|
|
178
|
+
// Apply transform to the main chart group
|
|
179
|
+
const chartGroup = container.select(".chart-group");
|
|
180
|
+
if (!chartGroup.empty()) {
|
|
181
|
+
chartGroup.attr("transform", transform.toString());
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Update axes if they exist
|
|
185
|
+
updateAxes(container, transform);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function updateAxes(container: d3.Selection<any, any, any, any>, transform: d3.ZoomTransform): void {
|
|
189
|
+
// Update X axis if constrained
|
|
190
|
+
if (config.constrain.x) {
|
|
191
|
+
const xAxisGroup = container.select(".x-axis");
|
|
192
|
+
if (!xAxisGroup.empty()) {
|
|
193
|
+
const xScale = getScaleFromAxis(xAxisGroup);
|
|
194
|
+
if (xScale) {
|
|
195
|
+
const newXScale = transform.rescaleX(xScale);
|
|
196
|
+
(xAxisGroup as any).call(d3.axisBottom(newXScale));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Update Y axis if constrained
|
|
202
|
+
if (config.constrain.y) {
|
|
203
|
+
const yAxisGroup = container.select(".y-axis");
|
|
204
|
+
if (!yAxisGroup.empty()) {
|
|
205
|
+
const yScale = getScaleFromAxis(yAxisGroup);
|
|
206
|
+
if (yScale) {
|
|
207
|
+
const newYScale = transform.rescaleY(yScale);
|
|
208
|
+
(yAxisGroup as any).call(d3.axisLeft(newYScale));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getScaleFromAxis(axisGroup: d3.Selection<any, any, any, any>): d3.ScaleLinear<number, number> | null {
|
|
215
|
+
// This is a simplified implementation - in practice, you'd store references to scales
|
|
216
|
+
// or implement a more sophisticated scale retrieval mechanism
|
|
217
|
+
try {
|
|
218
|
+
const axisNode = axisGroup.node();
|
|
219
|
+
if (axisNode && (axisNode as any).__scale__) {
|
|
220
|
+
return (axisNode as any).__scale__;
|
|
221
|
+
}
|
|
222
|
+
} catch (e) {
|
|
223
|
+
// Scale retrieval failed - this is expected in some cases
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Enable zoom
|
|
229
|
+
function enable(): ZoomSystem {
|
|
230
|
+
config.enabled = true;
|
|
231
|
+
if (zoomBehavior && chartContainer) {
|
|
232
|
+
chartContainer.call(zoomBehavior);
|
|
233
|
+
}
|
|
234
|
+
return zoomSystem;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Disable zoom
|
|
238
|
+
function disable(): ZoomSystem {
|
|
239
|
+
config.enabled = false;
|
|
240
|
+
if (chartContainer) {
|
|
241
|
+
chartContainer.on(".zoom", null);
|
|
242
|
+
}
|
|
243
|
+
return zoomSystem;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Attach zoom to container
|
|
247
|
+
function attach(container: d3.Selection<any, any, any, any>): ZoomSystem {
|
|
248
|
+
chartContainer = container;
|
|
249
|
+
|
|
250
|
+
if (config.enabled) {
|
|
251
|
+
const behavior = createZoomBehavior();
|
|
252
|
+
container.call(behavior);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return zoomSystem;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Detach zoom from container
|
|
259
|
+
function detach(): ZoomSystem {
|
|
260
|
+
if (chartContainer) {
|
|
261
|
+
chartContainer.on(".zoom", null);
|
|
262
|
+
chartContainer = null;
|
|
263
|
+
}
|
|
264
|
+
return zoomSystem;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Transform to specific state
|
|
268
|
+
function transform(selection: d3.Selection<any, any, any, any>, newTransform: d3.ZoomTransform, duration: number = 0): ZoomSystem {
|
|
269
|
+
if (!zoomBehavior) createZoomBehavior();
|
|
270
|
+
|
|
271
|
+
if (duration > 0) {
|
|
272
|
+
selection
|
|
273
|
+
.transition()
|
|
274
|
+
.duration(duration)
|
|
275
|
+
.ease(config.ease)
|
|
276
|
+
.call(zoomBehavior!.transform, newTransform);
|
|
277
|
+
} else {
|
|
278
|
+
selection.call(zoomBehavior!.transform, newTransform);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return zoomSystem;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Reset zoom to identity
|
|
285
|
+
function reset(duration: number = config.duration): ZoomSystem {
|
|
286
|
+
if (chartContainer) {
|
|
287
|
+
transform(chartContainer, d3.zoomIdentity, duration);
|
|
288
|
+
listeners.call("reset", undefined, { transform: d3.zoomIdentity, sourceEvent: null });
|
|
289
|
+
}
|
|
290
|
+
return zoomSystem;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Zoom to specific bounds
|
|
294
|
+
function zoomTo(bounds: ZoomBounds, duration: number = config.duration): ZoomSystem {
|
|
295
|
+
if (!chartContainer || !chartDimensions) return zoomSystem;
|
|
296
|
+
|
|
297
|
+
const { width, height, margin } = chartDimensions;
|
|
298
|
+
const chartWidth = width - margin.left - margin.right;
|
|
299
|
+
const chartHeight = height - margin.top - margin.bottom;
|
|
300
|
+
|
|
301
|
+
// Calculate transform to fit bounds
|
|
302
|
+
const [x0, x1] = bounds.x;
|
|
303
|
+
const [y0, y1] = bounds.y;
|
|
304
|
+
|
|
305
|
+
const scale = Math.min(
|
|
306
|
+
chartWidth / (x1 - x0),
|
|
307
|
+
chartHeight / (y1 - y0)
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
const translateX = chartWidth / 2 - scale * (x0 + x1) / 2;
|
|
311
|
+
const translateY = chartHeight / 2 - scale * (y0 + y1) / 2;
|
|
312
|
+
|
|
313
|
+
const newTransform = d3.zoomIdentity
|
|
314
|
+
.translate(translateX, translateY)
|
|
315
|
+
.scale(scale);
|
|
316
|
+
|
|
317
|
+
transform(chartContainer, newTransform, duration);
|
|
318
|
+
return zoomSystem;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Set chart dimensions
|
|
322
|
+
function setDimensions(dimensions: ChartDimensions): ZoomSystem {
|
|
323
|
+
chartDimensions = dimensions;
|
|
324
|
+
updateTranslateExtent();
|
|
325
|
+
return zoomSystem;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Configure zoom system
|
|
329
|
+
function configure(newConfig: Partial<ZoomConfig>): ZoomSystem {
|
|
330
|
+
Object.assign(config, newConfig);
|
|
331
|
+
|
|
332
|
+
// Update zoom behavior if it exists
|
|
333
|
+
if (zoomBehavior) {
|
|
334
|
+
if (newConfig.scaleExtent) {
|
|
335
|
+
zoomBehavior.scaleExtent(newConfig.scaleExtent);
|
|
336
|
+
}
|
|
337
|
+
if (newConfig.touchable !== undefined) {
|
|
338
|
+
zoomBehavior.touchable(newConfig.touchable);
|
|
339
|
+
}
|
|
340
|
+
if (newConfig.filter !== undefined) {
|
|
341
|
+
zoomBehavior.filter(newConfig.filter || defaultFilter);
|
|
342
|
+
}
|
|
343
|
+
if (newConfig.wheelDelta !== undefined) {
|
|
344
|
+
if (newConfig.wheelDelta) {
|
|
345
|
+
zoomBehavior.wheelDelta(newConfig.wheelDelta);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
updateTranslateExtent();
|
|
351
|
+
return zoomSystem;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Get current transform
|
|
355
|
+
function getCurrentTransform(): d3.ZoomTransform {
|
|
356
|
+
return currentTransform;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Check if zoom is enabled
|
|
360
|
+
function isEnabled(): boolean {
|
|
361
|
+
return config.enabled;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Add event listener
|
|
365
|
+
function on(type: string, callback: (event: ZoomEventData) => void): ZoomSystem {
|
|
366
|
+
(listeners as any).on(type, callback);
|
|
367
|
+
return zoomSystem;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Remove event listener
|
|
371
|
+
function off(type: string, callback?: (event: ZoomEventData) => void): ZoomSystem {
|
|
372
|
+
if (callback) {
|
|
373
|
+
(listeners as any).on(type, null);
|
|
374
|
+
} else {
|
|
375
|
+
(listeners as any).on(type, null);
|
|
376
|
+
}
|
|
377
|
+
return zoomSystem;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const zoomSystem: ZoomSystem = {
|
|
381
|
+
enable,
|
|
382
|
+
disable,
|
|
383
|
+
attach,
|
|
384
|
+
detach,
|
|
385
|
+
transform,
|
|
386
|
+
reset,
|
|
387
|
+
zoomTo,
|
|
388
|
+
setDimensions,
|
|
389
|
+
configure,
|
|
390
|
+
getCurrentTransform,
|
|
391
|
+
isEnabled,
|
|
392
|
+
on,
|
|
393
|
+
off
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
return zoomSystem;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// The function is already exported above, no need for duplicate export
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Type declarations for JavaScript modules during gradual TypeScript migration
|
|
2
|
+
|
|
3
|
+
declare module "../mintwaterfall-brush.js" {
|
|
4
|
+
export function createBrushSystem(): any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
declare module "../mintwaterfall-accessibility.js" {
|
|
8
|
+
export function createAccessibilitySystem(): any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare module "../mintwaterfall-tooltip.js" {
|
|
12
|
+
export function createTooltipSystem(): any;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare module "../mintwaterfall-export.js" {
|
|
16
|
+
export function createExportSystem(): any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module "../mintwaterfall-zoom.js" {
|
|
20
|
+
export function createZoomSystem(): any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare module "../mintwaterfall-performance.js" {
|
|
24
|
+
export function createPerformanceManager(): any;
|
|
25
|
+
}
|
|
File without changes
|