energy-visualization-sankey 1.0.11 → 1.0.13

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 (45) hide show
  1. package/.cursorrules +41 -0
  2. package/README.md +8 -1
  3. package/bun.lock +1426 -0
  4. package/dist/sankey.esm.js +108 -79
  5. package/dist/sankey.esm.js.map +1 -1
  6. package/dist/sankey.umd.js +8720 -8687
  7. package/dist/sankey.umd.js.map +1 -1
  8. package/dist/types/core/Sankey.d.ts +294 -0
  9. package/dist/types/core/Sankey.d.ts.map +1 -0
  10. package/dist/types/core/events/EventBus.d.ts +195 -0
  11. package/dist/types/core/events/EventBus.d.ts.map +1 -0
  12. package/dist/types/core/types/events.d.ts +42 -0
  13. package/dist/types/core/types/events.d.ts.map +1 -0
  14. package/dist/types/index.d.ts +19 -0
  15. package/dist/types/index.d.ts.map +1 -0
  16. package/dist/types/services/AnimationService.d.ts +229 -0
  17. package/dist/types/services/AnimationService.d.ts.map +1 -0
  18. package/dist/types/services/ConfigurationService.d.ts +182 -0
  19. package/dist/types/services/ConfigurationService.d.ts.map +1 -0
  20. package/dist/types/services/InteractionService.d.ts +377 -0
  21. package/dist/types/services/InteractionService.d.ts.map +1 -0
  22. package/dist/types/services/RenderingService.d.ts +160 -0
  23. package/dist/types/services/RenderingService.d.ts.map +1 -0
  24. package/dist/types/services/calculation/GraphService.d.ts +111 -0
  25. package/dist/types/services/calculation/GraphService.d.ts.map +1 -0
  26. package/dist/types/services/calculation/SummaryService.d.ts +149 -0
  27. package/dist/types/services/calculation/SummaryService.d.ts.map +1 -0
  28. package/dist/types/services/data/DataService.d.ts +167 -0
  29. package/dist/types/services/data/DataService.d.ts.map +1 -0
  30. package/dist/types/services/data/DataValidationService.d.ts +48 -0
  31. package/dist/types/services/data/DataValidationService.d.ts.map +1 -0
  32. package/dist/types/types/index.d.ts +194 -0
  33. package/dist/types/types/index.d.ts.map +1 -0
  34. package/dist/types/utils/Logger.d.ts +88 -0
  35. package/dist/types/utils/Logger.d.ts.map +1 -0
  36. package/package.json +4 -3
  37. package/rollup.config.js +11 -2
  38. package/src/core/Sankey.ts +3 -9
  39. package/src/index.ts +3 -3
  40. package/src/services/ConfigurationService.ts +59 -22
  41. package/src/services/RenderingService.ts +3 -3
  42. package/src/services/calculation/GraphService.ts +6 -6
  43. package/src/services/calculation/SummaryService.ts +3 -3
  44. package/src/types/index.ts +8 -1
  45. package/tsconfig.json +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "energy-visualization-sankey",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "A modern TypeScript library for creating interactive Sankey diagrams that visualize energy flows from sources to consumption sectors.",
5
5
  "keywords": [
6
6
  "sankey",
@@ -30,11 +30,11 @@
30
30
  "import": "./dist/sankey.esm.js",
31
31
  "require": "./dist/sankey.umd.js"
32
32
  },
33
- "./styles": "./dist/styles.css"
33
+ "./styles": "./dist/sankey.css"
34
34
  },
35
35
  "scripts": {
36
36
  "dev": "rollup -c -w",
37
- "build": "rollup -c",
37
+ "build": "rollup -c && tsc-alias -p tsconfig.json",
38
38
  "build:dev": "rollup -c",
39
39
  "type-check": "tsc --noEmit",
40
40
  "clean": "rm -rf dist",
@@ -73,6 +73,7 @@
73
73
  "rollup": "^4.6.1",
74
74
  "rollup-plugin-postcss": "^4.0.2",
75
75
  "rollup-plugin-typescript2": "^0.36.0",
76
+ "tsc-alias": "^1.8.16",
76
77
  "tslib": "^2.6.0",
77
78
  "typescript": "^5.3.0"
78
79
  }
package/rollup.config.js CHANGED
@@ -27,7 +27,7 @@ const cssConfig = {
27
27
  };
28
28
 
29
29
  const baseConfig = {
30
- input: 'src/core/Sankey.ts',
30
+ input: 'src/index.ts',
31
31
  // Embed D3 in the bundle for standalone distribution
32
32
  external: [],
33
33
  plugins: [
@@ -41,7 +41,16 @@ const baseConfig = {
41
41
  clean: true,
42
42
  abortOnError: false,
43
43
  rollupCommonJSResolveHack: false,
44
- typescript: ts
44
+ typescript: ts,
45
+ tsconfigOverride: {
46
+ compilerOptions: {
47
+ declaration: true,
48
+ declarationMap: true,
49
+ declarationDir: './dist/types',
50
+ baseUrl: '.',
51
+ paths: {}
52
+ }
53
+ }
45
54
  })
46
55
  ]
47
56
  };
@@ -205,7 +205,6 @@ export default class Sankey {
205
205
  timestamp: Date.now(),
206
206
  source: 'SankeyVisualization',
207
207
  data: {
208
- version: '7.0.0',
209
208
  services: [], // Will be populated as services come online
210
209
  initTime: 0 // Will be updated when initialization completes
211
210
  }
@@ -266,7 +265,6 @@ export default class Sankey {
266
265
  timestamp: Date.now(),
267
266
  source: 'SankeyVisualization',
268
267
  data: {
269
- version: '7.0.0',
270
268
  totalInitTime: totalInitializationTime,
271
269
  dataPointCount: this.options.data.length,
272
270
  yearRange: [
@@ -672,7 +670,7 @@ export default class Sankey {
672
670
  };
673
671
 
674
672
  for (let i = 0; i < graphs.length; ++i) {
675
- let top = this.services.configurationService!.TOP_Y;
673
+ let top = this.services.configurationService!.LEFT_Y;
676
674
  const y = graphs[i].year;
677
675
 
678
676
  graphNest.strokes[y] = {};
@@ -686,7 +684,7 @@ export default class Sankey {
686
684
  graphNest.strokes[y][f] = {};
687
685
 
688
686
  if (f == 'elec') {
689
- graphNest.tops[y][f] = this.services.configurationService!.ELEC_BOX_Y - summary.totals[i].elec * SCALE;
687
+ graphNest.tops[y][f] = this.services.configurationService!.ELECTRICITY_BOX_Y - summary.totals[i].elec * SCALE;
690
688
  } else if (f == 'heat') {
691
689
  graphNest.tops[y][f] = this.services.configurationService!.HEAT_BOX_Y - summary.totals[i].heat * SCALE;
692
690
  } else {
@@ -1053,16 +1051,12 @@ export default class Sankey {
1053
1051
  private mergeOptionsWithDefaults(options: SankeyOptions): SankeyOptions {
1054
1052
  // Merge user options with system defaults
1055
1053
  return {
1056
- data: options.data,
1057
- country: options.country,
1054
+ ...options,
1058
1055
  includeControls: options.includeControls !== false,
1059
1056
  includeTimeline: options.includeTimeline !== false,
1060
1057
  includeWasteToggle: options.includeWasteToggle !== false,
1061
1058
  autoPlay: options.autoPlay || false,
1062
1059
  showWasteHeat: options.showWasteHeat !== false,
1063
- animationSpeed: options.animationSpeed || 200,
1064
- width: options.width || null,
1065
- height: options.height || 620,
1066
1060
  loopAnimation: options.loopAnimation !== undefined ? options.loopAnimation : false
1067
1061
  };
1068
1062
  }
package/src/index.ts CHANGED
@@ -23,13 +23,13 @@ export type {
23
23
  YearTotals,
24
24
  BoxMaxes,
25
25
  BoxTops
26
- } from '@/types/index';
26
+ } from './types/index';
27
27
 
28
28
  // Export error handling types
29
29
  export {
30
30
  SankeyError,
31
31
  DataValidationError
32
- } from '@/types/index';
32
+ } from './types/index';
33
33
 
34
34
  // Export the main visualization class
35
- export {default as default} from '@/core/Sankey';
35
+ export {default as default} from './core/Sankey';
@@ -61,24 +61,22 @@ export class ConfigurationService {
61
61
  // ===================== COORDINATE POSITIONING CONSTANTS =====================
62
62
 
63
63
  // LEFT COLUMN POSITIONING: Fuel source boxes alignment
64
- public readonly LEFT_X = 10; // X-coordinate for left column (fuel sources)
65
- public readonly TOP_Y = 100; // Y-coordinate for top margin (visual breathing space)
64
+ public readonly LEFT_X: number = 10; // X-coordinate for left column (fuel sources)
65
+ public readonly LEFT_Y: number = 100; // Y-coordinate for top margin (visual breathing space)
66
66
 
67
67
  // ==================== MATHEMATICAL SCALING CONSTANTS ====================
68
68
 
69
69
  // ENERGY-TO-PIXEL CONVERSION: Critical scaling factor for proportional representation
70
- public readonly SCALE = 0.02; // Converts Quads to pixels: 1 Quad = 0.02 pixels height
70
+ public readonly SCALE: number = 0.02; // Converts Quads to pixels: 1 Quad = 0.02 pixels height
71
71
  // Calibrated for typical US energy consumption (0-100+ Quads)
72
72
  // Example: 50 Quads × 0.02 = 1.0 pixel height
73
73
 
74
74
  // ELECTRICITY BOX POSITIONING: Special coordinates for electricity box (bidirectional flows)
75
- public readonly ELEC_BOX_X = 320 as const;
76
- public readonly ELEC_BOX_Y = 120 as const;
75
+ public readonly ELECTRICITY_BOX_X: number = 320 as const;
76
+ public readonly ELECTRICITY_BOX_Y: number = 120 as const;
77
77
 
78
- public readonly HEAT_BOX_X = 750 as const;
79
- public readonly HEAT_BOX_Y = 200 as const;
80
- // X=350: Positioned between fuel sources (left) and sectors (right)
81
- // Y=120: Offset below title area for visual clarity
78
+ public readonly HEAT_BOX_X: number = 750 as const;
79
+ public readonly HEAT_BOX_Y: number = 200 as const;
82
80
 
83
81
  // ======================== VISUAL SPACING CONSTANTS ========================
84
82
 
@@ -87,7 +85,7 @@ export class ConfigurationService {
87
85
  public readonly RIGHT_GAP: number; // Gap between sector boxes (right column) - computed as LEFT_GAP × 2.1
88
86
 
89
87
  // ANIMATION PARAMETERS: Timing and transition control
90
- public readonly SPEED: number; // Animation speed in milliseconds (from user options, default 200)
88
+ public readonly SPEED: number = 200; // Animation speed in milliseconds (from user options, default 200)
91
89
  public readonly BLEED = 0.5; // Edge bleed factor for smooth visual transitions
92
90
 
93
91
  // =================== GEOMETRIC CALCULATION CONSTANTS ===================
@@ -100,7 +98,7 @@ export class ConfigurationService {
100
98
  // FLOW PATH SPACING: Visual separation between parallel energy flows
101
99
  public readonly PATH_GAP: number = 20; // Pixel gap between parallel flow paths
102
100
  // Prevents visual overlap while maintaining readability
103
- public readonly ELEC_GAP = 19; // Special gap for electricity flows (slightly smaller)
101
+ public readonly ELECTRICITY_GAP = 19; // Special gap for electricity flows (slightly smaller)
104
102
  // Optimized for electricity box's central position
105
103
 
106
104
  // ====================== ENERGY SOURCE DEFINITIONS ======================
@@ -165,7 +163,31 @@ export class ConfigurationService {
165
163
  ) {
166
164
  // Calculate computed properties
167
165
  this.RIGHT_GAP = this.LEFT_GAP * 2.1;
168
- this.SPEED = options.animationSpeed || 200;
166
+
167
+ if (options.animationSpeed) {
168
+ this.SPEED = options.animationSpeed;
169
+ }
170
+ if (options.scale) {
171
+ this.SCALE = options.scale;
172
+ }
173
+ if (options.leftX) {
174
+ this.LEFT_X = options.leftX;
175
+ }
176
+ if (options.leftY) {
177
+ this.LEFT_Y = options.leftY;
178
+ }
179
+ if (options.electricityBoxX) {
180
+ this.ELECTRICITY_BOX_X = options.electricityBoxX;
181
+ }
182
+ if (options.electricityBoxY) {
183
+ this.ELECTRICITY_BOX_Y = options.electricityBoxY;
184
+ }
185
+ if (options.heatBoxX) {
186
+ this.HEAT_BOX_X = options.heatBoxX;
187
+ }
188
+ if (options.heatBoxY) {
189
+ this.HEAT_BOX_Y = options.heatBoxY;
190
+ }
169
191
 
170
192
  this.FLOW_PATHS_ORDER = {
171
193
  "elec": this.BOXES_DEFAULT_FLOW_PATHS_ORDER,
@@ -366,39 +388,54 @@ export class ConfigurationService {
366
388
  private validateConfiguration(): void {
367
389
  // Validate dimensions
368
390
  if (this.WIDTH <= 0 || this.HEIGHT <= 0) {
369
- throw new Error('ConfigurationService: Invalid dimensions');
391
+ throw new Error('Invalid dimensions');
370
392
  }
371
393
 
372
394
  // Validate box positioning
373
395
  if (this.BOX_WIDTH <= 0 || this.BOX_HEIGHT <= 0) {
374
- throw new Error('ConfigurationService: Invalid box dimensions');
396
+ throw new Error('Invalid box dimensions');
397
+ }
398
+
399
+ // Validate scaling factors
400
+ if (this.SPEED <= 0) {
401
+ throw new Error('Invalid animation speed');
375
402
  }
376
403
 
377
404
  // Validate scaling factors
378
405
  if (this.SCALE <= 0) {
379
- throw new Error('ConfigurationService: Invalid scale factor');
406
+ throw new Error('Invalid scale factor');
407
+ }
408
+
409
+ // Validate left source positioning
410
+ if (this.LEFT_X <= 0 || this.LEFT_Y <= 0) {
411
+ throw new Error('Invalid left sources position');
380
412
  }
381
413
 
382
414
  // Validate electricity box positioning
383
- if (this.ELEC_BOX_X <= 0 || this.ELEC_BOX_X <= 0) {
384
- throw new Error('ConfigurationService: Invalid electricity box position');
415
+ if (this.ELECTRICITY_BOX_X <= 0 || this.ELECTRICITY_BOX_Y <= 0) {
416
+ throw new Error('Invalid electricity box position');
417
+ }
418
+
419
+ // Validate heat box positioning
420
+ if (this.HEAT_BOX_X <= 0 || this.HEAT_BOX_Y <= 0) {
421
+ throw new Error('Invalid heat box position');
385
422
  }
386
423
 
387
424
  // Validate fuel definitions
388
425
  if (this.FUELS.length === 0) {
389
- throw new Error('ConfigurationService: No fuels defined');
426
+ throw new Error('No fuels defined');
390
427
  }
391
428
 
392
429
  // Validate sector definitions
393
430
  if (this.BOXES.length === 0) {
394
- throw new Error('ConfigurationService: No sectors defined');
431
+ throw new Error('No sectors defined');
395
432
  }
396
433
 
397
434
  // Validate required fuels exist
398
435
  const requiredFuels = ['elec', 'solar', 'nuclear', 'hydro', 'wind', 'geo', 'gas', 'coal', 'bio', 'petro'];
399
436
  for (const fuel of requiredFuels) {
400
437
  if (!this.FUEL_NAMES.includes(fuel)) {
401
- console.warn(`ConfigurationService: Missing required fuel: ${fuel}`);
438
+ console.warn(`Missing required fuel: ${fuel}`);
402
439
  }
403
440
  }
404
441
 
@@ -406,11 +443,11 @@ export class ConfigurationService {
406
443
  const requiredSectors = ['elec', 'res', 'ag', 'indus', 'trans'];
407
444
  for (const sector of requiredSectors) {
408
445
  if (!this.BOX_NAMES.includes(sector)) {
409
- console.warn(`ConfigurationService: Missing required sector: ${sector}`);
446
+ console.warn(`Missing required sector: ${sector}`);
410
447
  }
411
448
  }
412
449
 
413
- this.logger.log('ConfigurationService: All configuration validated successfully');
450
+ this.logger.log('All configuration validated successfully');
414
451
  }
415
452
 
416
453
  // ==================== UTILITY METHODS ====================
@@ -172,7 +172,7 @@ export class RenderingService {
172
172
  .attr('x', this.configService.LEFT_X) // X-position: left column alignment
173
173
  .attr('y', (d: any, i: number) => { // Y-position: calculated per fuel
174
174
  // Calculate cumulative Y position for this fuel
175
- let cumulativeTop = this.configService.TOP_Y;
175
+ let cumulativeTop = this.configService.LEFT_Y;
176
176
  for (let j = 0; j < i; j++) {
177
177
  const prevFuel = leftFuels[j];
178
178
  const prevFuelTotal = totals[prevFuel.fuel] || 0;
@@ -236,8 +236,8 @@ export class RenderingService {
236
236
  // CONDITIONAL POSITIONING ALGORITHM: Electricity vs. Regular Sectors
237
237
  if (boxConfig.box === 'elec') {
238
238
  // ELECTRICITY BOX: Special central positioning
239
- x = this.configService.ELEC_BOX_X; // Configured X-position
240
- y = this.configService.ELEC_BOX_Y - totals.elec * this.configService.SCALE; // Dynamic Y-position
239
+ x = this.configService.ELECTRICITY_BOX_X; // Configured X-position
240
+ y = this.configService.ELECTRICITY_BOX_Y - totals.elec * this.configService.SCALE; // Dynamic Y-position
241
241
  } else if (boxConfig.box === 'heat') {
242
242
  // ELECTRICITY BOX: Special central positioning
243
243
  x = this.configService.HEAT_BOX_X; // Configured X-position
@@ -97,13 +97,13 @@ export class GraphService {
97
97
  // Eliminates repeated property access during O(n³) loop execution
98
98
  // Performance improvement: 5-10% reduction in execution time
99
99
  const SCALE = this.configService.SCALE; // Energy-to-pixel conversion (0.02)
100
- const ELEC_BOX_X = this.configService.ELEC_BOX_X; // Electricity box X-coordinate
101
- const ELEC_BOX_Y = this.configService.ELEC_BOX_Y; // Electricity box Y-coordinate
100
+ const ELEC_BOX_X = this.configService.ELECTRICITY_BOX_X; // Electricity box X-coordinate
101
+ const ELEC_BOX_Y = this.configService.ELECTRICITY_BOX_Y; // Electricity box Y-coordinate
102
102
  const HEAT_BOX_X = this.configService.HEAT_BOX_X; // Heat box X-coordinate
103
103
  const HEAT_BOX_Y = this.configService.HEAT_BOX_Y; // Heat box Y-coordinate
104
104
  const BOX_WIDTH = this.configService.BOX_WIDTH; // Standard box width
105
105
  const LEFT_X = this.configService.LEFT_X; // Left column X-coordinate
106
- const TOP_Y = this.configService.TOP_Y; // Top margin Y-coordinate
106
+ const TOP_Y = this.configService.LEFT_Y; // Top margin Y-coordinate
107
107
  const SR3 = this.configService.SR3; // Slope ratio (height/3)
108
108
  const PATH_GAP = this.configService.PATH_GAP; // Visual gap between flow paths
109
109
  const LEFT_GAP = this.configService.LEFT_GAP; // Gap between fuel boxes
@@ -382,7 +382,7 @@ export class GraphService {
382
382
  const BOX_WIDTH = this.configService.BOX_WIDTH;
383
383
  const SCALE = this.configService.SCALE;
384
384
  const SR3 = this.configService.SR3;
385
- const ELEC_GAP = this.configService.ELEC_GAP;
385
+ const ELEC_GAP = this.configService.ELECTRICITY_GAP;
386
386
  const HSR3 = this.configService.HSR3;
387
387
 
388
388
  for (let i = 0; i < this.graphs.length; ++i) {
@@ -415,8 +415,8 @@ export class GraphService {
415
415
  const BOX_WIDTH = this.configService.BOX_WIDTH;
416
416
  const SR3 = this.configService.SR3;
417
417
  const HSR3 = this.configService.HSR3;
418
- const ELEC_GAP = this.configService.ELEC_GAP;
419
- const ELEC_BOX_Y = this.configService.ELEC_BOX_Y;
418
+ const ELEC_GAP = this.configService.ELECTRICITY_GAP;
419
+ const ELEC_BOX_Y = this.configService.ELECTRICITY_BOX_Y;
420
420
 
421
421
  for (let i = 0; i < this.graphs.length; ++i) {
422
422
  let current_box: string | null = null;
@@ -118,9 +118,9 @@ export class SummaryService {
118
118
  // Measured improvement: 5-10% reduction in execution time
119
119
  const FUELS = this.configService.FUELS; // Energy source types array
120
120
  const BOX_NAMES = this.configService.BOX_NAMES; // Consumption sector names
121
- const ELEC_BOX_Y = this.configService.ELEC_BOX_Y; // Electricity box Y-coordinate
121
+ const ELEC_BOX_Y = this.configService.ELECTRICITY_BOX_Y; // Electricity box Y-coordinate
122
122
  const HEAT_BOX_Y = this.configService.HEAT_BOX_Y; // Heat box Y-coordinate
123
- const TOP_Y = this.configService.TOP_Y; // Top margin for fuel labels
123
+ const TOP_Y = this.configService.LEFT_Y; // Top margin for fuel labels
124
124
  const SCALE = this.configService.SCALE; // Energy-to-pixel conversion (0.02)
125
125
  const LEFT_GAP = this.configService.LEFT_GAP; // Visual gap between fuel boxes
126
126
 
@@ -372,7 +372,7 @@ export class SummaryService {
372
372
  // ELEC_BOX_Y: Base Y-coordinate for electricity box (right-hand column)
373
373
  // +50: Visual offset below electricity box for residential sector
374
374
  this.boxTops = {
375
- res: this.configService.ELEC_BOX_Y + 50, // Base position for residential
375
+ res: this.configService.ELECTRICITY_BOX_Y + 50, // Base position for residential
376
376
  heat: this.configService.HEAT_BOX_Y + 50, // Base position for residential
377
377
  ag: 0, // Will be calculated based on residential
378
378
  indus: 0, // Will be calculated based on agriculture
@@ -74,8 +74,15 @@ export interface SankeyOptions {
74
74
  readonly autoPlay?: boolean;
75
75
  readonly showWasteHeat?: boolean;
76
76
  readonly animationSpeed?: number;
77
- readonly width?: number | null;
77
+ readonly width?: number;
78
78
  readonly height?: number;
79
+ readonly scale?: number;
80
+ readonly leftX?: number;
81
+ readonly leftY?: number;
82
+ readonly electricityBoxX?: number;
83
+ readonly electricityBoxY?: number;
84
+ readonly heatBoxX?: number;
85
+ readonly heatBoxY?: number;
79
86
  readonly loopAnimation?: boolean;
80
87
  readonly debugLogging?: boolean;
81
88
  }
package/tsconfig.json CHANGED
@@ -24,6 +24,7 @@
24
24
  "declaration": true,
25
25
  "declarationMap": true,
26
26
  "outDir": "./dist",
27
+ "declarationDir": "./dist/types",
27
28
  "rootDir": "./src",
28
29
  "strict": true,
29
30
  "noImplicitAny": true,