@progress/kendo-charts 2.3.0-dev.202402161236 → 2.3.0-dev.202403071434
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/cdn/js/kendo-charts.js +1 -1
- package/dist/cdn/main.js +1 -1
- package/dist/es/sankey/calculation.js +252 -29
- package/dist/es/sankey/link.js +4 -4
- package/dist/es/sankey/sankey.js +121 -49
- package/dist/es/sankey/title.js +0 -1
- package/dist/es2015/sankey/calculation.js +235 -27
- package/dist/es2015/sankey/link.js +3 -3
- package/dist/es2015/sankey/sankey.js +103 -30
- package/dist/es2015/sankey/title.js +0 -1
- package/dist/npm/main.js +374 -81
- package/dist/npm/sankey.d.ts +30 -0
- package/dist/systemjs/kendo-charts.js +1 -1
- package/package.json +2 -1
|
@@ -3,24 +3,40 @@ import { deepExtend } from '../common';
|
|
|
3
3
|
var max = function (array, mapFn) { return Math.max.apply(null, array.map(mapFn)); };
|
|
4
4
|
var min = function (array, mapFn) { return Math.min.apply(null, array.map(mapFn)); };
|
|
5
5
|
var sum = function (array, mapFn) { return array.map(mapFn).reduce(function (acc, curr) { return (acc + curr); }, 0); };
|
|
6
|
-
var sortAsc = function (a, b) { return a.y0 - b.y0; };
|
|
6
|
+
var sortAsc = function (a, b) { return (a.y0 === b.y0 ? a.index - b.index : a.y0 + a.y1 - b.y0 - b.y1); };
|
|
7
7
|
var sortSource = function (a, b) { return sortAsc(a.source, b.source); };
|
|
8
8
|
var sortTarget = function (a, b) { return sortAsc(a.target, b.target); };
|
|
9
9
|
var value = function (node) { return node.value; };
|
|
10
10
|
|
|
11
11
|
function sortLinks(nodes) {
|
|
12
12
|
nodes.forEach(function (node) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
node.targetLinks.forEach(function (link) {
|
|
14
|
+
link.source.sourceLinks.sort(sortTarget);
|
|
15
|
+
});
|
|
16
|
+
node.sourceLinks.forEach(function (link) {
|
|
17
|
+
link.target.targetLinks.sort(sortSource);
|
|
18
|
+
});
|
|
17
19
|
});
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
var calcLayer = function (node, maxDepth) {
|
|
23
|
+
if (node.align === 'left') {
|
|
24
|
+
return node.depth;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (node.align === 'right') {
|
|
28
|
+
return maxDepth - node.height;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return node.sourceLinks.length ? node.depth : maxDepth;
|
|
32
|
+
};
|
|
33
|
+
|
|
20
34
|
var Sankey = function Sankey(options) {
|
|
21
|
-
var
|
|
35
|
+
var ref = options.nodesOptions;
|
|
36
|
+
var offset = ref.offset; if ( offset === void 0 ) offset = {};
|
|
37
|
+
var align = ref.align;
|
|
22
38
|
this.data = {
|
|
23
|
-
nodes: options.nodes.map(function (node) { return deepExtend({}, { offset: offset }, node); }),
|
|
39
|
+
nodes: options.nodes.map(function (node) { return deepExtend({}, { offset: offset, align: align }, node); }),
|
|
24
40
|
links: options.links.map(function (link) { return deepExtend({}, link); })
|
|
25
41
|
};
|
|
26
42
|
|
|
@@ -30,6 +46,10 @@ var Sankey = function Sankey(options) {
|
|
|
30
46
|
this.offsetY = options.offsetY || 0;
|
|
31
47
|
this.nodeWidth = options.nodesOptions.width;
|
|
32
48
|
this.nodePadding = options.nodesOptions.padding;
|
|
49
|
+
this.reverse = options.reverse;
|
|
50
|
+
this.targetColumnIndex = options.targetColumnIndex;
|
|
51
|
+
this.loops = options.loops;
|
|
52
|
+
this.autoLayout = options.autoLayout;
|
|
33
53
|
};
|
|
34
54
|
|
|
35
55
|
Sankey.prototype.calculate = function calculate () {
|
|
@@ -39,19 +59,21 @@ Sankey.prototype.calculate = function calculate () {
|
|
|
39
59
|
this.connectLinksToNodes(nodes, links);
|
|
40
60
|
this.calculateNodeValues(nodes);
|
|
41
61
|
this.calculateNodeDepths(nodes);
|
|
62
|
+
this.calculateNodeHeights(nodes);
|
|
42
63
|
|
|
43
64
|
var columns = this.calculateNodeColumns(nodes);
|
|
44
65
|
this.calculateNodeBreadths(columns);
|
|
45
66
|
this.applyNodesOffset(nodes);
|
|
46
67
|
this.calculateLinkBreadths(nodes);
|
|
47
68
|
|
|
48
|
-
return this.data;
|
|
69
|
+
return Object.assign({}, this.data, {columns: columns});
|
|
49
70
|
};
|
|
50
71
|
|
|
51
72
|
Sankey.prototype.connectLinksToNodes = function connectLinksToNodes (nodes, links) {
|
|
52
73
|
var nodesMap = new Map();
|
|
53
74
|
|
|
54
|
-
nodes.forEach(function (node) {
|
|
75
|
+
nodes.forEach(function (node, i) {
|
|
76
|
+
node.index = i;
|
|
55
77
|
node.sourceLinks = [];
|
|
56
78
|
node.targetLinks = [];
|
|
57
79
|
node.id = node.id !== undefined ? node.id : node.label.text;
|
|
@@ -95,6 +117,24 @@ Sankey.prototype.calculateNodeDepths = function calculateNodeDepths (nodes) {
|
|
|
95
117
|
}
|
|
96
118
|
};
|
|
97
119
|
|
|
120
|
+
Sankey.prototype.calculateNodeHeights = function calculateNodeHeights (nodes) {
|
|
121
|
+
var current = new Set(nodes);
|
|
122
|
+
var next = new Set;
|
|
123
|
+
var x = 0;
|
|
124
|
+
var eachNode = function (node) {
|
|
125
|
+
node.height = x;
|
|
126
|
+
node.targetLinks.forEach(function (link) {
|
|
127
|
+
next.add(link.source);
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
while (current.size) {
|
|
131
|
+
current.forEach(eachNode);
|
|
132
|
+
x++;
|
|
133
|
+
current = next;
|
|
134
|
+
next = new Set;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
98
138
|
Sankey.prototype.calculateNodeColumns = function calculateNodeColumns (nodes) {
|
|
99
139
|
var this$1 = this;
|
|
100
140
|
|
|
@@ -103,11 +143,12 @@ Sankey.prototype.calculateNodeColumns = function calculateNodeColumns (nodes) {
|
|
|
103
143
|
var columns = new Array(maxDepth + 1);
|
|
104
144
|
for (var i = 0; i < nodes.length; i++) {
|
|
105
145
|
var node = nodes[i];
|
|
106
|
-
var
|
|
107
|
-
node.x0 = this$1.offsetX +
|
|
146
|
+
var layer = Math.max(0, Math.min(maxDepth, calcLayer(node, maxDepth)));
|
|
147
|
+
node.x0 = this$1.offsetX + layer * columnWidth;
|
|
108
148
|
node.x1 = node.x0 + this$1.nodeWidth;
|
|
109
|
-
|
|
110
|
-
columns[
|
|
149
|
+
node.layer = layer;
|
|
150
|
+
columns[layer] = columns[layer] || [];
|
|
151
|
+
columns[layer].push(node);
|
|
111
152
|
}
|
|
112
153
|
|
|
113
154
|
return columns;
|
|
@@ -118,31 +159,39 @@ Sankey.prototype.calculateNodeBreadths = function calculateNodeBreadths (columns
|
|
|
118
159
|
|
|
119
160
|
var kSize = min(columns, function (c) { return (this$1.height - this$1.offsetY - (c.length - 1) * this$1.nodePadding) / sum(c, value); });
|
|
120
161
|
|
|
121
|
-
|
|
122
|
-
var nodes = columns[c];
|
|
162
|
+
columns.forEach(function (nodes) {
|
|
123
163
|
var y = this$1.offsetY;
|
|
124
|
-
|
|
125
|
-
var node = nodes[i];
|
|
164
|
+
nodes.forEach(function (node) {
|
|
126
165
|
node.y0 = y;
|
|
127
166
|
node.y1 = y + node.value * kSize;
|
|
128
167
|
y = node.y1 + this$1.nodePadding;
|
|
129
|
-
|
|
130
|
-
var link = node.sourceLinks[l];
|
|
168
|
+
node.sourceLinks.forEach(function (link) {
|
|
131
169
|
link.width = link.value * kSize;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
170
|
+
});
|
|
171
|
+
});
|
|
135
172
|
y = (this$1.height - y + this$1.nodePadding) / (nodes.length + 1);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
node
|
|
139
|
-
|
|
173
|
+
nodes.forEach(function (node, i) {
|
|
174
|
+
node.y0 += y * (i + 1);
|
|
175
|
+
node.y1 += y * (i + 1);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (this.autoLayout !== false) {
|
|
180
|
+
var loops = this.loops !== undefined ? this.loops : columns.length - 1;
|
|
181
|
+
var targetColumnIndex = this.targetColumnIndex || 1;
|
|
182
|
+
|
|
183
|
+
for (var i = 0; i < loops; i++) {
|
|
184
|
+
if (!this$1.reverse) {
|
|
185
|
+
this$1.uncurlLinksToLeft(columns, targetColumnIndex);
|
|
186
|
+
this$1.uncurlLinksToRight(columns, targetColumnIndex);
|
|
187
|
+
} else {
|
|
188
|
+
this$1.uncurlLinksToRight(columns, targetColumnIndex);
|
|
189
|
+
this$1.uncurlLinksToLeft(columns, targetColumnIndex);
|
|
190
|
+
}
|
|
140
191
|
}
|
|
141
192
|
}
|
|
142
193
|
|
|
143
|
-
|
|
144
|
-
sortLinks(columns[c$1]);
|
|
145
|
-
}
|
|
194
|
+
columns.forEach(sortLinks);
|
|
146
195
|
};
|
|
147
196
|
|
|
148
197
|
Sankey.prototype.applyNodesOffset = function applyNodesOffset (nodes) {
|
|
@@ -163,14 +212,188 @@ Sankey.prototype.calculateLinkBreadths = function calculateLinkBreadths (nodes)
|
|
|
163
212
|
var y = node.y0;
|
|
164
213
|
var y1 = y;
|
|
165
214
|
sourceLinks.forEach(function (link) {
|
|
215
|
+
link.x0 = link.source.x1;
|
|
166
216
|
link.y0 = y + link.width / 2;
|
|
167
217
|
y += link.width;
|
|
168
218
|
});
|
|
169
219
|
targetLinks.forEach(function (link) {
|
|
220
|
+
link.x1 = link.target.x0;
|
|
170
221
|
link.y1 = y1 + link.width / 2;
|
|
171
222
|
y1 += link.width;
|
|
172
223
|
});
|
|
173
224
|
});
|
|
174
225
|
};
|
|
175
226
|
|
|
227
|
+
Sankey.prototype.uncurlLinksToRight = function uncurlLinksToRight (columns, targetColumnIndex) {
|
|
228
|
+
var this$1 = this;
|
|
229
|
+
|
|
230
|
+
var n = columns.length;
|
|
231
|
+
for (var i = targetColumnIndex; i < n; i++) {
|
|
232
|
+
var column = columns[i];
|
|
233
|
+
column.forEach(function (target) {
|
|
234
|
+
var y = 0;
|
|
235
|
+
var sum = 0;
|
|
236
|
+
target.targetLinks.forEach(function (link) {
|
|
237
|
+
var kValue = link.value * (target.layer - link.source.layer);
|
|
238
|
+
y += this$1.targetTopPos(link.source, target) * kValue;
|
|
239
|
+
sum += kValue;
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
var dy = y === 0 ? 0 : (y / sum - target.y0);
|
|
243
|
+
target.y0 += dy;
|
|
244
|
+
target.y1 += dy;
|
|
245
|
+
sortLinks([target]);
|
|
246
|
+
});
|
|
247
|
+
column.sort(sortAsc);
|
|
248
|
+
this$1.arrangeNodesVertically(column);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
Sankey.prototype.uncurlLinksToLeft = function uncurlLinksToLeft (columns, targetColumnIndex) {
|
|
253
|
+
var this$1 = this;
|
|
254
|
+
|
|
255
|
+
var l = columns.length;
|
|
256
|
+
var startIndex = l - 1 - targetColumnIndex;
|
|
257
|
+
for (var i = startIndex; i >= 0; i--) {
|
|
258
|
+
var column = columns[i];
|
|
259
|
+
var loop = function ( j ) {
|
|
260
|
+
var source = column[j];
|
|
261
|
+
var y = 0;
|
|
262
|
+
var sum = 0;
|
|
263
|
+
source.sourceLinks.forEach(function (link) {
|
|
264
|
+
var kValue = link.value * (link.target.layer - source.layer);
|
|
265
|
+
y += this$1.sourceTopPos(source, link.target) * kValue;
|
|
266
|
+
sum += kValue;
|
|
267
|
+
});
|
|
268
|
+
var dy = y === 0 ? 0 : (y / sum - source.y0);
|
|
269
|
+
source.y0 += dy;
|
|
270
|
+
source.y1 += dy;
|
|
271
|
+
sortLinks([source]);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
for (var j = 0; j < column.length; j++) loop( j );
|
|
275
|
+
|
|
276
|
+
column.sort(sortAsc);
|
|
277
|
+
this$1.arrangeNodesVertically(column);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
Sankey.prototype.arrangeNodesVertically = function arrangeNodesVertically (nodes) {
|
|
282
|
+
var startIndex = 0;
|
|
283
|
+
var endIndex = nodes.length - 1;
|
|
284
|
+
|
|
285
|
+
this.arrangeUp(nodes, this.height, endIndex);
|
|
286
|
+
this.arrangeDown(nodes, this.offsetY, startIndex);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
Sankey.prototype.arrangeDown = function arrangeDown (nodes, yPos, index) {
|
|
290
|
+
var this$1 = this;
|
|
291
|
+
|
|
292
|
+
var currentY = yPos;
|
|
293
|
+
|
|
294
|
+
for (var i = index; i < nodes.length; i++) {
|
|
295
|
+
var node = nodes[i];
|
|
296
|
+
var dy = Math.max(0, currentY - node.y0);
|
|
297
|
+
node.y0 += dy;
|
|
298
|
+
node.y1 += dy;
|
|
299
|
+
currentY = node.y1 + this$1.nodePadding;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
Sankey.prototype.arrangeUp = function arrangeUp (nodes, yPos, index) {
|
|
304
|
+
var this$1 = this;
|
|
305
|
+
|
|
306
|
+
var currentY = yPos;
|
|
307
|
+
for (var i = index; i >= 0; --i) {
|
|
308
|
+
var node = nodes[i];
|
|
309
|
+
var dy = Math.max(0, node.y1 - currentY);
|
|
310
|
+
node.y0 -= dy;
|
|
311
|
+
node.y1 -= dy;
|
|
312
|
+
currentY = node.y0 - this$1.nodePadding;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
Sankey.prototype.sourceTopPos = function sourceTopPos (source, target) {
|
|
317
|
+
var this$1 = this;
|
|
318
|
+
|
|
319
|
+
var y = target.y0 - ((target.targetLinks.length - 1) * this.nodePadding) / 2;
|
|
320
|
+
for (var i = 0; i < target.targetLinks.length; i++) {
|
|
321
|
+
var link = target.targetLinks[i];
|
|
322
|
+
if (link.source === source) {
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
y += link.width + this$1.nodePadding;
|
|
326
|
+
}
|
|
327
|
+
for (var i$1 = 0; i$1 < source.sourceLinks.length; i$1++) {
|
|
328
|
+
var link$1 = source.sourceLinks[i$1];
|
|
329
|
+
if (link$1.target === target) {
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
y -= link$1.width;
|
|
333
|
+
}
|
|
334
|
+
return y;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
Sankey.prototype.targetTopPos = function targetTopPos (source, target) {
|
|
338
|
+
var this$1 = this;
|
|
339
|
+
|
|
340
|
+
var y = source.y0 - ((source.sourceLinks.length - 1) * this.nodePadding) / 2;
|
|
341
|
+
for (var i = 0; i < source.sourceLinks.length; i++) {
|
|
342
|
+
var link = source.sourceLinks[i];
|
|
343
|
+
if (link.target === target) {
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
y += link.width + this$1.nodePadding;
|
|
347
|
+
}
|
|
348
|
+
for (var i$1 = 0; i$1 < target.targetLinks.length; i$1++) {
|
|
349
|
+
var link$1 = target.targetLinks[i$1];
|
|
350
|
+
if (link$1.source === source) {
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
y -= link$1.width;
|
|
354
|
+
}
|
|
355
|
+
return y;
|
|
356
|
+
};
|
|
357
|
+
|
|
176
358
|
export var calculateSankey = function (options) { return new Sankey(options).calculate(); };
|
|
359
|
+
|
|
360
|
+
export var crossesValue = function (links) {
|
|
361
|
+
var value = 0;
|
|
362
|
+
var linksLength = links.length;
|
|
363
|
+
|
|
364
|
+
for (var i = 0; i < linksLength; i++) {
|
|
365
|
+
var link = links[i];
|
|
366
|
+
|
|
367
|
+
for (var lNext = i + 1; lNext < linksLength; lNext++) {
|
|
368
|
+
var nextLink = links[lNext];
|
|
369
|
+
|
|
370
|
+
if (intersect(link, nextLink)) {
|
|
371
|
+
value += Math.min(link.value, nextLink.value);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return value;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
function rotationDirection(p1x, p1y, p2x, p2y, p3x, p3y) {
|
|
380
|
+
var expression1 = (p3y - p1y) * (p2x - p1x);
|
|
381
|
+
var expression2 = (p2y - p1y) * (p3x - p1x);
|
|
382
|
+
|
|
383
|
+
if (expression1 > expression2) {
|
|
384
|
+
return 1;
|
|
385
|
+
} else if (expression1 === expression2) {
|
|
386
|
+
return 0;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return -1;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function intersect(link1, link2) {
|
|
393
|
+
var f1 = rotationDirection(link1.x0, link1.y0, link1.x1, link1.y1, link2.x1, link2.y1);
|
|
394
|
+
var f2 = rotationDirection(link1.x0, link1.y0, link1.x1, link1.y1, link2.x0, link2.y0);
|
|
395
|
+
var f3 = rotationDirection(link1.x0, link1.y0, link2.x0, link2.y0, link2.x1, link2.y1);
|
|
396
|
+
var f4 = rotationDirection(link1.x1, link1.y1, link2.x0, link2.y0, link2.x1, link2.y1);
|
|
397
|
+
|
|
398
|
+
return f1 !== f2 && f3 !== f4;
|
|
399
|
+
}
|
package/dist/es/sankey/link.js
CHANGED
|
@@ -14,14 +14,14 @@ export var Link = (function (SankeyElement) {
|
|
|
14
14
|
|
|
15
15
|
Link.prototype.getElement = function getElement () {
|
|
16
16
|
var link = this.options.link;
|
|
17
|
-
var
|
|
18
|
-
var
|
|
17
|
+
var x0 = link.x0;
|
|
18
|
+
var x1 = link.x1;
|
|
19
19
|
var y0 = link.y0;
|
|
20
20
|
var y1 = link.y1;
|
|
21
|
-
var xC = (
|
|
21
|
+
var xC = (x0 + x1) / 2;
|
|
22
22
|
|
|
23
23
|
return new drawing.Path(this.visualOptions())
|
|
24
|
-
.moveTo(
|
|
24
|
+
.moveTo(x0, y0).curveTo([xC, y0], [xC, y1], [x1, y1]);
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
Link.prototype.visualOptions = function visualOptions () {
|
package/dist/es/sankey/sankey.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { drawing } from '@progress/kendo-drawing';
|
|
1
|
+
import { geometry, drawing } from '@progress/kendo-drawing';
|
|
2
2
|
import { deepExtend, addClass, setDefaultOptions } from '../common';
|
|
3
|
-
import { calculateSankey } from './calculation';
|
|
3
|
+
import { calculateSankey, crossesValue } from './calculation';
|
|
4
4
|
import { Node, resolveNodeOptions } from './node';
|
|
5
5
|
import { Link, resolveLinkOptions } from './link';
|
|
6
6
|
import { Label, resolveLabelOptions } from './label';
|
|
@@ -10,6 +10,7 @@ import Box from '../core/box';
|
|
|
10
10
|
import rectToBox from '../core/utils/rect-to-box';
|
|
11
11
|
import { Observable } from '../common/observable';
|
|
12
12
|
import { Legend } from './legend';
|
|
13
|
+
import { defined } from '../drawing-utils';
|
|
13
14
|
|
|
14
15
|
var LINK = 'link';
|
|
15
16
|
var NODE = 'node';
|
|
@@ -67,6 +68,7 @@ export var Sankey = (function (Observable) {
|
|
|
67
68
|
}
|
|
68
69
|
this$1.size = { width: width, height: height };
|
|
69
70
|
this$1.surface.setSize(this$1.size);
|
|
71
|
+
this$1.resize = true;
|
|
70
72
|
this$1._redraw();
|
|
71
73
|
});
|
|
72
74
|
});
|
|
@@ -257,17 +259,17 @@ export var Sankey = (function (Observable) {
|
|
|
257
259
|
return legendVisual.chartElement.box;
|
|
258
260
|
};
|
|
259
261
|
|
|
260
|
-
Sankey.prototype.calculateSankey = function calculateSankey$1 (
|
|
261
|
-
var
|
|
262
|
-
var
|
|
263
|
-
var
|
|
264
|
-
var
|
|
265
|
-
var
|
|
266
|
-
var
|
|
267
|
-
var
|
|
268
|
-
var
|
|
269
|
-
|
|
270
|
-
var sankeyBox = new Box(0, 0,
|
|
262
|
+
Sankey.prototype.calculateSankey = function calculateSankey$1 (calcOptions, sankeyOptions) {
|
|
263
|
+
var title = sankeyOptions.title;
|
|
264
|
+
var legend = sankeyOptions.legend;
|
|
265
|
+
var data = sankeyOptions.data;
|
|
266
|
+
var nodes = sankeyOptions.nodes;
|
|
267
|
+
var labels = sankeyOptions.labels;
|
|
268
|
+
var nodesColors = sankeyOptions.nodesColors;
|
|
269
|
+
var disableAutoLayout = sankeyOptions.disableAutoLayout;
|
|
270
|
+
var autoLayout = !disableAutoLayout;
|
|
271
|
+
|
|
272
|
+
var sankeyBox = new Box(0, 0, calcOptions.width, calcOptions.height);
|
|
271
273
|
var titleBox = this.titleBox(title, sankeyBox);
|
|
272
274
|
|
|
273
275
|
var legendArea = sankeyBox.clone();
|
|
@@ -276,34 +278,35 @@ export var Sankey = (function (Observable) {
|
|
|
276
278
|
var titleHeight = titleBox.height();
|
|
277
279
|
if (title.position === TOP) {
|
|
278
280
|
sankeyBox.unpad({ top: titleHeight });
|
|
279
|
-
legendArea = new Box(0, titleHeight,
|
|
281
|
+
legendArea = new Box(0, titleHeight, calcOptions.width, calcOptions.height);
|
|
280
282
|
} else {
|
|
281
283
|
sankeyBox.shrink(0, titleHeight);
|
|
282
|
-
legendArea = new Box(0, 0,
|
|
284
|
+
legendArea = new Box(0, 0, calcOptions.width, calcOptions.height - titleHeight);
|
|
283
285
|
}
|
|
284
286
|
}
|
|
285
287
|
|
|
286
288
|
var legendBox = this.legendBox(legend, data.nodes, legendArea);
|
|
289
|
+
var legendPosition = (legend && legend.position) || Legend.prototype.options.position;
|
|
287
290
|
|
|
288
291
|
if (legendBox) {
|
|
289
|
-
if (
|
|
292
|
+
if (legendPosition === LEFT) {
|
|
290
293
|
sankeyBox.unpad({ left: legendBox.width() });
|
|
291
294
|
}
|
|
292
295
|
|
|
293
|
-
if (
|
|
296
|
+
if (legendPosition === RIGHT) {
|
|
294
297
|
sankeyBox.shrink(legendBox.width(), 0);
|
|
295
298
|
}
|
|
296
299
|
|
|
297
|
-
if (
|
|
300
|
+
if (legendPosition === TOP) {
|
|
298
301
|
sankeyBox.unpad({ top: legendBox.height() });
|
|
299
302
|
}
|
|
300
303
|
|
|
301
|
-
if (
|
|
304
|
+
if (legendPosition === BOTTOM) {
|
|
302
305
|
sankeyBox.shrink(0, legendBox.height());
|
|
303
306
|
}
|
|
304
307
|
}
|
|
305
308
|
|
|
306
|
-
var calculatedNodes = calculateSankey(Object.assign({},
|
|
309
|
+
var calculatedNodes = calculateSankey(Object.assign({}, calcOptions, {offsetX: 0, offsetY: 0, width: sankeyBox.width(), height: sankeyBox.height()})).nodes;
|
|
307
310
|
var box = new Box();
|
|
308
311
|
|
|
309
312
|
calculatedNodes.forEach(function (nodeEl, i) {
|
|
@@ -311,47 +314,102 @@ export var Sankey = (function (Observable) {
|
|
|
311
314
|
var nodeInstance = new Node(nodeOps);
|
|
312
315
|
box.wrap(rectToBox(nodeInstance.exportVisual().rawBBox()));
|
|
313
316
|
|
|
314
|
-
var labelInstance = new Label(
|
|
317
|
+
var labelInstance = new Label(resolveLabelOptions(nodeEl, labels, sankeyBox.width()));
|
|
315
318
|
var labelVisual = labelInstance.exportVisual();
|
|
316
319
|
if (labelVisual) {
|
|
317
320
|
box.wrap(rectToBox(labelVisual.rawBBox()));
|
|
318
321
|
}
|
|
319
322
|
});
|
|
320
323
|
|
|
321
|
-
var offsetX =
|
|
322
|
-
var offsetY =
|
|
324
|
+
var offsetX = sankeyBox.x1;
|
|
325
|
+
var offsetY = sankeyBox.y1;
|
|
323
326
|
|
|
324
|
-
var width =
|
|
325
|
-
var height =
|
|
327
|
+
var width = sankeyBox.width() + offsetX;
|
|
328
|
+
var height = sankeyBox.height() + offsetY;
|
|
329
|
+
|
|
330
|
+
width -= box.x2 > sankeyBox.width() ? box.x2 - sankeyBox.width() : 0;
|
|
331
|
+
height -= box.y2 > sankeyBox.height() ? box.y2 - sankeyBox.height() : 0;
|
|
332
|
+
|
|
333
|
+
offsetX += box.x1 < 0 ? -box.x1 : 0;
|
|
334
|
+
offsetY += box.y1 < 0 ? -box.y1 : 0;
|
|
335
|
+
|
|
336
|
+
if (autoLayout === false) {
|
|
337
|
+
return {
|
|
338
|
+
sankey: calculateSankey(Object.assign({}, calcOptions, {offsetX: offsetX, offsetY: offsetY, width: width, height: height, autoLayout: false})),
|
|
339
|
+
legendBox: legendBox,
|
|
340
|
+
titleBox: titleBox
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (this.resize && autoLayout && this.permutation) {
|
|
345
|
+
this.resize = false;
|
|
346
|
+
return {
|
|
347
|
+
sankey: calculateSankey(Object.assign({}, calcOptions, {offsetX: offsetX, offsetY: offsetY, width: width, height: height}, this.permutation)),
|
|
348
|
+
legendBox: legendBox,
|
|
349
|
+
titleBox: titleBox
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
var startColumn = 1;
|
|
354
|
+
var loops = 2;
|
|
355
|
+
var columnsLength = calculateSankey(Object.assign({}, calcOptions, {offsetX: offsetX, offsetY: offsetY, width: width, height: height, autoLayout: false})).columns.length;
|
|
356
|
+
var results = [];
|
|
357
|
+
|
|
358
|
+
var permutation = function (targetColumnIndex, reverse) {
|
|
359
|
+
var currPerm = calculateSankey(Object.assign({}, calcOptions, {offsetX: offsetX, offsetY: offsetY, width: width, height: height, loops: loops, targetColumnIndex: targetColumnIndex, reverse: reverse}));
|
|
360
|
+
var crosses = crossesValue(currPerm.links);
|
|
361
|
+
results.push({
|
|
362
|
+
crosses: crosses,
|
|
363
|
+
reverse: reverse,
|
|
364
|
+
targetColumnIndex: targetColumnIndex
|
|
365
|
+
});
|
|
366
|
+
return crosses === 0;
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
for (var index = startColumn; index <= columnsLength - 1; index++) {
|
|
370
|
+
if (permutation(index, false) || permutation(index, true)) {
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
var minCrosses = Math.min.apply(null, results.map(function (r) { return r.crosses; }));
|
|
376
|
+
var bestResult = results.find(function (r) { return r.crosses === minCrosses; });
|
|
377
|
+
this.permutation = { targetColumnIndex: bestResult.targetColumnIndex, reverse: bestResult.reverse };
|
|
378
|
+
var result = calculateSankey(Object.assign({}, calcOptions, {offsetX: offsetX, offsetY: offsetY, width: width, height: height}, this.permutation));
|
|
326
379
|
|
|
327
380
|
return {
|
|
328
|
-
sankey:
|
|
381
|
+
sankey: result,
|
|
329
382
|
legendBox: legendBox,
|
|
330
383
|
titleBox: titleBox
|
|
331
384
|
};
|
|
332
385
|
};
|
|
333
386
|
|
|
334
|
-
Sankey.prototype._render = function _render () {
|
|
335
|
-
var
|
|
336
|
-
var
|
|
337
|
-
|
|
338
|
-
var
|
|
339
|
-
var
|
|
340
|
-
var
|
|
341
|
-
var
|
|
342
|
-
var
|
|
343
|
-
var
|
|
344
|
-
var
|
|
345
|
-
var
|
|
387
|
+
Sankey.prototype._render = function _render (options, context) {
|
|
388
|
+
var sankeyOptions = options || this.options;
|
|
389
|
+
var sankeyContext = context || this;
|
|
390
|
+
|
|
391
|
+
var data = sankeyOptions.data;
|
|
392
|
+
var labelOptions = sankeyOptions.labels;
|
|
393
|
+
var nodesOptions = sankeyOptions.nodes;
|
|
394
|
+
var linkOptions = sankeyOptions.links;
|
|
395
|
+
var nodesColors = sankeyOptions.nodesColors;
|
|
396
|
+
var title = sankeyOptions.title;
|
|
397
|
+
var legend = sankeyOptions.legend;
|
|
398
|
+
var ref = sankeyContext.size;
|
|
399
|
+
var width = ref.width;
|
|
400
|
+
var height = ref.height;
|
|
401
|
+
|
|
346
402
|
var calcOptions = Object.assign({}, data, {width: width, height: height, nodesOptions: nodesOptions, title: title, legend: legend});
|
|
347
|
-
var ref$
|
|
348
|
-
var sankey = ref$
|
|
349
|
-
var titleBox = ref$
|
|
350
|
-
var legendBox = ref$
|
|
403
|
+
var ref$1 = this.calculateSankey(calcOptions, sankeyOptions);
|
|
404
|
+
var sankey = ref$1.sankey;
|
|
405
|
+
var titleBox = ref$1.titleBox;
|
|
406
|
+
var legendBox = ref$1.legendBox;
|
|
351
407
|
var nodes = sankey.nodes;
|
|
352
408
|
var links = sankey.links;
|
|
353
409
|
|
|
354
|
-
var visual = new drawing.Group(
|
|
410
|
+
var visual = new drawing.Group({
|
|
411
|
+
clip: drawing.Path.fromRect(new geometry.Rect([0, 0], [width, height]))
|
|
412
|
+
});
|
|
355
413
|
|
|
356
414
|
if (titleBox) {
|
|
357
415
|
var titleElement = new Title(Object.assign({}, title, {drawingRect: titleBox}));
|
|
@@ -366,6 +424,7 @@ export var Sankey = (function (Observable) {
|
|
|
366
424
|
}
|
|
367
425
|
|
|
368
426
|
var visualNodes = new Map();
|
|
427
|
+
sankeyContext.nodesVisuals = visualNodes;
|
|
369
428
|
|
|
370
429
|
nodes.forEach(function (node, i) {
|
|
371
430
|
var nodeOps = resolveNodeOptions(node, nodesOptions, nodesColors, i);
|
|
@@ -388,6 +447,7 @@ export var Sankey = (function (Observable) {
|
|
|
388
447
|
var sortedLinks = links.slice().sort(function (a, b) { return b.value - a.value; });
|
|
389
448
|
|
|
390
449
|
var linksVisuals = [];
|
|
450
|
+
sankeyContext.linksVisuals = linksVisuals;
|
|
391
451
|
|
|
392
452
|
sortedLinks.forEach(function (link) {
|
|
393
453
|
var source = link.source;
|
|
@@ -412,11 +472,9 @@ export var Sankey = (function (Observable) {
|
|
|
412
472
|
visual.append(linkVisual);
|
|
413
473
|
});
|
|
414
474
|
|
|
415
|
-
|
|
416
|
-
this.nodesVisuals = visualNodes;
|
|
417
|
-
|
|
475
|
+
var diagramWidth = nodes.reduce(function (acc, node) { return Math.max(acc, node.x1); }, 0);
|
|
418
476
|
nodes.forEach(function (node) {
|
|
419
|
-
var textOps = resolveLabelOptions(node, labelOptions,
|
|
477
|
+
var textOps = resolveLabelOptions(node, labelOptions, diagramWidth);
|
|
420
478
|
var labelInstance = new Label(textOps);
|
|
421
479
|
var labelVisual = labelInstance.exportVisual();
|
|
422
480
|
|
|
@@ -428,8 +486,18 @@ export var Sankey = (function (Observable) {
|
|
|
428
486
|
return visual;
|
|
429
487
|
};
|
|
430
488
|
|
|
431
|
-
Sankey.prototype.exportVisual = function exportVisual () {
|
|
432
|
-
|
|
489
|
+
Sankey.prototype.exportVisual = function exportVisual (exportOptions) {
|
|
490
|
+
var options = (exportOptions && exportOptions.options) ?
|
|
491
|
+
deepExtend({}, this.options, exportOptions.options) : this.options;
|
|
492
|
+
|
|
493
|
+
var context = {
|
|
494
|
+
size: {
|
|
495
|
+
width: defined(exportOptions && exportOptions.width) ? exportOptions.width : this.size.width,
|
|
496
|
+
height: defined(exportOptions && exportOptions.height) ? exportOptions.height : this.size.height
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
return this._render(options, context);
|
|
433
501
|
};
|
|
434
502
|
|
|
435
503
|
Sankey.prototype._setOptions = function _setOptions (options) {
|
|
@@ -440,6 +508,9 @@ export var Sankey = (function (Observable) {
|
|
|
440
508
|
}(Observable));
|
|
441
509
|
|
|
442
510
|
setDefaultOptions(Sankey, {
|
|
511
|
+
title: {
|
|
512
|
+
position: TOP, // 'top', 'bottom'
|
|
513
|
+
},
|
|
443
514
|
labels: {
|
|
444
515
|
visible: true,
|
|
445
516
|
margin: {
|
|
@@ -458,6 +529,7 @@ setDefaultOptions(Sankey, {
|
|
|
458
529
|
width: 24,
|
|
459
530
|
padding: 16,
|
|
460
531
|
opacity: 1,
|
|
532
|
+
align: 'stretch', // 'left', 'right', 'stretch'
|
|
461
533
|
offset: { left: 0, top: 0 }
|
|
462
534
|
},
|
|
463
535
|
links: {
|