chartjs-chart-sankey 0.16.3 → 0.17.0
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/dist/chartjs-chart-sankey.cjs +80 -25
- package/dist/chartjs-chart-sankey.esm.js +80 -25
- package/dist/chartjs-chart-sankey.min.js +2 -2
- package/dist/controller.d.cts +1 -1
- package/dist/controller.d.ts +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.d.cts +1 -1
- package/dist/index.esm.d.ts +1 -1
- package/dist/labels.d.cts +2 -3
- package/dist/labels.d.ts +2 -3
- package/dist/lib/layout.d.ts +6 -4
- package/dist/types.d.cts +12 -6
- package/dist/types.d.ts +12 -6
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* chartjs-chart-sankey v0.
|
|
2
|
+
* chartjs-chart-sankey v0.17.0
|
|
3
3
|
* https://chartjs-chart-sankey.pages.dev/
|
|
4
4
|
* (c) 2026 Jukka Kurkela
|
|
5
5
|
* Released under the MIT license
|
|
@@ -43,7 +43,7 @@ function isPatternOrGradient(value) {
|
|
|
43
43
|
const type = Object.prototype.toString.call(value);
|
|
44
44
|
return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
|
|
45
45
|
}
|
|
46
|
-
function
|
|
46
|
+
function resolveNodeOption(option, node) {
|
|
47
47
|
if (typeof option === 'function') {
|
|
48
48
|
return option(node);
|
|
49
49
|
}
|
|
@@ -442,7 +442,36 @@ const nodeByXYSize = (a, b)=>{
|
|
|
442
442
|
if (nodeY$1(a) === nodeY$1(b)) return a.size - b.size;
|
|
443
443
|
return nodeY$1(a) - nodeY$1(b);
|
|
444
444
|
};
|
|
445
|
-
|
|
445
|
+
function createColumnGapState() {
|
|
446
|
+
return {
|
|
447
|
+
lastAfter: 0,
|
|
448
|
+
realCount: 0,
|
|
449
|
+
realCumOffset: 0,
|
|
450
|
+
yHistory: []
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function countCrossColumnPaddings(grid, colIdx, y, ownPaddings) {
|
|
454
|
+
let paddings = ownPaddings;
|
|
455
|
+
for(let col = 0; col < colIdx; col++){
|
|
456
|
+
const otherHistory = grid[col].yHistory;
|
|
457
|
+
for(let row = 0; row < otherHistory.length; row++){
|
|
458
|
+
if (otherHistory[row] > y) break;
|
|
459
|
+
paddings = Math.max(row + 1, paddings);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return paddings;
|
|
463
|
+
}
|
|
464
|
+
function offsetForNode(state, gap, paddings) {
|
|
465
|
+
const realNodesAbove = state.realCount;
|
|
466
|
+
const transitionGap = realNodesAbove > 0 ? Math.max(state.lastAfter, gap.before) : 0;
|
|
467
|
+
const realCumOffset = state.realCumOffset + transitionGap;
|
|
468
|
+
const virtualLevels = paddings - realNodesAbove;
|
|
469
|
+
state.realCount = realNodesAbove + 1;
|
|
470
|
+
state.realCumOffset = realCumOffset;
|
|
471
|
+
state.lastAfter = gap.after;
|
|
472
|
+
return realCumOffset + virtualLevels * gap.before;
|
|
473
|
+
}
|
|
474
|
+
function addPadding(nodeArray, gaps) {
|
|
446
475
|
let maxY = 0;
|
|
447
476
|
const columnXs = new Map();
|
|
448
477
|
const grid = [];
|
|
@@ -450,7 +479,7 @@ const nodeByXYSize = (a, b)=>{
|
|
|
450
479
|
if (!columnXs.has(x)) {
|
|
451
480
|
const index = grid.length;
|
|
452
481
|
columnXs.set(x, index);
|
|
453
|
-
grid.push(
|
|
482
|
+
grid.push(createColumnGapState());
|
|
454
483
|
return index;
|
|
455
484
|
}
|
|
456
485
|
return columnXs.get(x) ?? 0;
|
|
@@ -458,21 +487,23 @@ const nodeByXYSize = (a, b)=>{
|
|
|
458
487
|
nodeArray.sort(nodeByXYSize);
|
|
459
488
|
for (const node of nodeArray){
|
|
460
489
|
const colIdx = getColIndex(nodeX$1(node));
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
490
|
+
const state = grid[colIdx];
|
|
491
|
+
const gap = gaps.get(node.key) ?? {
|
|
492
|
+
after: 0,
|
|
493
|
+
before: 0
|
|
494
|
+
};
|
|
495
|
+
const y = nodeY$1(node);
|
|
496
|
+
if (y) {
|
|
497
|
+
state.yHistory.push(y);
|
|
498
|
+
let paddings = state.yHistory.length;
|
|
465
499
|
if (node.in) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
for(let row = 0; row < otherColumn.length; row++){
|
|
469
|
-
if (otherColumn[row] > nodeY$1(node)) break;
|
|
470
|
-
paddings = Math.max(row + 1, paddings);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
while(column.length < paddings)column.push(nodeY$1(node));
|
|
500
|
+
paddings = countCrossColumnPaddings(grid, colIdx, y, paddings);
|
|
501
|
+
while(state.yHistory.length < paddings)state.yHistory.push(y);
|
|
474
502
|
}
|
|
475
|
-
node.y =
|
|
503
|
+
node.y = y + offsetForNode(state, gap, paddings);
|
|
504
|
+
} else {
|
|
505
|
+
state.realCount += 1;
|
|
506
|
+
state.lastAfter = gap.after;
|
|
476
507
|
}
|
|
477
508
|
maxY = Math.max(maxY, nodeY$1(node) + Math.max(node.in, node.out));
|
|
478
509
|
}
|
|
@@ -511,8 +542,15 @@ function layout(nodes, data, { priority, height, nodePadding, modeX }) {
|
|
|
511
542
|
];
|
|
512
543
|
const maxX = calculateX(nodes, data, modeX ?? 'edge');
|
|
513
544
|
const maxY = priority ? calculateYUsingPriority(nodeArray, maxX) : calculateY(nodeArray, maxX);
|
|
514
|
-
const
|
|
515
|
-
const
|
|
545
|
+
const scale = maxY / height;
|
|
546
|
+
const scaledGaps = new Map();
|
|
547
|
+
for (const [key, gap] of nodePadding){
|
|
548
|
+
scaledGaps.set(key, {
|
|
549
|
+
after: gap.after * scale,
|
|
550
|
+
before: gap.before * scale
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
const maxYWithPadding = addPadding(nodeArray, scaledGaps);
|
|
516
554
|
sortFlows(nodeArray);
|
|
517
555
|
return {
|
|
518
556
|
maxX,
|
|
@@ -626,16 +664,29 @@ function getNodeRect(node, size, xScale, yScale, maxColumn, nodeWidth, columnPad
|
|
|
626
664
|
y
|
|
627
665
|
};
|
|
628
666
|
}
|
|
667
|
+
function resolveNodeGap(option, node) {
|
|
668
|
+
const resolved = resolveNodeOption(option ?? 10, node) ?? 10;
|
|
669
|
+
if (typeof resolved === 'number') {
|
|
670
|
+
return {
|
|
671
|
+
after: resolved,
|
|
672
|
+
before: resolved
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
return {
|
|
676
|
+
after: resolved.after ?? 10,
|
|
677
|
+
before: resolved.before ?? 10
|
|
678
|
+
};
|
|
679
|
+
}
|
|
629
680
|
function resolveNodeLabelStyle(options, node) {
|
|
630
681
|
const { backgroundColor, borderRadius = 0, color, display, font, padding = 4, position } = options.nodeLabels ?? {};
|
|
631
682
|
return {
|
|
632
|
-
backgroundColor:
|
|
683
|
+
backgroundColor: resolveNodeOption(backgroundColor, node),
|
|
633
684
|
borderRadius,
|
|
634
|
-
color:
|
|
635
|
-
display:
|
|
685
|
+
color: resolveNodeOption(color, node) ?? options.color ?? 'black',
|
|
686
|
+
display: resolveNodeOption(display, node) ?? true,
|
|
636
687
|
font,
|
|
637
688
|
padding,
|
|
638
|
-
position:
|
|
689
|
+
position: resolveNodeOption(position, node) ?? 'auto'
|
|
639
690
|
};
|
|
640
691
|
}
|
|
641
692
|
class SankeyController extends chart_js.DatasetController {
|
|
@@ -646,10 +697,14 @@ class SankeyController extends chart_js.DatasetController {
|
|
|
646
697
|
const nodes = buildNodesFromData(sankeyData, this.options);
|
|
647
698
|
const orientation = this.options.orientation ?? 'horizontal';
|
|
648
699
|
this._nodes = nodes;
|
|
700
|
+
const nodeGaps = new Map();
|
|
701
|
+
for (const node of nodes.values()){
|
|
702
|
+
nodeGaps.set(node.key, resolveNodeGap(this.options.nodePadding, node));
|
|
703
|
+
}
|
|
649
704
|
const { maxX, maxY } = layout(nodes, sankeyData, {
|
|
650
705
|
height: orientation === 'vertical' ? this.chart.width : this.chart.height,
|
|
651
706
|
modeX: this.options.modeX,
|
|
652
|
-
nodePadding:
|
|
707
|
+
nodePadding: nodeGaps,
|
|
653
708
|
priority: !!this.options.priority
|
|
654
709
|
});
|
|
655
710
|
this._maxX = maxX;
|
|
@@ -796,7 +851,7 @@ class SankeyController extends chart_js.DatasetController {
|
|
|
796
851
|
SankeyController.id = 'sankey';
|
|
797
852
|
SankeyController.descriptors = {
|
|
798
853
|
_indexable: false,
|
|
799
|
-
_scriptable:
|
|
854
|
+
_scriptable: (name)=>name !== 'nodePadding',
|
|
800
855
|
nodeLabels: {
|
|
801
856
|
_indexable: false,
|
|
802
857
|
_scriptable: false
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* chartjs-chart-sankey v0.
|
|
2
|
+
* chartjs-chart-sankey v0.17.0
|
|
3
3
|
* https://chartjs-chart-sankey.pages.dev/
|
|
4
4
|
* (c) 2026 Jukka Kurkela
|
|
5
5
|
* Released under the MIT license
|
|
@@ -40,7 +40,7 @@ function isPatternOrGradient(value) {
|
|
|
40
40
|
const type = Object.prototype.toString.call(value);
|
|
41
41
|
return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
|
|
42
42
|
}
|
|
43
|
-
function
|
|
43
|
+
function resolveNodeOption(option, node) {
|
|
44
44
|
if (typeof option === 'function') {
|
|
45
45
|
return option(node);
|
|
46
46
|
}
|
|
@@ -439,7 +439,36 @@ const nodeByXYSize = (a, b)=>{
|
|
|
439
439
|
if (nodeY$1(a) === nodeY$1(b)) return a.size - b.size;
|
|
440
440
|
return nodeY$1(a) - nodeY$1(b);
|
|
441
441
|
};
|
|
442
|
-
|
|
442
|
+
function createColumnGapState() {
|
|
443
|
+
return {
|
|
444
|
+
lastAfter: 0,
|
|
445
|
+
realCount: 0,
|
|
446
|
+
realCumOffset: 0,
|
|
447
|
+
yHistory: []
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function countCrossColumnPaddings(grid, colIdx, y, ownPaddings) {
|
|
451
|
+
let paddings = ownPaddings;
|
|
452
|
+
for(let col = 0; col < colIdx; col++){
|
|
453
|
+
const otherHistory = grid[col].yHistory;
|
|
454
|
+
for(let row = 0; row < otherHistory.length; row++){
|
|
455
|
+
if (otherHistory[row] > y) break;
|
|
456
|
+
paddings = Math.max(row + 1, paddings);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return paddings;
|
|
460
|
+
}
|
|
461
|
+
function offsetForNode(state, gap, paddings) {
|
|
462
|
+
const realNodesAbove = state.realCount;
|
|
463
|
+
const transitionGap = realNodesAbove > 0 ? Math.max(state.lastAfter, gap.before) : 0;
|
|
464
|
+
const realCumOffset = state.realCumOffset + transitionGap;
|
|
465
|
+
const virtualLevels = paddings - realNodesAbove;
|
|
466
|
+
state.realCount = realNodesAbove + 1;
|
|
467
|
+
state.realCumOffset = realCumOffset;
|
|
468
|
+
state.lastAfter = gap.after;
|
|
469
|
+
return realCumOffset + virtualLevels * gap.before;
|
|
470
|
+
}
|
|
471
|
+
function addPadding(nodeArray, gaps) {
|
|
443
472
|
let maxY = 0;
|
|
444
473
|
const columnXs = new Map();
|
|
445
474
|
const grid = [];
|
|
@@ -447,7 +476,7 @@ const nodeByXYSize = (a, b)=>{
|
|
|
447
476
|
if (!columnXs.has(x)) {
|
|
448
477
|
const index = grid.length;
|
|
449
478
|
columnXs.set(x, index);
|
|
450
|
-
grid.push(
|
|
479
|
+
grid.push(createColumnGapState());
|
|
451
480
|
return index;
|
|
452
481
|
}
|
|
453
482
|
return columnXs.get(x) ?? 0;
|
|
@@ -455,21 +484,23 @@ const nodeByXYSize = (a, b)=>{
|
|
|
455
484
|
nodeArray.sort(nodeByXYSize);
|
|
456
485
|
for (const node of nodeArray){
|
|
457
486
|
const colIdx = getColIndex(nodeX$1(node));
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
487
|
+
const state = grid[colIdx];
|
|
488
|
+
const gap = gaps.get(node.key) ?? {
|
|
489
|
+
after: 0,
|
|
490
|
+
before: 0
|
|
491
|
+
};
|
|
492
|
+
const y = nodeY$1(node);
|
|
493
|
+
if (y) {
|
|
494
|
+
state.yHistory.push(y);
|
|
495
|
+
let paddings = state.yHistory.length;
|
|
462
496
|
if (node.in) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
for(let row = 0; row < otherColumn.length; row++){
|
|
466
|
-
if (otherColumn[row] > nodeY$1(node)) break;
|
|
467
|
-
paddings = Math.max(row + 1, paddings);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
while(column.length < paddings)column.push(nodeY$1(node));
|
|
497
|
+
paddings = countCrossColumnPaddings(grid, colIdx, y, paddings);
|
|
498
|
+
while(state.yHistory.length < paddings)state.yHistory.push(y);
|
|
471
499
|
}
|
|
472
|
-
node.y =
|
|
500
|
+
node.y = y + offsetForNode(state, gap, paddings);
|
|
501
|
+
} else {
|
|
502
|
+
state.realCount += 1;
|
|
503
|
+
state.lastAfter = gap.after;
|
|
473
504
|
}
|
|
474
505
|
maxY = Math.max(maxY, nodeY$1(node) + Math.max(node.in, node.out));
|
|
475
506
|
}
|
|
@@ -508,8 +539,15 @@ function layout(nodes, data, { priority, height, nodePadding, modeX }) {
|
|
|
508
539
|
];
|
|
509
540
|
const maxX = calculateX(nodes, data, modeX ?? 'edge');
|
|
510
541
|
const maxY = priority ? calculateYUsingPriority(nodeArray, maxX) : calculateY(nodeArray, maxX);
|
|
511
|
-
const
|
|
512
|
-
const
|
|
542
|
+
const scale = maxY / height;
|
|
543
|
+
const scaledGaps = new Map();
|
|
544
|
+
for (const [key, gap] of nodePadding){
|
|
545
|
+
scaledGaps.set(key, {
|
|
546
|
+
after: gap.after * scale,
|
|
547
|
+
before: gap.before * scale
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
const maxYWithPadding = addPadding(nodeArray, scaledGaps);
|
|
513
551
|
sortFlows(nodeArray);
|
|
514
552
|
return {
|
|
515
553
|
maxX,
|
|
@@ -623,16 +661,29 @@ function getNodeRect(node, size, xScale, yScale, maxColumn, nodeWidth, columnPad
|
|
|
623
661
|
y
|
|
624
662
|
};
|
|
625
663
|
}
|
|
664
|
+
function resolveNodeGap(option, node) {
|
|
665
|
+
const resolved = resolveNodeOption(option ?? 10, node) ?? 10;
|
|
666
|
+
if (typeof resolved === 'number') {
|
|
667
|
+
return {
|
|
668
|
+
after: resolved,
|
|
669
|
+
before: resolved
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
return {
|
|
673
|
+
after: resolved.after ?? 10,
|
|
674
|
+
before: resolved.before ?? 10
|
|
675
|
+
};
|
|
676
|
+
}
|
|
626
677
|
function resolveNodeLabelStyle(options, node) {
|
|
627
678
|
const { backgroundColor, borderRadius = 0, color, display, font, padding = 4, position } = options.nodeLabels ?? {};
|
|
628
679
|
return {
|
|
629
|
-
backgroundColor:
|
|
680
|
+
backgroundColor: resolveNodeOption(backgroundColor, node),
|
|
630
681
|
borderRadius,
|
|
631
|
-
color:
|
|
632
|
-
display:
|
|
682
|
+
color: resolveNodeOption(color, node) ?? options.color ?? 'black',
|
|
683
|
+
display: resolveNodeOption(display, node) ?? true,
|
|
633
684
|
font,
|
|
634
685
|
padding,
|
|
635
|
-
position:
|
|
686
|
+
position: resolveNodeOption(position, node) ?? 'auto'
|
|
636
687
|
};
|
|
637
688
|
}
|
|
638
689
|
class SankeyController extends DatasetController {
|
|
@@ -643,10 +694,14 @@ class SankeyController extends DatasetController {
|
|
|
643
694
|
const nodes = buildNodesFromData(sankeyData, this.options);
|
|
644
695
|
const orientation = this.options.orientation ?? 'horizontal';
|
|
645
696
|
this._nodes = nodes;
|
|
697
|
+
const nodeGaps = new Map();
|
|
698
|
+
for (const node of nodes.values()){
|
|
699
|
+
nodeGaps.set(node.key, resolveNodeGap(this.options.nodePadding, node));
|
|
700
|
+
}
|
|
646
701
|
const { maxX, maxY } = layout(nodes, sankeyData, {
|
|
647
702
|
height: orientation === 'vertical' ? this.chart.width : this.chart.height,
|
|
648
703
|
modeX: this.options.modeX,
|
|
649
|
-
nodePadding:
|
|
704
|
+
nodePadding: nodeGaps,
|
|
650
705
|
priority: !!this.options.priority
|
|
651
706
|
});
|
|
652
707
|
this._maxX = maxX;
|
|
@@ -793,7 +848,7 @@ class SankeyController extends DatasetController {
|
|
|
793
848
|
SankeyController.id = 'sankey';
|
|
794
849
|
SankeyController.descriptors = {
|
|
795
850
|
_indexable: false,
|
|
796
|
-
_scriptable:
|
|
851
|
+
_scriptable: (name)=>name !== 'nodePadding',
|
|
797
852
|
nodeLabels: {
|
|
798
853
|
_indexable: false,
|
|
799
854
|
_scriptable: false
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* chartjs-chart-sankey v0.
|
|
2
|
+
* chartjs-chart-sankey v0.17.0
|
|
3
3
|
* https://chartjs-chart-sankey.pages.dev/
|
|
4
4
|
* (c) 2026 Jukka Kurkela
|
|
5
5
|
* Released under the MIT license
|
|
6
6
|
*/
|
|
7
|
-
!function(t,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports,require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["exports","chart.js","chart.js/helpers"],o):o((t="undefined"!=typeof globalThis?globalThis:t||self)["chartjs-chart-sankey"]={},t.Chart,t.Chart.helpers)}(this,function(t,o,e){"use strict";const r=t=>void 0!==t;function n(t){return t&&-1!==["min","max"].indexOf(t)?t:"max"}function i(t,o){return"function"==typeof t?t(o):t&&"object"==typeof t&&!function(t){const o=Object.prototype.toString.call(t);return"[object CanvasPattern]"===o||"[object CanvasGradient]"===o}(t)?t[o.key]:t}function a(t,o,e,r,n,i,a){t.save(),t.fillStyle=o,a>0?(!function(t,o,e,r,n,i){const a=Math.max(0,Math.min(i,r/2,n/2));t.beginPath(),t.moveTo(o+a,e),t.lineTo(o+r-a,e),t.quadraticCurveTo(o+r,e,o+r,e+a),t.lineTo(o+r,e+n-a),t.quadraticCurveTo(o+r,e+n,o+r-a,e+n),t.lineTo(o+a,e+n),t.quadraticCurveTo(o,e+n,o,e+n-a),t.lineTo(o,e+a),t.quadraticCurveTo(o,e,o+a,e),t.closePath()}(t,e,r,n,i,a),t.fill()):t.fillRect(e,r,n,i),t.restore()}function s(t,o,e){const r=function(t){if(!t)return[];const o=[],e=Array.isArray(t)?t:[t];for(;e.length;){const t=e.pop();"string"==typeof t?o.unshift(...t.split("\n")):Array.isArray(t)?e.push(...t):t&&o.unshift(`${t}`)}return o}(o);if(!r.length)return;const{backgroundColor:n,borderRadius:i,color:s,font:l,lineOffset:h,padding:c}=e,d=function(t,o){return"auto"===t?o:t}(e.position,e.autoPosition),f=Number(l.lineHeight);t.font=l.string;const u=Math.max(...r.map(o=>t.measureText(o).width)),p=f*r.length,y=function(t,o,e){const{borderWidth:r,height:n,padding:i,width:a,x:s,y:l}=o,h={align:"center",x:s+a/2,y:l+n/2};return"left"===t?(h.align="right",h.x=s-r-i):"right"===t?(h.align="left",h.x=s+a+r+i):"top"===t?h.y=l-i-e/2:"bottom"===t&&(h.y=l+n+i+e/2),h}(d,e,p);t.textAlign=y.align,t.textBaseline="middle";const g=u+2*c,x=p+2*c,m=function(t,o,e,r,n){return"left"===t?o-n:"right"===t?o-e-n:o-r/2}(y.align,y.x,u,g,c),w=1===r.length?y.y:y.y-p/2+h,b=w+(r.length-1)*f/2;void 0!==n&&a(t,n,m,b-x/2,g,x,i),t.fillStyle=s;for(let o=0;o<r.length;o++)t.fillText(r[o],y.x,w+o*f)}const l=(t,o)=>o.flow===t.flow?t.index-o.index:o.flow-t.flow;function h(t,{size:o,priority:e,column:r}){const i=new Map;for(let o=0;o<t.length;o++){const{from:e,to:r,flow:n}=t[o],a=i.get(e)??{from:[],in:0,key:e,out:0,size:0,to:[]},s=(e===r?a:i.get(r))??{from:[],in:0,key:r,out:0,size:0,to:[]};a.out+=n,a.to.push({addY:0,flow:n,index:o,key:r,node:s}),1===a.to.length&&i.set(e,a),s.in+=n,s.from.push({addY:0,flow:n,index:o,key:e,node:a}),1===s.from.length&&i.set(r,s)}return((t,o)=>{const e=n(o);for(const o of t.values())o.from.sort(l),o.to.sort(l),o.size=Math[e](o.in||o.out,o.out||o.in)})(i,o),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.priority=o[e.key])})(i,e),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.column=!0,e.x=o[e.key])})(i,r),i}const c=1e-6;function d(t){return t.x??0}function f(t){return t.y??0}const u=(t,o=new Set)=>{const e=[];for(const r of t)o.has(r.key)||(o.add(r.key),e.push(r.key,...u(r.to.map(t=>t.node),o)));return e},p=(t,o)=>{const e=o.filter(t=>0===t.from.length),r=e.map(t=>t.key),n=u(e),i=new Set(n);for(const o of t)i.has(o.from)||i.has(o.to)||(r.push(o.from),i.add(o.from)),i.add(o.to);return r},y=(t,o)=>{const e=new Set(t.filter(t=>o.has(t.from)).map(t=>t.to)),r=[...o],n=r.filter(t=>!e.has(t));return n.length?n:r.slice(0,1)};function g(t,o,e=new Set){let r=0;for(const n of t)e.has(n.node)||(e.add(n.node),r+=n.node[o].length+g(n.node[o],o,e));return r}const x=t=>(o,e)=>g(o.node[t],t)-g(e.node[t],t)||o.node[t].length-e.node[t].length;function m(t,o){if(!t.from.length)return o;t.from.sort(x("from"));for(const e of t.from){const t=e.node;r(t.y)||(t.y=o,m(t,o?o+c:0)),o=Math.max(t.y+t.out,o)}return f(t)+t.size}const w=(t,o)=>Boolean(o&&d(o)<d(t));function b(t,o){if(!t.to.length)return o;t.to.sort(x("to"));for(let e=0;e<t.to.length;e++){const n=t.to[e],i=n.node;r(i.y)||(i.y=o,b(i,o?o+c:0)),w(i,t.to[e+1]?.node)?o+=n.flow:o=Math.max(i.y+Math.max(i.in,i.out),o)}return f(t)+t.size}function M(t,o){return r(t.y)?t.y:(t.y=o,o)}function v(t,o){if(!t.length)return 0;const e=((t,o)=>{const e=[...t].sort((t,o)=>t.size-o.size),r=e[e.length-1].size,n=t.filter(t=>t.size===r),i=n[0];if(1===n.length)return i;if(n.sort((t,o)=>d(t)-d(o)),0===d(i))return i;const a=n[n.length-1];return d(a)===o?a:n[Math.floor(n.length/2)]})(t,o);return e.y=0,m(e,0),b(e,0),function(t,o){const e=t.filter(t=>0===t.x),n=t.filter(t=>t.x===o),i=e.filter(t=>!r(t.y)),a=n.filter(t=>!r(t.y)),s=t.filter(t=>d(t)>0&&d(t)<o&&!r(t.y));let l=e.reduce((t,o)=>Math.max(t,f(o)+o.out||0),0)+c,h=n.reduce((t,o)=>Math.max(t,f(o)+o.in||0),0)+c,u=0;l>=h?(i.forEach(t=>{l=M(t,l),l=Math.max(l+t.out,b(t,l))}),a.forEach(t=>{h=M(t,h),h=Math.max(h+t.in,m(t,h))})):(i.forEach(t=>{l=M(t,l)}),a.forEach(t=>{h=M(t,h),h=Math.max(h+t.in,m(t,h))})),s.forEach(o=>{let e=t.filter(t=>d(t)===d(o)&&r(t.y)).reduce((t,o)=>Math.max(t,f(o)+Math.max(o.in,o.out)),0);e=M(o,e),e=Math.max(e+o.in,m(o,e)),e=Math.max(e+o.out,b(o,e)),u=Math.max(u,e)}),Math.max(l,h,u)}(t,o),((t,o)=>{let e=0;for(let r=0;r<=o;r++){const o=t.filter(t=>d(t)===r).sort((t,o)=>f(t)-f(o));let n=0;for(const t of o)f(t)<n&&(t.y=n),n=f(t)+t.size;e=Math.max(e,n)}return e})(t,o)}const k=(t,o)=>d(t)!==d(o)?d(t)-d(o):f(t)===f(o)?t.size-o.size:f(t)-f(o);function C(t,o,{priority:e,height:n,nodePadding:i,modeX:a}){const s=[...t.values()],l=function(t,o,e){const n=o.filter(t=>t.from!==t.to),i=[...t.keys()],a=[...t.values()],s=new Set(i);let l=0;for(;s.size;){const e=0===l?p(o,a):y(n,s);if(!e.length)throw new Error("Fatal error: Unable to place nodes to columns. Please report this issue.");for(const o of e){const e=t.get(o);e&&!r(e.x)&&(e.x=l),s.delete(o)}s.size&&l++}const h=a.reduce((t,o)=>Math.max(t,d(o)),0);if("edge"===e){const e=new Set(o.map(t=>t.from));i.filter(t=>!e.has(t)).forEach(o=>{const e=t.get(o);e&&!e.column&&(e.x=h)})}return h}(t,o,a??"edge"),h=e?function(t,o){let e=0,r=0;for(let n=0;n<=o;n++){let o=r;const i=t.filter(t=>d(t)===n).sort((t,o)=>(t.priority??0)-(o.priority??0));if(i.length){const o=t.reduce((t,o)=>d(o)>n?Math.min(t,d(o)):t,1/0);r=i[0].to.filter(t=>d(t.node)>o).reduce((t,o)=>t+o.flow,0)||0}for(const t of i)t.y=o,o+=Math.max(t.out,t.in);e=Math.max(o,e)}return e}(s,l):v(s,l),c=function(t,o){let e=0;const r=new Map,n=[],i=t=>{if(!r.has(t)){const o=n.length;return r.set(t,o),n.push([]),o}return r.get(t)??0};t.sort(k);for(const r of t){const t=i(d(r)),a=n[t]??[];if(f(r)){a.push(f(r));let e=a.length;if(r.in){for(let o=0;o<t;o++){const t=n[o]??[];for(let o=0;o<t.length&&!(t[o]>f(r));o++)e=Math.max(o+1,e)}for(;a.length<e;)a.push(f(r))}r.y=f(r)+e*o}e=Math.max(e,f(r)+Math.max(r.in,r.out))}return e}(s,h/n*i);return function(t){t.forEach(t=>{const o=t.size,e=o<t.in,r=o<t.out;let n=0,i=t.from.length;t.from.sort((t,o)=>f(t.node)+t.node.out/2-(f(o.node)+o.node.out/2)).forEach((t,r)=>{e?t.addY=r*(o-t.flow)/(i-1):(t.addY=n,n+=t.flow)}),n=0,i=t.to.length,t.to.sort((t,o)=>f(t.node)+t.node.in/2-(f(o.node)+o.node.in/2)).forEach((t,e)=>{r?t.addY=e*(o-t.flow)/(i-1):(t.addY=n,n+=t.flow)})})}(s),{maxX:l,maxY:c}}function _(t){return t.x??0}function P(t){return t.y??0}function T(t,o){return Math[o](t.in||t.out,t.out||t.in)}function S(t,o,e,r){return"vertical"===r?o<(e.top+e.bottom)/2?"bottom":"top":t<(e.left+e.right)/2?"right":"left"}function z(t,o,e){for(const r of t)if(r.key===o&&r.index===e)return r.addY;return 0}function F(t,o,e,r,n,i,a,s,l){return"vertical"===l?{_custom:{flow:n,from:t,height:a.parse(n,i),to:o,x:a.parse(r,i),y:s.parse(_(o),i)},x:a.parse(e,i),y:s.parse(_(t),i)}:{_custom:{flow:n,from:t,height:s.parse(n,i),to:o,x:a.parse(_(o),i),y:s.parse(r,i)},x:a.parse(_(t),i),y:s.parse(e,i)}}function E(t,o,e,r,n,i,a,s){const l=t._custom,h=o.getPixelForValue(t.x),c=e.getPixelForValue(t.y);return"vertical"===s?{flow:l.flow,from:l.from,height:0,to:l.to,width:Math.abs(o.getPixelForValue(t.x+l.height)-h),x:h,x2:o.getPixelForValue(l.x),y:R(e,t.y,r,i)+n+a,y2:R(e,l.y,r,i)-a}:{flow:l.flow,from:l.from,height:Math.abs(e.getPixelForValue(t.y+l.height)-c),to:l.to,width:0,x:R(o,t.x,r,i)+n+a,x2:R(o,l.x,r,i)-a,y:c,y2:e.getPixelForValue(l.y)}}function R(t,o,e,r){const n=t.getPixelForValue(o);return e?n-o/e*r:n}function W(t,o,e){const r="vertical"===o?e.height-e.chartArea.bottom:e.width-e.chartArea.right;return Math.max(0,t+3-r)}function X(t,o,e,r,n,i,a,s){if("vertical"===s){const s=e.getPixelForValue(P(t));return{height:i,width:Math.abs(e.getPixelForValue(P(t)+o)-s),x:s,y:R(r,_(t),n,a)}}const l=r.getPixelForValue(P(t));return{height:Math.abs(r.getPixelForValue(P(t)+o)-l),width:i,x:R(e,_(t),n,a),y:l}}function Y(t,o){const{backgroundColor:e,borderRadius:r=0,color:n,display:a,font:s,padding:l=4,position:h}=t.nodeLabels??{};return{backgroundColor:i(e,o),borderRadius:r,color:i(n,o)??t.color??"black",display:i(a,o)??!0,font:s,padding:l,position:i(h,o)??"auto"}}class j extends o.DatasetController{parseObjectData(t,o,e,r){const n=((t,o)=>{const{from:e="from",to:r="to",flow:n="flow"}=o;return t.map(({[e]:t,[r]:o,[n]:i})=>({flow:i,from:t,to:o}))})(o,this.options.parsing),{xScale:i,yScale:a}=t,s=[],l=h(n,this.options),c=this.options.orientation??"horizontal";this._nodes=l;const{maxX:d,maxY:f}=C(l,n,{height:"vertical"===c?this.chart.width:this.chart.height,modeX:this.options.modeX,nodePadding:this.options.nodePadding??10,priority:!!this.options.priority});if(this._maxX=d,this._maxY=f,!i||!a)return[];for(let t=0,o=n.length;t<o;++t){const o=n[t],e=l.get(o.from),r=l.get(o.to);if(!e||!r)continue;const h=P(e)+z(e.to,o.to,t),d=P(r)+z(r.from,o.from,t);s.push(F(e,r,h,d,o.flow,t,i,a,c))}return s.slice(e,e+r)}getMinMax(t){return{max:t===("vertical"===this.options.orientation?this._cachedMeta.yScale:this._cachedMeta.xScale)?this._maxX:this._maxY,min:0}}update(t){const{data:o}=this._cachedMeta;this.updateElements(o,0,o.length,t)}updateElements(t,o,e,r){const{xScale:n,yScale:i}=this._cachedMeta;if(!n||!i)return;const a=this.resolveDataElementOptions(o,r),s=this.getSharedOptions(a),{borderWidth:l,nodeWidth:h=10,orientation:c="horizontal"}=this.options,d=W(h,c,this.chart),f=l?l/2+.5:0;for(let a=o;a<o+e;a++){const o=this.getParsed(a);this.updateElement(t[a],a,{options:this.resolveDataElementOptions(a,r),progress:"reset"===r?0:1,...E(o,n,i,this._maxX,h,d,f,c)},r)}s&&this.updateSharedOptions(s,r,a)}_drawLabels(){const t=this.chart.ctx,r=this.options,i=this._nodes||new Map,a=n(r.size),l=r.labels,{borderWidth:h=1,nodeWidth:c=10,orientation:d="horizontal"}=r,f=W(c,d,this.chart),u=r.font??this.chart.options.font??o.Chart.defaults.font,{xScale:p,yScale:y}=this._cachedMeta;if(!p||!y)return;t.save();const g=this.chart.chartArea;for(const o of i.values()){const n=T(o,a),{height:i,width:x,x:m,y:w}=X(o,n,p,y,this._maxX,c,f,d),b=l?.[o.key]??o.key,M=Y(r,o);if(M.display){const o=e.toFont(M.font??u);s(t,b,{autoPosition:S(m,w,g,d),backgroundColor:M.backgroundColor,borderRadius:M.borderRadius,borderWidth:h,color:M.color,font:o,height:i,lineOffset:e.valueOrDefault(r.padding,o.lineHeight/2),padding:M.padding,position:M.position,width:x,x:m,y:w})}}t.restore()}_drawNodes(){const t=this.chart.ctx,o=this._nodes||new Map,{borderColor:e,borderWidth:r=0,nodeWidth:i=10,orientation:a="horizontal",size:s}=this.options,l=W(i,a,this.chart),h=n(s),{xScale:c,yScale:d}=this._cachedMeta;t.save(),e&&r&&(t.strokeStyle=e,t.lineWidth=r);for(const e of o.values()){if(t.fillStyle=e.color??"black",!c||!d)return;const o=Math[h](e.in||e.out,e.out||e.in),{height:n,width:s,x:f,y:u}=X(e,o,c,d,this._maxX,i,l,a);r&&t.strokeRect(f,u,s,n),t.fillRect(f,u,s,n)}t.restore()}draw(){const t=this.chart.ctx,o=this.getMeta().data??[],e=[];for(let t=0,r=o.length;t<r;++t){const r=o[t];r.from&&r.to&&(r.from.color=r.options.colorFrom,r.to.color=r.options.colorTo,r.active&&e.push(r))}for(const t of e)t.from&&t.to&&(t.from.color=t.options.colorFrom,t.to.color=t.options.colorTo);this._drawNodes();for(let e=0,r=o.length;e<r;++e)o[e].draw(t);this._drawLabels()}constructor(...t){super(...t),this._nodes=new Map,this._maxX=0,this._maxY=0}}j.id="sankey",j.descriptors={_indexable:!1,_scriptable:!0,nodeLabels:{_indexable:!1,_scriptable:!1}},j.defaults={animations:{colors:{properties:["colorFrom","colorTo"],type:"color"},numbers:{properties:["x","y","x2","y2","height","width"],type:"number"},progress:{delay:t=>"data"===t.type?500*t.parsed["vertical"===t.dataset.orientation?"y":"x"]+20*t.dataIndex:void 0,duration:t=>"data"===t.type?200*(t.parsed._custom["vertical"===t.dataset.orientation?"y":"x"]-t.parsed["vertical"===t.dataset.orientation?"y":"x"]):void 0,easing:"linear"}},borderColor:"black",borderWidth:1,color:"black",dataElementType:"flow",modeX:"edge",nodePadding:10,nodeWidth:10,orientation:"horizontal",transitions:{hide:{animations:{colors:{properties:["colorFrom","colorTo"],to:"transparent",type:"color"}}},resize:{animations:{progress:{delay:0,duration:0}}},show:{animations:{colors:{from:"transparent",properties:["colorFrom","colorTo"],type:"color"}}}}},j.overrides={datasets:{clip:!1,parsing:{flow:"flow",from:"from",to:"to"}},interaction:{intersect:!0,mode:"nearest"},layout:{padding:{bottom:3,left:3,right:13,top:3}},plugins:{legend:{display:!1},tooltip:{callbacks:{label(t){const o=t.parsed._custom;return`${o.from.key} -> ${o.to.key}: ${o.flow}`},title:()=>""}}},scales:{x:{bounds:"data",display:!1,min:0,offset:!1,type:"linear"},y:{bounds:"data",display:!1,min:0,offset:!1,reverse:!0,type:"linear"}}};const O=(t,o,e,r,n)=>"vertical"===n?o<r?{cp1:{x:t,y:o+(r-o)/3*2},cp2:{x:e,y:o+(r-o)/3}}:{cp1:{x:0,y:o-(o-r)/3},cp2:{x:0,y:r+(o-r)/3}}:t<e?{cp1:{x:t+(e-t)/3*2,y:o},cp2:{x:t+(e-t)/3,y:r}}:{cp1:{x:t-(t-e)/3,y:0},cp2:{x:e+(t-e)/3,y:0}},V=(t,o,e)=>({x:t.x+e*(o.x-t.x),y:t.y+e*(o.y-t.y)}),L=(t,o)=>e.color(t).alpha(o).rgbString(),A=(t,o)=>"string"==typeof t?L(t,o):t,q=t=>"string"==typeof t?e.getHoverColor(t):t;class D extends o.Element{draw(t){const{x:r,x2:n,y:i,y2:a,height:l,progress:h,width:c}=this,d=this.options.orientation,f=O(r,i,n,a,d),u={height:l,width:c,x:r,x2:n,y:i,y2:a};if(0===h)return;t.save(),h<1&&function(t,{height:o,width:e,x:r,x2:n,y:i,y2:a},s,l){t.beginPath(),"vertical"===l?t.rect(Math.min(r,n),i,Math.abs(n-r)+e+1,(a-i)*s+1):t.rect(r,Math.min(i,a),(n-r)*s+1,Math.abs(a-i)+o+1),t.clip()}(t,u,h,d),function(t,{x:o,x2:e,y:r,y2:n,options:i}){let a="black";null!==i.flowColor?a=i.flowColor:"from"===i.colorMode?a=A(i.colorFrom,i.alpha):"to"===i.colorMode?a=A(i.colorTo,i.alpha):"string"==typeof i.colorFrom&&"string"==typeof i.colorTo&&(a="vertical"===i.orientation?t.createLinearGradient(0,r,0,n):t.createLinearGradient(o,0,e,0),a.addColorStop(0,L(i.colorFrom,i.alpha)),a.addColorStop(1,L(i.colorTo,i.alpha))),t.fillStyle=a,t.strokeStyle=a,t.lineWidth=.5}(t,this),function(t,{height:o,width:e,x:r,x2:n,y:i,y2:a},{cp1:s,cp2:l},h){t.beginPath(),t.moveTo(r,i),t.bezierCurveTo(s.x,s.y,l.x,l.y,n,a),"vertical"===h?(t.lineTo(n+e,a),t.bezierCurveTo(l.x+e,l.y,s.x+e,s.y,r+e,i)):(t.lineTo(n,a+o),t.bezierCurveTo(l.x,l.y+o,s.x,s.y+o,r,i+o)),t.lineTo(r,i),t.stroke(),t.closePath(),t.fill()}(t,u,f,d);const p=this.options.flowLabels;if(p.display){const r=e.toFont(p.font??o.Chart.defaults.font),n=function({height:t,width:o,x:e,x2:r,y:n,y2:i},a){return"vertical"===a?{height:i-n,width:Math.abs(r-e)+o,x:Math.min(e,r),y:n}:{height:Math.abs(i-n)+t,width:r-e,x:e,y:Math.min(n,i)}}(u,d);s(t,`${this.flow}`,{autoPosition:"center",backgroundColor:p.backgroundColor,borderRadius:p.borderRadius,borderWidth:0,color:p.color,font:r,height:n.height,lineOffset:r.lineHeight/2,padding:p.padding,position:p.position,width:n.width,x:n.x,y:n.y})}t.restore()}inRange(t,o,e){const{x:r,y:n,x2:i,y2:a,height:s,width:l}=this.getProps(["x","y","x2","y2","height","width"],e),h="vertical"===this.options.orientation;if(h?o<n||o>a:t<r||t>i)return!1;const{cp1:c,cp2:d}=O(r,n,i,a,this.options.orientation),f=h?(o-n)/(a-n):(t-r)/(i-r),u={x:i,y:a},p=V({x:r,y:n},c,f),y=V(c,d,f),g=V(d,u,f),x=V(p,y,f),m=V(y,g,f),w=V(x,m,f);return h?t>=w.x&&t<=w.x+l:o>=w.y&&o<=w.y+s}inXRange(t,o){const{x:e,x2:r,width:n}=this.getProps(["x","x2","width"],o),i=Math.min(e,r),a=Math.max(e,r)+("vertical"===this.options.orientation?n:0);return t>=i&&t<=a}inYRange(t,o){const{y:e,y2:r,height:n}=this.getProps(["y","y2","height"],o),i=Math.min(e,r),a=Math.max(e,r)+("vertical"===this.options.orientation?0:n);return t>=i&&t<=a}getCenterPoint(t){const{x:o,y:e,x2:r,y2:n,height:i,width:a}=this.getProps(["x","y","x2","y2","height","width"],t),s="vertical"===this.options.orientation;return{x:(o+r+(s?a:0))/2,y:(e+n+(s?0:i))/2}}tooltipPosition(t=!1){return this.getCenterPoint(t)}getRange(t){const o="vertical"===this.options.orientation;return"x"===t?o?this.width/2:0:o?0:this.height/2}constructor(t){super(),this.flow=0,this.x2=0,this.y2=0,this.width=0,this.height=0,this.progress=1,t&&Object.assign(this,t)}}D.id="flow",D.defaults={alpha:.5,colorFrom:"red",colorMode:"gradient",colorTo:"green",flowColor:null,flowLabels:{borderRadius:0,color:"black",display:!1,padding:4,position:"center"},hoverColorFrom:(t,o)=>q(o.colorFrom),hoverColorTo:(t,o)=>q(o.colorTo),orientation:"horizontal"},D.descriptors={_scriptable:!0,flowLabels:{_scriptable:!0}},o.Chart.register(j,D),t.Flow=D,t.SankeyController=j});
|
|
7
|
+
!function(t,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports,require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["exports","chart.js","chart.js/helpers"],o):o((t="undefined"!=typeof globalThis?globalThis:t||self)["chartjs-chart-sankey"]={},t.Chart,t.Chart.helpers)}(this,function(t,o,e){"use strict";const r=t=>void 0!==t;function n(t){return t&&-1!==["min","max"].indexOf(t)?t:"max"}function i(t,o){return"function"==typeof t?t(o):t&&"object"==typeof t&&!function(t){const o=Object.prototype.toString.call(t);return"[object CanvasPattern]"===o||"[object CanvasGradient]"===o}(t)?t[o.key]:t}function a(t,o,e,r,n,i,a){t.save(),t.fillStyle=o,a>0?(!function(t,o,e,r,n,i){const a=Math.max(0,Math.min(i,r/2,n/2));t.beginPath(),t.moveTo(o+a,e),t.lineTo(o+r-a,e),t.quadraticCurveTo(o+r,e,o+r,e+a),t.lineTo(o+r,e+n-a),t.quadraticCurveTo(o+r,e+n,o+r-a,e+n),t.lineTo(o+a,e+n),t.quadraticCurveTo(o,e+n,o,e+n-a),t.lineTo(o,e+a),t.quadraticCurveTo(o,e,o+a,e),t.closePath()}(t,e,r,n,i,a),t.fill()):t.fillRect(e,r,n,i),t.restore()}function s(t,o,e){const r=function(t){if(!t)return[];const o=[],e=Array.isArray(t)?t:[t];for(;e.length;){const t=e.pop();"string"==typeof t?o.unshift(...t.split("\n")):Array.isArray(t)?e.push(...t):t&&o.unshift(`${t}`)}return o}(o);if(!r.length)return;const{backgroundColor:n,borderRadius:i,color:s,font:l,lineOffset:h,padding:c}=e,f=function(t,o){return"auto"===t?o:t}(e.position,e.autoPosition),d=Number(l.lineHeight);t.font=l.string;const u=Math.max(...r.map(o=>t.measureText(o).width)),p=d*r.length,y=function(t,o,e){const{borderWidth:r,height:n,padding:i,width:a,x:s,y:l}=o,h={align:"center",x:s+a/2,y:l+n/2};return"left"===t?(h.align="right",h.x=s-r-i):"right"===t?(h.align="left",h.x=s+a+r+i):"top"===t?h.y=l-i-e/2:"bottom"===t&&(h.y=l+n+i+e/2),h}(f,e,p);t.textAlign=y.align,t.textBaseline="middle";const g=u+2*c,x=p+2*c,m=function(t,o,e,r,n){return"left"===t?o-n:"right"===t?o-e-n:o-r/2}(y.align,y.x,u,g,c),b=1===r.length?y.y:y.y-p/2+h,w=b+(r.length-1)*d/2;void 0!==n&&a(t,n,m,w-x/2,g,x,i),t.fillStyle=s;for(let o=0;o<r.length;o++)t.fillText(r[o],y.x,b+o*d)}const l=(t,o)=>o.flow===t.flow?t.index-o.index:o.flow-t.flow;function h(t,{size:o,priority:e,column:r}){const i=new Map;for(let o=0;o<t.length;o++){const{from:e,to:r,flow:n}=t[o],a=i.get(e)??{from:[],in:0,key:e,out:0,size:0,to:[]},s=(e===r?a:i.get(r))??{from:[],in:0,key:r,out:0,size:0,to:[]};a.out+=n,a.to.push({addY:0,flow:n,index:o,key:r,node:s}),1===a.to.length&&i.set(e,a),s.in+=n,s.from.push({addY:0,flow:n,index:o,key:e,node:a}),1===s.from.length&&i.set(r,s)}return((t,o)=>{const e=n(o);for(const o of t.values())o.from.sort(l),o.to.sort(l),o.size=Math[e](o.in||o.out,o.out||o.in)})(i,o),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.priority=o[e.key])})(i,e),((t,o)=>{if(o)for(const e of t.values())e.key in o&&(e.column=!0,e.x=o[e.key])})(i,r),i}const c=1e-6;function f(t){return t.x??0}function d(t){return t.y??0}const u=(t,o=new Set)=>{const e=[];for(const r of t)o.has(r.key)||(o.add(r.key),e.push(r.key,...u(r.to.map(t=>t.node),o)));return e},p=(t,o)=>{const e=o.filter(t=>0===t.from.length),r=e.map(t=>t.key),n=u(e),i=new Set(n);for(const o of t)i.has(o.from)||i.has(o.to)||(r.push(o.from),i.add(o.from)),i.add(o.to);return r},y=(t,o)=>{const e=new Set(t.filter(t=>o.has(t.from)).map(t=>t.to)),r=[...o],n=r.filter(t=>!e.has(t));return n.length?n:r.slice(0,1)};function g(t,o,e=new Set){let r=0;for(const n of t)e.has(n.node)||(e.add(n.node),r+=n.node[o].length+g(n.node[o],o,e));return r}const x=t=>(o,e)=>g(o.node[t],t)-g(e.node[t],t)||o.node[t].length-e.node[t].length;function m(t,o){if(!t.from.length)return o;t.from.sort(x("from"));for(const e of t.from){const t=e.node;r(t.y)||(t.y=o,m(t,o?o+c:0)),o=Math.max(t.y+t.out,o)}return d(t)+t.size}const b=(t,o)=>Boolean(o&&f(o)<f(t));function w(t,o){if(!t.to.length)return o;t.to.sort(x("to"));for(let e=0;e<t.to.length;e++){const n=t.to[e],i=n.node;r(i.y)||(i.y=o,w(i,o?o+c:0)),b(i,t.to[e+1]?.node)?o+=n.flow:o=Math.max(i.y+Math.max(i.in,i.out),o)}return d(t)+t.size}function M(t,o){return r(t.y)?t.y:(t.y=o,o)}function v(t,o){if(!t.length)return 0;const e=((t,o)=>{const e=[...t].sort((t,o)=>t.size-o.size),r=e[e.length-1].size,n=t.filter(t=>t.size===r),i=n[0];if(1===n.length)return i;if(n.sort((t,o)=>f(t)-f(o)),0===f(i))return i;const a=n[n.length-1];return f(a)===o?a:n[Math.floor(n.length/2)]})(t,o);return e.y=0,m(e,0),w(e,0),function(t,o){const e=t.filter(t=>0===t.x),n=t.filter(t=>t.x===o),i=e.filter(t=>!r(t.y)),a=n.filter(t=>!r(t.y)),s=t.filter(t=>f(t)>0&&f(t)<o&&!r(t.y));let l=e.reduce((t,o)=>Math.max(t,d(o)+o.out||0),0)+c,h=n.reduce((t,o)=>Math.max(t,d(o)+o.in||0),0)+c,u=0;l>=h?(i.forEach(t=>{l=M(t,l),l=Math.max(l+t.out,w(t,l))}),a.forEach(t=>{h=M(t,h),h=Math.max(h+t.in,m(t,h))})):(i.forEach(t=>{l=M(t,l)}),a.forEach(t=>{h=M(t,h),h=Math.max(h+t.in,m(t,h))})),s.forEach(o=>{let e=t.filter(t=>f(t)===f(o)&&r(t.y)).reduce((t,o)=>Math.max(t,d(o)+Math.max(o.in,o.out)),0);e=M(o,e),e=Math.max(e+o.in,m(o,e)),e=Math.max(e+o.out,w(o,e)),u=Math.max(u,e)}),Math.max(l,h,u)}(t,o),((t,o)=>{let e=0;for(let r=0;r<=o;r++){const o=t.filter(t=>f(t)===r).sort((t,o)=>d(t)-d(o));let n=0;for(const t of o)d(t)<n&&(t.y=n),n=d(t)+t.size;e=Math.max(e,n)}return e})(t,o)}const k=(t,o)=>f(t)!==f(o)?f(t)-f(o):d(t)===d(o)?t.size-o.size:d(t)-d(o);function C(t,o,e,r){let n=r;for(let r=0;r<o;r++){const o=t[r].yHistory;for(let t=0;t<o.length&&!(o[t]>e);t++)n=Math.max(t+1,n)}return n}function P(t,o,e){const r=t.realCount,n=r>0?Math.max(t.lastAfter,o.before):0,i=t.realCumOffset+n,a=e-r;return t.realCount=r+1,t.realCumOffset=i,t.lastAfter=o.after,i+a*o.before}function _(t,o,{priority:e,height:n,nodePadding:i,modeX:a}){const s=[...t.values()],l=function(t,o,e){const n=o.filter(t=>t.from!==t.to),i=[...t.keys()],a=[...t.values()],s=new Set(i);let l=0;for(;s.size;){const e=0===l?p(o,a):y(n,s);if(!e.length)throw new Error("Fatal error: Unable to place nodes to columns. Please report this issue.");for(const o of e){const e=t.get(o);e&&!r(e.x)&&(e.x=l),s.delete(o)}s.size&&l++}const h=a.reduce((t,o)=>Math.max(t,f(o)),0);if("edge"===e){const e=new Set(o.map(t=>t.from));i.filter(t=>!e.has(t)).forEach(o=>{const e=t.get(o);e&&!e.column&&(e.x=h)})}return h}(t,o,a??"edge"),h=e?function(t,o){let e=0,r=0;for(let n=0;n<=o;n++){let o=r;const i=t.filter(t=>f(t)===n).sort((t,o)=>(t.priority??0)-(o.priority??0));if(i.length){const o=t.reduce((t,o)=>f(o)>n?Math.min(t,f(o)):t,1/0);r=i[0].to.filter(t=>f(t.node)>o).reduce((t,o)=>t+o.flow,0)||0}for(const t of i)t.y=o,o+=Math.max(t.out,t.in);e=Math.max(o,e)}return e}(s,l):v(s,l),c=h/n,u=new Map;for(const[t,o]of i)u.set(t,{after:o.after*c,before:o.before*c});const g=function(t,o){let e=0;const r=new Map,n=[],i=t=>{if(!r.has(t)){const o=n.length;return r.set(t,o),n.push({lastAfter:0,realCount:0,realCumOffset:0,yHistory:[]}),o}return r.get(t)??0};t.sort(k);for(const r of t){const t=i(f(r)),a=n[t],s=o.get(r.key)??{after:0,before:0},l=d(r);if(l){a.yHistory.push(l);let o=a.yHistory.length;if(r.in)for(o=C(n,t,l,o);a.yHistory.length<o;)a.yHistory.push(l);r.y=l+P(a,s,o)}else a.realCount+=1,a.lastAfter=s.after;e=Math.max(e,d(r)+Math.max(r.in,r.out))}return e}(s,u);return function(t){t.forEach(t=>{const o=t.size,e=o<t.in,r=o<t.out;let n=0,i=t.from.length;t.from.sort((t,o)=>d(t.node)+t.node.out/2-(d(o.node)+o.node.out/2)).forEach((t,r)=>{e?t.addY=r*(o-t.flow)/(i-1):(t.addY=n,n+=t.flow)}),n=0,i=t.to.length,t.to.sort((t,o)=>d(t.node)+t.node.in/2-(d(o.node)+o.node.in/2)).forEach((t,e)=>{r?t.addY=e*(o-t.flow)/(i-1):(t.addY=n,n+=t.flow)})})}(s),{maxX:l,maxY:g}}function T(t){return t.x??0}function S(t){return t.y??0}function z(t,o){return Math[o](t.in||t.out,t.out||t.in)}function F(t,o,e,r){return"vertical"===r?o<(e.top+e.bottom)/2?"bottom":"top":t<(e.left+e.right)/2?"right":"left"}function E(t,o,e){for(const r of t)if(r.key===o&&r.index===e)return r.addY;return 0}function O(t,o,e,r,n,i,a,s,l){return"vertical"===l?{_custom:{flow:n,from:t,height:a.parse(n,i),to:o,x:a.parse(r,i),y:s.parse(T(o),i)},x:a.parse(e,i),y:s.parse(T(t),i)}:{_custom:{flow:n,from:t,height:s.parse(n,i),to:o,x:a.parse(T(o),i),y:s.parse(r,i)},x:a.parse(T(t),i),y:s.parse(e,i)}}function R(t,o,e,r,n,i,a,s){const l=t._custom,h=o.getPixelForValue(t.x),c=e.getPixelForValue(t.y);return"vertical"===s?{flow:l.flow,from:l.from,height:0,to:l.to,width:Math.abs(o.getPixelForValue(t.x+l.height)-h),x:h,x2:o.getPixelForValue(l.x),y:W(e,t.y,r,i)+n+a,y2:W(e,l.y,r,i)-a}:{flow:l.flow,from:l.from,height:Math.abs(e.getPixelForValue(t.y+l.height)-c),to:l.to,width:0,x:W(o,t.x,r,i)+n+a,x2:W(o,l.x,r,i)-a,y:c,y2:e.getPixelForValue(l.y)}}function W(t,o,e,r){const n=t.getPixelForValue(o);return e?n-o/e*r:n}function X(t,o,e){const r="vertical"===o?e.height-e.chartArea.bottom:e.width-e.chartArea.right;return Math.max(0,t+3-r)}function Y(t,o,e,r,n,i,a,s){if("vertical"===s){const s=e.getPixelForValue(S(t));return{height:i,width:Math.abs(e.getPixelForValue(S(t)+o)-s),x:s,y:W(r,T(t),n,a)}}const l=r.getPixelForValue(S(t));return{height:Math.abs(r.getPixelForValue(S(t)+o)-l),width:i,x:W(e,T(t),n,a),y:l}}function j(t,o){const e=i(t??10,o)??10;return"number"==typeof e?{after:e,before:e}:{after:e.after??10,before:e.before??10}}function A(t,o){const{backgroundColor:e,borderRadius:r=0,color:n,display:a,font:s,padding:l=4,position:h}=t.nodeLabels??{};return{backgroundColor:i(e,o),borderRadius:r,color:i(n,o)??t.color??"black",display:i(a,o)??!0,font:s,padding:l,position:i(h,o)??"auto"}}class V extends o.DatasetController{parseObjectData(t,o,e,r){const n=((t,o)=>{const{from:e="from",to:r="to",flow:n="flow"}=o;return t.map(({[e]:t,[r]:o,[n]:i})=>({flow:i,from:t,to:o}))})(o,this.options.parsing),{xScale:i,yScale:a}=t,s=[],l=h(n,this.options),c=this.options.orientation??"horizontal";this._nodes=l;const f=new Map;for(const t of l.values())f.set(t.key,j(this.options.nodePadding,t));const{maxX:d,maxY:u}=_(l,n,{height:"vertical"===c?this.chart.width:this.chart.height,modeX:this.options.modeX,nodePadding:f,priority:!!this.options.priority});if(this._maxX=d,this._maxY=u,!i||!a)return[];for(let t=0,o=n.length;t<o;++t){const o=n[t],e=l.get(o.from),r=l.get(o.to);if(!e||!r)continue;const h=S(e)+E(e.to,o.to,t),f=S(r)+E(r.from,o.from,t);s.push(O(e,r,h,f,o.flow,t,i,a,c))}return s.slice(e,e+r)}getMinMax(t){return{max:t===("vertical"===this.options.orientation?this._cachedMeta.yScale:this._cachedMeta.xScale)?this._maxX:this._maxY,min:0}}update(t){const{data:o}=this._cachedMeta;this.updateElements(o,0,o.length,t)}updateElements(t,o,e,r){const{xScale:n,yScale:i}=this._cachedMeta;if(!n||!i)return;const a=this.resolveDataElementOptions(o,r),s=this.getSharedOptions(a),{borderWidth:l,nodeWidth:h=10,orientation:c="horizontal"}=this.options,f=X(h,c,this.chart),d=l?l/2+.5:0;for(let a=o;a<o+e;a++){const o=this.getParsed(a);this.updateElement(t[a],a,{options:this.resolveDataElementOptions(a,r),progress:"reset"===r?0:1,...R(o,n,i,this._maxX,h,f,d,c)},r)}s&&this.updateSharedOptions(s,r,a)}_drawLabels(){const t=this.chart.ctx,r=this.options,i=this._nodes||new Map,a=n(r.size),l=r.labels,{borderWidth:h=1,nodeWidth:c=10,orientation:f="horizontal"}=r,d=X(c,f,this.chart),u=r.font??this.chart.options.font??o.Chart.defaults.font,{xScale:p,yScale:y}=this._cachedMeta;if(!p||!y)return;t.save();const g=this.chart.chartArea;for(const o of i.values()){const n=z(o,a),{height:i,width:x,x:m,y:b}=Y(o,n,p,y,this._maxX,c,d,f),w=l?.[o.key]??o.key,M=A(r,o);if(M.display){const o=e.toFont(M.font??u);s(t,w,{autoPosition:F(m,b,g,f),backgroundColor:M.backgroundColor,borderRadius:M.borderRadius,borderWidth:h,color:M.color,font:o,height:i,lineOffset:e.valueOrDefault(r.padding,o.lineHeight/2),padding:M.padding,position:M.position,width:x,x:m,y:b})}}t.restore()}_drawNodes(){const t=this.chart.ctx,o=this._nodes||new Map,{borderColor:e,borderWidth:r=0,nodeWidth:i=10,orientation:a="horizontal",size:s}=this.options,l=X(i,a,this.chart),h=n(s),{xScale:c,yScale:f}=this._cachedMeta;t.save(),e&&r&&(t.strokeStyle=e,t.lineWidth=r);for(const e of o.values()){if(t.fillStyle=e.color??"black",!c||!f)return;const o=Math[h](e.in||e.out,e.out||e.in),{height:n,width:s,x:d,y:u}=Y(e,o,c,f,this._maxX,i,l,a);r&&t.strokeRect(d,u,s,n),t.fillRect(d,u,s,n)}t.restore()}draw(){const t=this.chart.ctx,o=this.getMeta().data??[],e=[];for(let t=0,r=o.length;t<r;++t){const r=o[t];r.from&&r.to&&(r.from.color=r.options.colorFrom,r.to.color=r.options.colorTo,r.active&&e.push(r))}for(const t of e)t.from&&t.to&&(t.from.color=t.options.colorFrom,t.to.color=t.options.colorTo);this._drawNodes();for(let e=0,r=o.length;e<r;++e)o[e].draw(t);this._drawLabels()}constructor(...t){super(...t),this._nodes=new Map,this._maxX=0,this._maxY=0}}V.id="sankey",V.descriptors={_indexable:!1,_scriptable:t=>"nodePadding"!==t,nodeLabels:{_indexable:!1,_scriptable:!1}},V.defaults={animations:{colors:{properties:["colorFrom","colorTo"],type:"color"},numbers:{properties:["x","y","x2","y2","height","width"],type:"number"},progress:{delay:t=>"data"===t.type?500*t.parsed["vertical"===t.dataset.orientation?"y":"x"]+20*t.dataIndex:void 0,duration:t=>"data"===t.type?200*(t.parsed._custom["vertical"===t.dataset.orientation?"y":"x"]-t.parsed["vertical"===t.dataset.orientation?"y":"x"]):void 0,easing:"linear"}},borderColor:"black",borderWidth:1,color:"black",dataElementType:"flow",modeX:"edge",nodePadding:10,nodeWidth:10,orientation:"horizontal",transitions:{hide:{animations:{colors:{properties:["colorFrom","colorTo"],to:"transparent",type:"color"}}},resize:{animations:{progress:{delay:0,duration:0}}},show:{animations:{colors:{from:"transparent",properties:["colorFrom","colorTo"],type:"color"}}}}},V.overrides={datasets:{clip:!1,parsing:{flow:"flow",from:"from",to:"to"}},interaction:{intersect:!0,mode:"nearest"},layout:{padding:{bottom:3,left:3,right:13,top:3}},plugins:{legend:{display:!1},tooltip:{callbacks:{label(t){const o=t.parsed._custom;return`${o.from.key} -> ${o.to.key}: ${o.flow}`},title:()=>""}}},scales:{x:{bounds:"data",display:!1,min:0,offset:!1,type:"linear"},y:{bounds:"data",display:!1,min:0,offset:!1,reverse:!0,type:"linear"}}};const H=(t,o,e,r,n)=>"vertical"===n?o<r?{cp1:{x:t,y:o+(r-o)/3*2},cp2:{x:e,y:o+(r-o)/3}}:{cp1:{x:0,y:o-(o-r)/3},cp2:{x:0,y:r+(o-r)/3}}:t<e?{cp1:{x:t+(e-t)/3*2,y:o},cp2:{x:t+(e-t)/3,y:r}}:{cp1:{x:t-(t-e)/3,y:0},cp2:{x:e+(t-e)/3,y:0}},L=(t,o,e)=>({x:t.x+e*(o.x-t.x),y:t.y+e*(o.y-t.y)}),q=(t,o)=>e.color(t).alpha(o).rgbString(),D=(t,o)=>"string"==typeof t?q(t,o):t,$=t=>"string"==typeof t?e.getHoverColor(t):t;class G extends o.Element{draw(t){const{x:r,x2:n,y:i,y2:a,height:l,progress:h,width:c}=this,f=this.options.orientation,d=H(r,i,n,a,f),u={height:l,width:c,x:r,x2:n,y:i,y2:a};if(0===h)return;t.save(),h<1&&function(t,{height:o,width:e,x:r,x2:n,y:i,y2:a},s,l){t.beginPath(),"vertical"===l?t.rect(Math.min(r,n),i,Math.abs(n-r)+e+1,(a-i)*s+1):t.rect(r,Math.min(i,a),(n-r)*s+1,Math.abs(a-i)+o+1),t.clip()}(t,u,h,f),function(t,{x:o,x2:e,y:r,y2:n,options:i}){let a="black";null!==i.flowColor?a=i.flowColor:"from"===i.colorMode?a=D(i.colorFrom,i.alpha):"to"===i.colorMode?a=D(i.colorTo,i.alpha):"string"==typeof i.colorFrom&&"string"==typeof i.colorTo&&(a="vertical"===i.orientation?t.createLinearGradient(0,r,0,n):t.createLinearGradient(o,0,e,0),a.addColorStop(0,q(i.colorFrom,i.alpha)),a.addColorStop(1,q(i.colorTo,i.alpha))),t.fillStyle=a,t.strokeStyle=a,t.lineWidth=.5}(t,this),function(t,{height:o,width:e,x:r,x2:n,y:i,y2:a},{cp1:s,cp2:l},h){t.beginPath(),t.moveTo(r,i),t.bezierCurveTo(s.x,s.y,l.x,l.y,n,a),"vertical"===h?(t.lineTo(n+e,a),t.bezierCurveTo(l.x+e,l.y,s.x+e,s.y,r+e,i)):(t.lineTo(n,a+o),t.bezierCurveTo(l.x,l.y+o,s.x,s.y+o,r,i+o)),t.lineTo(r,i),t.stroke(),t.closePath(),t.fill()}(t,u,d,f);const p=this.options.flowLabels;if(p.display){const r=e.toFont(p.font??o.Chart.defaults.font),n=function({height:t,width:o,x:e,x2:r,y:n,y2:i},a){return"vertical"===a?{height:i-n,width:Math.abs(r-e)+o,x:Math.min(e,r),y:n}:{height:Math.abs(i-n)+t,width:r-e,x:e,y:Math.min(n,i)}}(u,f);s(t,`${this.flow}`,{autoPosition:"center",backgroundColor:p.backgroundColor,borderRadius:p.borderRadius,borderWidth:0,color:p.color,font:r,height:n.height,lineOffset:r.lineHeight/2,padding:p.padding,position:p.position,width:n.width,x:n.x,y:n.y})}t.restore()}inRange(t,o,e){const{x:r,y:n,x2:i,y2:a,height:s,width:l}=this.getProps(["x","y","x2","y2","height","width"],e),h="vertical"===this.options.orientation;if(h?o<n||o>a:t<r||t>i)return!1;const{cp1:c,cp2:f}=H(r,n,i,a,this.options.orientation),d=h?(o-n)/(a-n):(t-r)/(i-r),u={x:i,y:a},p=L({x:r,y:n},c,d),y=L(c,f,d),g=L(f,u,d),x=L(p,y,d),m=L(y,g,d),b=L(x,m,d);return h?t>=b.x&&t<=b.x+l:o>=b.y&&o<=b.y+s}inXRange(t,o){const{x:e,x2:r,width:n}=this.getProps(["x","x2","width"],o),i=Math.min(e,r),a=Math.max(e,r)+("vertical"===this.options.orientation?n:0);return t>=i&&t<=a}inYRange(t,o){const{y:e,y2:r,height:n}=this.getProps(["y","y2","height"],o),i=Math.min(e,r),a=Math.max(e,r)+("vertical"===this.options.orientation?0:n);return t>=i&&t<=a}getCenterPoint(t){const{x:o,y:e,x2:r,y2:n,height:i,width:a}=this.getProps(["x","y","x2","y2","height","width"],t),s="vertical"===this.options.orientation;return{x:(o+r+(s?a:0))/2,y:(e+n+(s?0:i))/2}}tooltipPosition(t=!1){return this.getCenterPoint(t)}getRange(t){const o="vertical"===this.options.orientation;return"x"===t?o?this.width/2:0:o?0:this.height/2}constructor(t){super(),this.flow=0,this.x2=0,this.y2=0,this.width=0,this.height=0,this.progress=1,t&&Object.assign(this,t)}}G.id="flow",G.defaults={alpha:.5,colorFrom:"red",colorMode:"gradient",colorTo:"green",flowColor:null,flowLabels:{borderRadius:0,color:"black",display:!1,padding:4,position:"center"},hoverColorFrom:(t,o)=>$(o.colorFrom),hoverColorTo:(t,o)=>$(o.colorTo),orientation:"horizontal"},G.descriptors={_scriptable:!0,flowLabels:{_scriptable:!0}},o.Chart.register(V,G),t.Flow=G,t.SankeyController=V});
|
package/dist/controller.d.cts
CHANGED
|
@@ -6,7 +6,7 @@ export default class SankeyController extends DatasetController {
|
|
|
6
6
|
static readonly id = "sankey";
|
|
7
7
|
static readonly descriptors: {
|
|
8
8
|
_indexable: boolean;
|
|
9
|
-
_scriptable: boolean;
|
|
9
|
+
_scriptable: (name: string) => boolean;
|
|
10
10
|
nodeLabels: {
|
|
11
11
|
_indexable: boolean;
|
|
12
12
|
_scriptable: boolean;
|
package/dist/controller.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export default class SankeyController extends DatasetController {
|
|
|
6
6
|
static readonly id = "sankey";
|
|
7
7
|
static readonly descriptors: {
|
|
8
8
|
_indexable: boolean;
|
|
9
|
-
_scriptable: boolean;
|
|
9
|
+
_scriptable: (name: string) => boolean;
|
|
10
10
|
nodeLabels: {
|
|
11
11
|
_indexable: boolean;
|
|
12
12
|
_scriptable: boolean;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import Sankey from './controller.cjs';
|
|
2
2
|
import Flow from './flow.cjs';
|
|
3
|
-
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.cjs';
|
|
3
|
+
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeGap, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyNodeOption, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.cjs';
|
|
4
4
|
export { Flow, Sankey as SankeyController };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import Sankey from './controller.js';
|
|
2
2
|
import Flow from './flow.js';
|
|
3
|
-
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.js';
|
|
3
|
+
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeGap, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyNodeOption, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.js';
|
|
4
4
|
export { Flow, Sankey as SankeyController };
|
package/dist/index.esm.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.cjs';
|
|
1
|
+
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeGap, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyNodeOption, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.cjs';
|
|
2
2
|
export { default as SankeyController } from './controller.cjs';
|
|
3
3
|
export { default as Flow } from './flow.cjs';
|
package/dist/index.esm.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.js';
|
|
1
|
+
export type { FlowConfig, FlowOptions, FlowProps, SankeyControllerDatasetFlowLabelsOptions, SankeyControllerDatasetNodeLabelsOptions, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyLabelPosition, SankeyNodeGap, SankeyNodeLabelOption, SankeyNodeLabelPosition, SankeyNodeOption, SankeyOrientation, SankeyParsedData, SankeyParsingOptions, SankeyScriptableContext, } from './types.js';
|
|
2
2
|
export { default as SankeyController } from './controller.js';
|
|
3
3
|
export { default as Flow } from './flow.js';
|
package/dist/labels.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { CanvasFontSpec, Color } from 'chart.js' with { 'resolution-mode': 'import' };
|
|
2
|
-
import type { SankeyLabelPosition, SankeyNode,
|
|
3
|
-
type ResolvableNodeLabelValue = boolean | Color | SankeyLabelPosition;
|
|
2
|
+
import type { SankeyLabelPosition, SankeyNode, SankeyNodeOption } from './types.cjs';
|
|
4
3
|
type ResolvedLabelPosition = Exclude<SankeyLabelPosition, 'auto'>;
|
|
5
4
|
export interface DrawLabelOptions {
|
|
6
5
|
autoPosition: ResolvedLabelPosition;
|
|
@@ -17,6 +16,6 @@ export interface DrawLabelOptions {
|
|
|
17
16
|
x: number;
|
|
18
17
|
y: number;
|
|
19
18
|
}
|
|
20
|
-
export declare function
|
|
19
|
+
export declare function resolveNodeOption<T>(option: SankeyNodeOption<T> | undefined, node: SankeyNode): T | undefined;
|
|
21
20
|
export declare function drawLabel(ctx: CanvasRenderingContext2D, label: string, options: DrawLabelOptions): void;
|
|
22
21
|
export {};
|
package/dist/labels.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { CanvasFontSpec, Color } from 'chart.js';
|
|
2
|
-
import type { SankeyLabelPosition, SankeyNode,
|
|
3
|
-
type ResolvableNodeLabelValue = boolean | Color | SankeyLabelPosition;
|
|
2
|
+
import type { SankeyLabelPosition, SankeyNode, SankeyNodeOption } from './types.js';
|
|
4
3
|
type ResolvedLabelPosition = Exclude<SankeyLabelPosition, 'auto'>;
|
|
5
4
|
export interface DrawLabelOptions {
|
|
6
5
|
autoPosition: ResolvedLabelPosition;
|
|
@@ -17,6 +16,6 @@ export interface DrawLabelOptions {
|
|
|
17
16
|
x: number;
|
|
18
17
|
y: number;
|
|
19
18
|
}
|
|
20
|
-
export declare function
|
|
19
|
+
export declare function resolveNodeOption<T>(option: SankeyNodeOption<T> | undefined, node: SankeyNode): T | undefined;
|
|
21
20
|
export declare function drawLabel(ctx: CanvasRenderingContext2D, label: string, options: DrawLabelOptions): void;
|
|
22
21
|
export {};
|
package/dist/lib/layout.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FromToElement, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyNode } from '../types.js';
|
|
1
|
+
import type { FromToElement, SankeyControllerDatasetOptions, SankeyDataPoint, SankeyNode, SankeyNodeGap } from '../types.js';
|
|
2
2
|
export type SankeyMode = 'edge' | 'even';
|
|
3
3
|
/**
|
|
4
4
|
* Get all keys the input nodes flow to, including keys of the input nodes
|
|
@@ -15,18 +15,20 @@ export declare function nodeCount(list: Array<FromToElement>, prop: FlowDirectio
|
|
|
15
15
|
export declare const returnsToNearerColumn: (current: SankeyNode, next?: SankeyNode) => boolean;
|
|
16
16
|
export declare function calculateY(nodeArray: SankeyNode[], maxX: number): number;
|
|
17
17
|
export declare function calculateYUsingPriority(nodeArray: SankeyNode[], maxX: number): number;
|
|
18
|
+
type PaddableNode = Pick<SankeyNode, 'in' | 'key' | 'out' | 'size' | 'x' | 'y'>;
|
|
19
|
+
type NodeGap = Required<SankeyNodeGap>;
|
|
18
20
|
/**
|
|
19
21
|
* @return {number} maxY
|
|
20
22
|
*/
|
|
21
|
-
export declare function addPadding(nodeArray:
|
|
23
|
+
export declare function addPadding(nodeArray: PaddableNode[], gaps: Map<string, NodeGap>): number;
|
|
22
24
|
export declare function sortFlows(nodeArray: SankeyNode[]): void;
|
|
23
25
|
interface LayoutOptions {
|
|
24
26
|
/** use node priority when sorting nodes vertically */
|
|
25
27
|
priority: boolean;
|
|
26
28
|
/** chart height in CSS pixels */
|
|
27
29
|
height: number;
|
|
28
|
-
/** vertical
|
|
29
|
-
nodePadding:
|
|
30
|
+
/** vertical before/after gap per node, in CSS pixels */
|
|
31
|
+
nodePadding: Map<string, NodeGap>;
|
|
30
32
|
/** layout mode in x-direction */
|
|
31
33
|
modeX: SankeyControllerDatasetOptions['modeX'];
|
|
32
34
|
}
|
package/dist/types.d.cts
CHANGED
|
@@ -12,15 +12,21 @@ export type SankeyScriptableContext = ScriptableContext<'sankey'> & {
|
|
|
12
12
|
export type SankeyLabelPosition = 'auto' | 'bottom' | 'center' | 'left' | 'right' | 'top';
|
|
13
13
|
export type SankeyNodeLabelPosition = SankeyLabelPosition;
|
|
14
14
|
export type SankeyOrientation = 'horizontal' | 'vertical';
|
|
15
|
-
export type
|
|
15
|
+
export type SankeyNodeOption<T> = T | Record<string, T> | ((node: SankeyNode) => T | undefined);
|
|
16
|
+
/** @deprecated use SankeyNodeOption */
|
|
17
|
+
export type SankeyNodeLabelOption<T> = SankeyNodeOption<T>;
|
|
18
|
+
export interface SankeyNodeGap {
|
|
19
|
+
after?: number;
|
|
20
|
+
before?: number;
|
|
21
|
+
}
|
|
16
22
|
export interface SankeyControllerDatasetNodeLabelsOptions {
|
|
17
|
-
backgroundColor?:
|
|
23
|
+
backgroundColor?: SankeyNodeOption<Color>;
|
|
18
24
|
borderRadius?: number;
|
|
19
|
-
color?:
|
|
20
|
-
display?:
|
|
25
|
+
color?: SankeyNodeOption<Color>;
|
|
26
|
+
display?: SankeyNodeOption<boolean>;
|
|
21
27
|
font?: Partial<FontSpec>;
|
|
22
28
|
padding?: number;
|
|
23
|
-
position?:
|
|
29
|
+
position?: SankeyNodeOption<SankeyLabelPosition>;
|
|
24
30
|
}
|
|
25
31
|
export interface SankeyControllerDatasetFlowLabelsOptions {
|
|
26
32
|
backgroundColor?: Scriptable<Color, SankeyScriptableContext>;
|
|
@@ -55,7 +61,7 @@ export interface SankeyControllerDatasetOptions extends Omit<ControllerDatasetOp
|
|
|
55
61
|
flowColor?: ScriptableAndArray<Color, SankeyScriptableContext>;
|
|
56
62
|
modeX?: 'edge' | 'even';
|
|
57
63
|
nodeLabels?: SankeyControllerDatasetNodeLabelsOptions;
|
|
58
|
-
nodePadding?: number
|
|
64
|
+
nodePadding?: SankeyNodeOption<number | SankeyNodeGap>;
|
|
59
65
|
nodeWidth?: number;
|
|
60
66
|
orientation?: SankeyOrientation;
|
|
61
67
|
padding?: number;
|
package/dist/types.d.ts
CHANGED
|
@@ -11,15 +11,21 @@ export type SankeyScriptableContext = ScriptableContext<'sankey'> & {
|
|
|
11
11
|
export type SankeyLabelPosition = 'auto' | 'bottom' | 'center' | 'left' | 'right' | 'top';
|
|
12
12
|
export type SankeyNodeLabelPosition = SankeyLabelPosition;
|
|
13
13
|
export type SankeyOrientation = 'horizontal' | 'vertical';
|
|
14
|
-
export type
|
|
14
|
+
export type SankeyNodeOption<T> = T | Record<string, T> | ((node: SankeyNode) => T | undefined);
|
|
15
|
+
/** @deprecated use SankeyNodeOption */
|
|
16
|
+
export type SankeyNodeLabelOption<T> = SankeyNodeOption<T>;
|
|
17
|
+
export interface SankeyNodeGap {
|
|
18
|
+
after?: number;
|
|
19
|
+
before?: number;
|
|
20
|
+
}
|
|
15
21
|
export interface SankeyControllerDatasetNodeLabelsOptions {
|
|
16
|
-
backgroundColor?:
|
|
22
|
+
backgroundColor?: SankeyNodeOption<Color>;
|
|
17
23
|
borderRadius?: number;
|
|
18
|
-
color?:
|
|
19
|
-
display?:
|
|
24
|
+
color?: SankeyNodeOption<Color>;
|
|
25
|
+
display?: SankeyNodeOption<boolean>;
|
|
20
26
|
font?: Partial<FontSpec>;
|
|
21
27
|
padding?: number;
|
|
22
|
-
position?:
|
|
28
|
+
position?: SankeyNodeOption<SankeyLabelPosition>;
|
|
23
29
|
}
|
|
24
30
|
export interface SankeyControllerDatasetFlowLabelsOptions {
|
|
25
31
|
backgroundColor?: Scriptable<Color, SankeyScriptableContext>;
|
|
@@ -54,7 +60,7 @@ export interface SankeyControllerDatasetOptions extends Omit<ControllerDatasetOp
|
|
|
54
60
|
flowColor?: ScriptableAndArray<Color, SankeyScriptableContext>;
|
|
55
61
|
modeX?: 'edge' | 'even';
|
|
56
62
|
nodeLabels?: SankeyControllerDatasetNodeLabelsOptions;
|
|
57
|
-
nodePadding?: number
|
|
63
|
+
nodePadding?: SankeyNodeOption<number | SankeyNodeGap>;
|
|
58
64
|
nodeWidth?: number;
|
|
59
65
|
orientation?: SankeyOrientation;
|
|
60
66
|
padding?: number;
|
package/package.json
CHANGED