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,475 @@
1
+ // MintWaterfall Export System - TypeScript Version
2
+ // Provides SVG, PNG, PDF, and data export capabilities with full type safety
3
+
4
+ import * as d3 from 'd3';
5
+
6
+ // Type definitions for export system
7
+ export interface ExportConfig {
8
+ filename: string;
9
+ quality: number;
10
+ scale: number;
11
+ background: string;
12
+ padding: number;
13
+ includeStyles: boolean;
14
+ includeData: boolean;
15
+ }
16
+
17
+ export interface ExportOptions extends Partial<ExportConfig> {
18
+ width?: number;
19
+ height?: number;
20
+ }
21
+
22
+ export interface ExportResult {
23
+ blob: Blob;
24
+ url: string;
25
+ data: string;
26
+ download: () => void;
27
+ }
28
+
29
+ export interface PNGExportOptions extends Partial<ExportConfig> {
30
+ width?: number;
31
+ height?: number;
32
+ canvas?: HTMLCanvasElement;
33
+ context?: CanvasRenderingContext2D;
34
+ }
35
+
36
+ export interface PDFExportOptions extends Partial<ExportConfig> {
37
+ width?: number;
38
+ height?: number;
39
+ orientation?: 'portrait' | 'landscape';
40
+ pageFormat?: 'a4' | 'letter' | 'legal' | [number, number];
41
+ margin?: number | { top: number; right: number; bottom: number; left: number };
42
+ }
43
+
44
+ export interface DataExportOptions extends Partial<ExportConfig> {
45
+ dataFormat?: 'json' | 'csv' | 'tsv';
46
+ includeMetadata?: boolean;
47
+ delimiter?: string;
48
+ }
49
+
50
+ export interface ChartContainer {
51
+ select(selector: string): d3.Selection<any, any, any, any>;
52
+ node(): any;
53
+ }
54
+
55
+ export interface ExportSystem {
56
+ exportSVG(chartContainer: ChartContainer, options?: ExportOptions): ExportResult;
57
+ exportPNG(chartContainer: ChartContainer, options?: PNGExportOptions): Promise<ExportResult>;
58
+ exportPDF(chartContainer: ChartContainer, options?: PDFExportOptions): Promise<ExportResult>;
59
+ exportData(data: any[], options?: DataExportOptions): ExportResult;
60
+ configure(newConfig: Partial<ExportConfig>): ExportSystem;
61
+ downloadFile(content: string | Blob, filename: string, mimeType?: string): void;
62
+ }
63
+
64
+ export type ExportFormat = 'svg' | 'png' | 'pdf' | 'json' | 'csv';
65
+
66
+ export function createExportSystem(): ExportSystem {
67
+
68
+ let config: ExportConfig = {
69
+ filename: "waterfall-chart",
70
+ quality: 1.0,
71
+ scale: 1,
72
+ background: "#ffffff",
73
+ padding: 20,
74
+ includeStyles: true,
75
+ includeData: true
76
+ };
77
+
78
+ // Export chart as SVG
79
+ function exportSVG(chartContainer: ChartContainer, options: ExportOptions = {}): ExportResult {
80
+ const opts: ExportConfig = { ...config, ...options };
81
+
82
+ try {
83
+ const svg = chartContainer.select("svg");
84
+ if (svg.empty()) {
85
+ throw new Error("No SVG element found in chart container");
86
+ }
87
+
88
+ const svgNode = svg.node() as SVGSVGElement;
89
+ const serializer = new XMLSerializer();
90
+
91
+ // Clone SVG to avoid modifying original
92
+ const clonedSvg = svgNode.cloneNode(true) as SVGSVGElement;
93
+
94
+ // Add styles if requested
95
+ if (opts.includeStyles) {
96
+ addInlineStyles(clonedSvg);
97
+ }
98
+
99
+ // Add background if specified
100
+ if (opts.background && opts.background !== "transparent") {
101
+ addBackground(clonedSvg, opts.background);
102
+ }
103
+
104
+ // Serialize to string
105
+ const svgString = serializer.serializeToString(clonedSvg);
106
+
107
+ // Create downloadable blob
108
+ const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
109
+
110
+ return {
111
+ blob,
112
+ url: URL.createObjectURL(blob),
113
+ data: svgString,
114
+ download: () => downloadBlob(blob, `${opts.filename}.svg`)
115
+ };
116
+
117
+ } catch (error) {
118
+ console.error("SVG export failed:", error);
119
+ throw error;
120
+ }
121
+ }
122
+
123
+ // Export chart as PNG with enhanced features
124
+ function exportPNG(chartContainer: ChartContainer, options: PNGExportOptions = {}): Promise<ExportResult> {
125
+ const opts: ExportConfig & PNGExportOptions = {
126
+ ...config,
127
+ scale: 2, // Default to 2x for high-DPI
128
+ quality: 0.95,
129
+ ...options
130
+ };
131
+
132
+ return new Promise((resolve, reject) => {
133
+ try {
134
+ const svg = chartContainer.select("svg");
135
+ if (svg.empty()) {
136
+ reject(new Error("No SVG element found in chart container"));
137
+ return;
138
+ }
139
+
140
+ const svgNode = svg.node() as SVGSVGElement;
141
+ const bbox = svgNode.getBBox();
142
+ const width = (bbox.width + opts.padding * 2) * opts.scale;
143
+ const height = (bbox.height + opts.padding * 2) * opts.scale;
144
+
145
+ // Create high-DPI canvas
146
+ const canvas = document.createElement("canvas");
147
+ canvas.width = width;
148
+ canvas.height = height;
149
+ const ctx = canvas.getContext("2d");
150
+
151
+ if (!ctx) {
152
+ reject(new Error("Failed to get canvas context"));
153
+ return;
154
+ }
155
+
156
+ // Enable high-quality rendering
157
+ ctx.imageSmoothingEnabled = true;
158
+ ctx.imageSmoothingQuality = "high";
159
+
160
+ // Set background
161
+ if (opts.background && opts.background !== "transparent") {
162
+ ctx.fillStyle = opts.background;
163
+ ctx.fillRect(0, 0, width, height);
164
+ }
165
+
166
+ // Convert SVG to image with enhanced error handling
167
+ const svgExport = exportSVG(chartContainer, {
168
+ ...opts,
169
+ includeStyles: true,
170
+ background: "transparent" // Let canvas handle background
171
+ });
172
+
173
+ const img = new Image();
174
+ img.onload = () => {
175
+ try {
176
+ // Draw image with proper scaling and positioning
177
+ ctx.drawImage(img, opts.padding * opts.scale, opts.padding * opts.scale);
178
+
179
+ // Convert to blob
180
+ canvas.toBlob((blob) => {
181
+ if (!blob) {
182
+ reject(new Error("Failed to create PNG blob"));
183
+ return;
184
+ }
185
+
186
+ // Clean up
187
+ URL.revokeObjectURL(svgExport.url);
188
+
189
+ resolve({
190
+ blob,
191
+ url: URL.createObjectURL(blob),
192
+ data: svgExport.data,
193
+ download: () => downloadBlob(blob, `${opts.filename}.png`)
194
+ });
195
+ }, "image/png", opts.quality);
196
+
197
+ } catch (drawError) {
198
+ reject(new Error(`PNG rendering failed: ${drawError}`));
199
+ }
200
+ };
201
+
202
+ img.onerror = () => {
203
+ reject(new Error("Failed to load SVG image for PNG conversion"));
204
+ };
205
+
206
+ // Load SVG as data URL
207
+ img.src = `data:image/svg+xml;base64,${btoa(svgExport.data as string)}`;
208
+
209
+ } catch (error) {
210
+ reject(new Error(`PNG export failed: ${error}`));
211
+ }
212
+ });
213
+ }
214
+
215
+ // Export chart as PDF (requires external library like jsPDF)
216
+ function exportPDF(chartContainer: ChartContainer, options: PDFExportOptions = {}): Promise<ExportResult> {
217
+ const opts: ExportConfig & PDFExportOptions = {
218
+ ...config,
219
+ orientation: 'landscape',
220
+ pageFormat: 'a4',
221
+ ...options
222
+ };
223
+
224
+ return new Promise((resolve, reject) => {
225
+ // Check if jsPDF is available
226
+ if (typeof window === 'undefined' || !(window as any).jsPDF) {
227
+ reject(new Error('jsPDF library is required for PDF export. Please include it: <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>'));
228
+ return;
229
+ }
230
+
231
+ try {
232
+ // Get PNG data first
233
+ exportPNG(chartContainer, {
234
+ ...opts,
235
+ scale: 2,
236
+ quality: 0.95
237
+ }).then((pngResult) => {
238
+ const jsPDF = (window as any).jsPDF;
239
+ const pdf = new jsPDF({
240
+ orientation: opts.orientation,
241
+ unit: 'mm',
242
+ format: opts.pageFormat
243
+ });
244
+
245
+ // Calculate dimensions
246
+ const pdfWidth = pdf.internal.pageSize.getWidth();
247
+ const pdfHeight = pdf.internal.pageSize.getHeight();
248
+
249
+ // Add image to PDF
250
+ const reader = new FileReader();
251
+ reader.onload = () => {
252
+ try {
253
+ const imgData = reader.result as string;
254
+
255
+ // Calculate aspect ratio and size
256
+ const img = new Image();
257
+ img.onload = () => {
258
+ const aspectRatio = img.width / img.height;
259
+ let width = pdfWidth - 20; // 10mm margin on each side
260
+ let height = width / aspectRatio;
261
+
262
+ // Adjust if height is too large
263
+ if (height > pdfHeight - 20) {
264
+ height = pdfHeight - 20;
265
+ width = height * aspectRatio;
266
+ }
267
+
268
+ const x = (pdfWidth - width) / 2;
269
+ const y = (pdfHeight - height) / 2;
270
+
271
+ pdf.addImage(imgData, 'PNG', x, y, width, height);
272
+
273
+ // Generate PDF blob
274
+ const pdfBlob = pdf.output('blob');
275
+
276
+ // Clean up
277
+ URL.revokeObjectURL(pngResult.url);
278
+
279
+ resolve({
280
+ blob: pdfBlob,
281
+ url: URL.createObjectURL(pdfBlob),
282
+ data: pdfBlob,
283
+ download: () => downloadBlob(pdfBlob, `${opts.filename}.pdf`)
284
+ });
285
+ };
286
+
287
+ img.src = imgData;
288
+
289
+ } catch (pdfError) {
290
+ reject(new Error(`PDF generation failed: ${pdfError}`));
291
+ }
292
+ };
293
+
294
+ reader.onerror = () => {
295
+ reject(new Error("Failed to read PNG data for PDF conversion"));
296
+ };
297
+
298
+ reader.readAsDataURL(pngResult.blob);
299
+
300
+ }).catch(reject);
301
+
302
+ } catch (error) {
303
+ reject(new Error(`PDF export failed: ${error}`));
304
+ }
305
+ });
306
+ }
307
+
308
+ // Export data in various formats
309
+ function exportData(data: any[], options: DataExportOptions = {}): ExportResult {
310
+ const opts: ExportConfig & DataExportOptions = {
311
+ ...config,
312
+ dataFormat: 'json',
313
+ includeMetadata: true,
314
+ delimiter: ',',
315
+ ...options
316
+ };
317
+
318
+ try {
319
+ let content: string;
320
+ let mimeType: string;
321
+ let extension: string;
322
+
323
+ switch (opts.dataFormat) {
324
+ case 'json':
325
+ const jsonData = opts.includeMetadata
326
+ ? {
327
+ data,
328
+ metadata: {
329
+ exportDate: new Date().toISOString(),
330
+ count: data.length
331
+ }
332
+ }
333
+ : data;
334
+ content = JSON.stringify(jsonData, null, 2);
335
+ mimeType = 'application/json';
336
+ extension = 'json';
337
+ break;
338
+
339
+ case 'csv':
340
+ content = convertToCSV(data, opts.delimiter || ',');
341
+ mimeType = 'text/csv';
342
+ extension = 'csv';
343
+ break;
344
+
345
+ case 'tsv':
346
+ content = convertToCSV(data, '\t');
347
+ mimeType = 'text/tab-separated-values';
348
+ extension = 'tsv';
349
+ break;
350
+
351
+ default:
352
+ throw new Error(`Unsupported data export format: ${opts.dataFormat}`);
353
+ }
354
+
355
+ const blob = new Blob([content], { type: `${mimeType};charset=utf-8` });
356
+
357
+ return {
358
+ blob,
359
+ url: URL.createObjectURL(blob),
360
+ data: content,
361
+ download: () => downloadBlob(blob, `${opts.filename}.${extension}`)
362
+ };
363
+
364
+ } catch (error) {
365
+ console.error("Data export failed:", error);
366
+ throw error;
367
+ }
368
+ }
369
+
370
+ // Helper function to add inline styles to SVG
371
+ function addInlineStyles(svgElement: SVGSVGElement): void {
372
+ try {
373
+ const styleSheets = Array.from(document.styleSheets);
374
+ let styles = '';
375
+
376
+ styleSheets.forEach(sheet => {
377
+ try {
378
+ const rules = Array.from(sheet.cssRules || sheet.rules);
379
+ rules.forEach(rule => {
380
+ if (rule.type === CSSRule.STYLE_RULE) {
381
+ const styleRule = rule as CSSStyleRule;
382
+ if (styleRule.selectorText &&
383
+ (styleRule.selectorText.includes('.mintwaterfall') ||
384
+ styleRule.selectorText.includes('svg') ||
385
+ styleRule.selectorText.includes('chart'))) {
386
+ styles += styleRule.cssText;
387
+ }
388
+ }
389
+ });
390
+ } catch (e) {
391
+ // Skip inaccessible stylesheets (CORS)
392
+ console.warn('Could not access stylesheet:', e);
393
+ }
394
+ });
395
+
396
+ if (styles) {
397
+ const styleElement = document.createElementNS('http://www.w3.org/2000/svg', 'style');
398
+ styleElement.textContent = styles;
399
+ svgElement.insertBefore(styleElement, svgElement.firstChild);
400
+ }
401
+ } catch (error) {
402
+ console.warn('Failed to add inline styles:', error);
403
+ }
404
+ }
405
+
406
+ // Helper function to add background to SVG
407
+ function addBackground(svgElement: SVGSVGElement, backgroundColor: string): void {
408
+ const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
409
+ rect.setAttribute('width', '100%');
410
+ rect.setAttribute('height', '100%');
411
+ rect.setAttribute('fill', backgroundColor);
412
+ svgElement.insertBefore(rect, svgElement.firstChild);
413
+ }
414
+
415
+ // Helper function to convert data to CSV
416
+ function convertToCSV(data: any[], delimiter: string = ','): string {
417
+ if (!data || data.length === 0) return '';
418
+
419
+ // Get headers from first object
420
+ const headers = Object.keys(data[0]);
421
+
422
+ // Create CSV content
423
+ const csvContent = [
424
+ headers.join(delimiter),
425
+ ...data.map(row =>
426
+ headers.map(header => {
427
+ const value = row[header];
428
+ // Escape quotes and wrap in quotes if contains delimiter
429
+ const stringValue = value != null ? String(value) : '';
430
+ if (stringValue.includes(delimiter) || stringValue.includes('"') || stringValue.includes('\n')) {
431
+ return `"${stringValue.replace(/"/g, '""')}"`;
432
+ }
433
+ return stringValue;
434
+ }).join(delimiter)
435
+ )
436
+ ].join('\n');
437
+
438
+ return csvContent;
439
+ }
440
+
441
+ // Helper function to download blob
442
+ function downloadBlob(blob: Blob, filename: string): void {
443
+ const url = URL.createObjectURL(blob);
444
+ const link = document.createElement('a');
445
+ link.href = url;
446
+ link.download = filename;
447
+ document.body.appendChild(link);
448
+ link.click();
449
+ document.body.removeChild(link);
450
+ URL.revokeObjectURL(url);
451
+ }
452
+
453
+ // Configure export system
454
+ function configure(newConfig: Partial<ExportConfig>): ExportSystem {
455
+ config = { ...config, ...newConfig };
456
+ return exportSystem;
457
+ }
458
+
459
+ // Download file utility
460
+ function downloadFile(content: string | Blob, filename: string, mimeType: string = 'text/plain'): void {
461
+ const blob = content instanceof Blob ? content : new Blob([content], { type: mimeType });
462
+ downloadBlob(blob, filename);
463
+ }
464
+
465
+ const exportSystem: ExportSystem = {
466
+ exportSVG,
467
+ exportPNG,
468
+ exportPDF,
469
+ exportData,
470
+ configure,
471
+ downloadFile
472
+ };
473
+
474
+ return exportSystem;
475
+ }