@progress/kendo-charts 2.1.1-dev.202401290907 → 2.2.0-dev.202402011056
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/legend.js +59 -0
- package/dist/es/sankey/node.js +3 -1
- package/dist/es/sankey/sankey.js +119 -22
- package/dist/es/sankey/title.js +48 -0
- package/dist/es2015/sankey/legend.js +47 -0
- package/dist/es2015/sankey/node.js +3 -1
- package/dist/es2015/sankey/sankey.js +107 -17
- package/dist/es2015/sankey/title.js +37 -0
- package/dist/npm/main.js +217 -23
- package/dist/systemjs/kendo-charts.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { default as ChartLegend } from "../chart/legend/legend";
|
|
2
|
+
import { SankeyElement } from "./element";
|
|
3
|
+
import { setDefaultOptions } from '../common';
|
|
4
|
+
import { nodeColor } from "./node";
|
|
5
|
+
import { BOTTOM, CENTER, POINTER } from "../common/constants";
|
|
6
|
+
import { AREA } from "../chart/constants";
|
|
7
|
+
|
|
8
|
+
export var Legend = (function (SankeyElement) {
|
|
9
|
+
function Legend () {
|
|
10
|
+
SankeyElement.apply(this, arguments);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if ( SankeyElement ) Legend.__proto__ = SankeyElement;
|
|
14
|
+
Legend.prototype = Object.create( SankeyElement && SankeyElement.prototype );
|
|
15
|
+
Legend.prototype.constructor = Legend;
|
|
16
|
+
|
|
17
|
+
Legend.prototype.getElement = function getElement () {
|
|
18
|
+
var options = this.options;
|
|
19
|
+
var drawingRect = options.drawingRect;
|
|
20
|
+
var nodes = options.nodes; if ( nodes === void 0 ) nodes = [];
|
|
21
|
+
var colors = options.colors; if ( colors === void 0 ) colors = [];
|
|
22
|
+
|
|
23
|
+
if (options.visible === false || !nodes.length) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var data = nodes.map(function (node, index) { return ({
|
|
28
|
+
text: (node.label && node.label.text) || '',
|
|
29
|
+
area: { background: nodeColor(node, colors, index), opacity: node.opacity },
|
|
30
|
+
node: node,
|
|
31
|
+
}); });
|
|
32
|
+
|
|
33
|
+
var legend = new ChartLegend(Object.assign({}, options, {data: data}));
|
|
34
|
+
legend.reflow(drawingRect);
|
|
35
|
+
|
|
36
|
+
legend.renderVisual();
|
|
37
|
+
return legend.visual;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
Legend.prototype.createElement = function createElement () {
|
|
41
|
+
return this.getElement();
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return Legend;
|
|
45
|
+
}(SankeyElement));
|
|
46
|
+
|
|
47
|
+
setDefaultOptions(Legend, {
|
|
48
|
+
markers: { visible: false },
|
|
49
|
+
item: {
|
|
50
|
+
type: AREA,
|
|
51
|
+
cursor: POINTER,
|
|
52
|
+
opacity: 1
|
|
53
|
+
},
|
|
54
|
+
position: BOTTOM,
|
|
55
|
+
align: CENTER,
|
|
56
|
+
border: {
|
|
57
|
+
width: 0
|
|
58
|
+
}
|
|
59
|
+
});
|
package/dist/es/sankey/node.js
CHANGED
|
@@ -34,10 +34,12 @@ export var Node = (function (SankeyElement) {
|
|
|
34
34
|
return Node;
|
|
35
35
|
}(SankeyElement));
|
|
36
36
|
|
|
37
|
+
export var nodeColor = function (node, nodesColors, index) { return node.color || nodesColors[index % nodesColors.length]; };
|
|
38
|
+
|
|
37
39
|
export var resolveNodeOptions = function (node, options, nodesColors, index) {
|
|
38
40
|
var nodeOptions = deepExtend({}, options, options.node);
|
|
39
41
|
return deepExtend({},
|
|
40
|
-
{ color: nodesColors
|
|
42
|
+
{ color: nodeColor(node, nodesColors, index) },
|
|
41
43
|
nodeOptions,
|
|
42
44
|
{ node: node },
|
|
43
45
|
{
|
package/dist/es/sankey/sankey.js
CHANGED
|
@@ -4,10 +4,12 @@ import { calculateSankey } from './calculation';
|
|
|
4
4
|
import { Node, resolveNodeOptions } from './node';
|
|
5
5
|
import { Link, resolveLinkOptions } from './link';
|
|
6
6
|
import { Label, resolveLabelOptions } from './label';
|
|
7
|
-
import {
|
|
7
|
+
import { Title } from './title';
|
|
8
|
+
import { BOTTOM, LEFT, RIGHT, TOP } from '../common/constants';
|
|
8
9
|
import Box from '../core/box';
|
|
9
10
|
import rectToBox from '../core/utils/rect-to-box';
|
|
10
11
|
import { Observable } from '../common/observable';
|
|
12
|
+
import { Legend } from './legend';
|
|
11
13
|
|
|
12
14
|
var LINK = 'link';
|
|
13
15
|
var NODE = 'node';
|
|
@@ -103,11 +105,10 @@ export var Sankey = (function (Observable) {
|
|
|
103
105
|
};
|
|
104
106
|
|
|
105
107
|
Sankey.prototype._mouseenter = function _mouseenter (ev) {
|
|
106
|
-
var this$1 = this;
|
|
107
|
-
|
|
108
108
|
var element = ev.element;
|
|
109
109
|
var isLink = element.type === LINK;
|
|
110
110
|
var isNode = element.type === NODE;
|
|
111
|
+
var isLegendItem = Boolean(element.chartElement && element.chartElement.options.node);
|
|
111
112
|
|
|
112
113
|
if ((isLink && this.trigger('linkEnter', ev)) ||
|
|
113
114
|
(isNode && this.trigger('nodeEnter', ev))) {
|
|
@@ -120,10 +121,10 @@ export var Sankey = (function (Observable) {
|
|
|
120
121
|
this.setLinksOpacity(highlight.inactiveOpacity);
|
|
121
122
|
this.setOpacity(element, highlight.opacity);
|
|
122
123
|
} else if (isNode) {
|
|
123
|
-
this.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
this.highlightLinks(element, highlight);
|
|
125
|
+
} else if (isLegendItem) {
|
|
126
|
+
var nodeVisual = this.nodesVisuals.get(element.chartElement.options.node.id);
|
|
127
|
+
this.highlightLinks(nodeVisual, highlight);
|
|
127
128
|
}
|
|
128
129
|
};
|
|
129
130
|
|
|
@@ -131,6 +132,7 @@ export var Sankey = (function (Observable) {
|
|
|
131
132
|
var element = ev.element;
|
|
132
133
|
var isLink = element.type === LINK;
|
|
133
134
|
var isNode = element.type === NODE;
|
|
135
|
+
var isLegendItem = Boolean(element.chartElement && element.chartElement.options.node);
|
|
134
136
|
var target = ev.originalEvent.relatedTarget;
|
|
135
137
|
|
|
136
138
|
if (isLink && target && target.nodeName === 'text') {
|
|
@@ -142,11 +144,22 @@ export var Sankey = (function (Observable) {
|
|
|
142
144
|
return;
|
|
143
145
|
}
|
|
144
146
|
|
|
145
|
-
if (isLink || isNode) {
|
|
147
|
+
if (isLink || isNode || isLegendItem) {
|
|
146
148
|
this.setLinksOpacity(this.options.links.opacity);
|
|
147
149
|
}
|
|
148
150
|
};
|
|
149
151
|
|
|
152
|
+
Sankey.prototype.highlightLinks = function highlightLinks (node, highlight) {
|
|
153
|
+
var this$1 = this;
|
|
154
|
+
|
|
155
|
+
if (node) {
|
|
156
|
+
this.setLinksOpacity(highlight.inactiveOpacity);
|
|
157
|
+
node.links.forEach(function (link) {
|
|
158
|
+
this$1.setOpacity(link, highlight.opacity);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
150
163
|
Sankey.prototype._destroySurface = function _destroySurface () {
|
|
151
164
|
if (this.surface) {
|
|
152
165
|
this.surface.destroy();
|
|
@@ -205,12 +218,74 @@ export var Sankey = (function (Observable) {
|
|
|
205
218
|
this.visual = this._render();
|
|
206
219
|
};
|
|
207
220
|
|
|
221
|
+
Sankey.prototype.titleBox = function titleBox (title, drawingRect) {
|
|
222
|
+
if (!title || title.visible === false || !title.text) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
var titleElement = new Title(Object.assign({}, {drawingRect: drawingRect}, title));
|
|
227
|
+
var titleVisual = titleElement.exportVisual();
|
|
228
|
+
return titleVisual.chartElement.box;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
Sankey.prototype.legendBox = function legendBox (options, nodes, drawingRect) {
|
|
232
|
+
if (!options || options.visible === false) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
var legend = new Legend(Object.assign({}, {nodes: nodes}, options, {drawingRect: drawingRect}));
|
|
237
|
+
var legendVisual = legend.exportVisual();
|
|
238
|
+
|
|
239
|
+
return legendVisual.chartElement.box;
|
|
240
|
+
};
|
|
241
|
+
|
|
208
242
|
Sankey.prototype.calculateSankey = function calculateSankey$1 (options) {
|
|
209
243
|
var ref = this.options;
|
|
210
|
-
var
|
|
211
|
-
var
|
|
212
|
-
var
|
|
213
|
-
var
|
|
244
|
+
var title = ref.title;
|
|
245
|
+
var legend = ref.legend;
|
|
246
|
+
var data = ref.data;
|
|
247
|
+
var ref$1 = this.options;
|
|
248
|
+
var nodes = ref$1.nodes;
|
|
249
|
+
var labels = ref$1.labels;
|
|
250
|
+
var nodesColors = ref$1.nodesColors;
|
|
251
|
+
|
|
252
|
+
var sankeyBox = new Box(0, 0, options.width, options.height);
|
|
253
|
+
var titleBox = this.titleBox(title, sankeyBox);
|
|
254
|
+
|
|
255
|
+
var legendArea = sankeyBox.clone();
|
|
256
|
+
|
|
257
|
+
if (titleBox) {
|
|
258
|
+
var titleHeight = titleBox.height();
|
|
259
|
+
if (title.position === TOP) {
|
|
260
|
+
sankeyBox.unpad({ top: titleHeight });
|
|
261
|
+
legendArea = new Box(0, titleHeight, options.width, options.height);
|
|
262
|
+
} else {
|
|
263
|
+
sankeyBox.shrink(0, titleHeight);
|
|
264
|
+
legendArea = new Box(0, 0, options.width, options.height - titleHeight);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
var legendBox = this.legendBox(legend, data.nodes, legendArea);
|
|
269
|
+
|
|
270
|
+
if (legendBox) {
|
|
271
|
+
if (legend.position === LEFT) {
|
|
272
|
+
sankeyBox.unpad({ left: legendBox.width() });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (legend.position === RIGHT) {
|
|
276
|
+
sankeyBox.shrink(legendBox.width(), 0);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (legend.position === TOP) {
|
|
280
|
+
sankeyBox.unpad({ top: legendBox.height() });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (legend.position === BOTTOM) {
|
|
284
|
+
sankeyBox.shrink(0, legendBox.height());
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
var calculatedNodes = calculateSankey(Object.assign({}, options, {offsetX: sankeyBox.x1, offsetY: sankeyBox.y1, width: sankeyBox.x2, height: sankeyBox.y2})).nodes;
|
|
214
289
|
var box = new Box();
|
|
215
290
|
|
|
216
291
|
calculatedNodes.forEach(function (nodeEl, i) {
|
|
@@ -225,13 +300,17 @@ export var Sankey = (function (Observable) {
|
|
|
225
300
|
}
|
|
226
301
|
});
|
|
227
302
|
|
|
228
|
-
var offsetX = box.x1 < 0 ? -box.x1 : 0;
|
|
229
|
-
var offsetY = box.y1 < 0 ? -box.y1 : 0;
|
|
303
|
+
var offsetX = (box.x1 < 0 ? -box.x1 : 0) + sankeyBox.x1;
|
|
304
|
+
var offsetY = (box.y1 < 0 ? -box.y1 : 0) + sankeyBox.y1;
|
|
230
305
|
|
|
231
|
-
var width = box.width() >
|
|
232
|
-
var height = box.height() >
|
|
306
|
+
var width = box.width() > sankeyBox.x2 ? offsetX + sankeyBox.x2 - (box.width() - sankeyBox.x2) : sankeyBox.x2;
|
|
307
|
+
var height = box.height() > sankeyBox.y2 ? offsetY + sankeyBox.y2 - (box.height() - sankeyBox.y2) : sankeyBox.y2;
|
|
233
308
|
|
|
234
|
-
return
|
|
309
|
+
return {
|
|
310
|
+
sankey: calculateSankey(Object.assign({}, options, {offsetX: offsetX, offsetY: offsetY, width: width, height: height})),
|
|
311
|
+
legendBox: legendBox,
|
|
312
|
+
titleBox: titleBox
|
|
313
|
+
};
|
|
235
314
|
};
|
|
236
315
|
|
|
237
316
|
Sankey.prototype._render = function _render () {
|
|
@@ -241,16 +320,33 @@ export var Sankey = (function (Observable) {
|
|
|
241
320
|
var nodesOptions = ref.nodes;
|
|
242
321
|
var linkOptions = ref.links;
|
|
243
322
|
var nodesColors = ref.nodesColors;
|
|
323
|
+
var title = ref.title;
|
|
324
|
+
var legend = ref.legend;
|
|
244
325
|
var ref$1 = this.size;
|
|
245
326
|
var width = ref$1.width;
|
|
246
327
|
var height = ref$1.height;
|
|
247
|
-
var calcOptions = Object.assign({}, data, {width: width, height: height, nodesOptions: nodesOptions});
|
|
328
|
+
var calcOptions = Object.assign({}, data, {width: width, height: height, nodesOptions: nodesOptions, title: title, legend: legend});
|
|
248
329
|
var ref$2 = this.calculateSankey(calcOptions);
|
|
249
|
-
var
|
|
250
|
-
var
|
|
330
|
+
var sankey = ref$2.sankey;
|
|
331
|
+
var titleBox = ref$2.titleBox;
|
|
332
|
+
var legendBox = ref$2.legendBox;
|
|
333
|
+
var nodes = sankey.nodes;
|
|
334
|
+
var links = sankey.links;
|
|
251
335
|
|
|
252
336
|
var visual = new drawing.Group();
|
|
253
337
|
|
|
338
|
+
if (titleBox) {
|
|
339
|
+
var titleElement = new Title(Object.assign({}, title, {drawingRect: titleBox}));
|
|
340
|
+
var titleVisual = titleElement.exportVisual();
|
|
341
|
+
visual.append(titleVisual);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (legendBox) {
|
|
345
|
+
var legendElement = new Legend(Object.assign({}, legend, {drawingRect: legendBox, nodes: nodes, colors: nodesColors}));
|
|
346
|
+
var legendVisual = legendElement.exportVisual();
|
|
347
|
+
visual.append(legendVisual);
|
|
348
|
+
}
|
|
349
|
+
|
|
254
350
|
var visualNodes = new Map();
|
|
255
351
|
|
|
256
352
|
nodes.forEach(function (node, i) {
|
|
@@ -265,11 +361,11 @@ export var Sankey = (function (Observable) {
|
|
|
265
361
|
visual.append(nodeVisual);
|
|
266
362
|
});
|
|
267
363
|
|
|
268
|
-
|
|
364
|
+
var sortedLinks = links.slice().sort(function (a, b) { return b.value - a.value; });
|
|
269
365
|
|
|
270
366
|
var linksVisuals = [];
|
|
271
367
|
|
|
272
|
-
|
|
368
|
+
sortedLinks.forEach(function (link) {
|
|
273
369
|
var source = link.source;
|
|
274
370
|
var target = link.target;
|
|
275
371
|
var sourceNode = visualNodes.get(source.id);
|
|
@@ -288,6 +384,7 @@ export var Sankey = (function (Observable) {
|
|
|
288
384
|
});
|
|
289
385
|
|
|
290
386
|
this.linksVisuals = linksVisuals;
|
|
387
|
+
this.nodesVisuals = visualNodes;
|
|
291
388
|
|
|
292
389
|
nodes.forEach(function (node) {
|
|
293
390
|
var textOps = resolveLabelOptions(node, labelOptions, width);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Title as ChartTitle } from "../core";
|
|
2
|
+
import { SankeyElement } from "./element";
|
|
3
|
+
import { setDefaultOptions, getSpacing } from '../common';
|
|
4
|
+
import { CENTER, TOP } from "../common/constants";
|
|
5
|
+
|
|
6
|
+
export var Title = (function (SankeyElement) {
|
|
7
|
+
function Title () {
|
|
8
|
+
SankeyElement.apply(this, arguments);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if ( SankeyElement ) Title.__proto__ = SankeyElement;
|
|
12
|
+
Title.prototype = Object.create( SankeyElement && SankeyElement.prototype );
|
|
13
|
+
Title.prototype.constructor = Title;
|
|
14
|
+
|
|
15
|
+
Title.prototype.getElement = function getElement () {
|
|
16
|
+
var options = this.options;
|
|
17
|
+
var drawingRect = options.drawingRect;
|
|
18
|
+
var text = options.text;
|
|
19
|
+
|
|
20
|
+
if (options.visible === false || !text) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var title = ChartTitle.buildTitle(text, options);
|
|
25
|
+
|
|
26
|
+
title.reflow(drawingRect);
|
|
27
|
+
|
|
28
|
+
title.renderVisual();
|
|
29
|
+
return title.visual;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
Title.prototype.createElement = function createElement () {
|
|
33
|
+
return this.getElement();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return Title;
|
|
37
|
+
}(SankeyElement));
|
|
38
|
+
|
|
39
|
+
setDefaultOptions(Title, {
|
|
40
|
+
position: TOP, // 'top', 'bottom'
|
|
41
|
+
align: CENTER, // 'left', 'right', 'center'
|
|
42
|
+
opacity: 1,
|
|
43
|
+
border: {
|
|
44
|
+
width: 0
|
|
45
|
+
},
|
|
46
|
+
margin: getSpacing(5),
|
|
47
|
+
padding: getSpacing(5)
|
|
48
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { default as ChartLegend } from "../chart/legend/legend";
|
|
2
|
+
import { SankeyElement } from "./element";
|
|
3
|
+
import { setDefaultOptions } from '../common';
|
|
4
|
+
import { nodeColor } from "./node";
|
|
5
|
+
import { BOTTOM, CENTER, POINTER } from "../common/constants";
|
|
6
|
+
import { AREA } from "../chart/constants";
|
|
7
|
+
|
|
8
|
+
export class Legend extends SankeyElement {
|
|
9
|
+
getElement() {
|
|
10
|
+
const options = this.options;
|
|
11
|
+
const { drawingRect, nodes = [], colors = [] } = options;
|
|
12
|
+
|
|
13
|
+
if (options.visible === false || !nodes.length) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const data = nodes.map((node, index) => ({
|
|
18
|
+
text: (node.label && node.label.text) || '',
|
|
19
|
+
area: { background: nodeColor(node, colors, index), opacity: node.opacity },
|
|
20
|
+
node: node,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
const legend = new ChartLegend(Object.assign({}, options, {data}));
|
|
24
|
+
legend.reflow(drawingRect);
|
|
25
|
+
|
|
26
|
+
legend.renderVisual();
|
|
27
|
+
return legend.visual;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
createElement() {
|
|
31
|
+
return this.getElement();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setDefaultOptions(Legend, {
|
|
36
|
+
markers: { visible: false },
|
|
37
|
+
item: {
|
|
38
|
+
type: AREA,
|
|
39
|
+
cursor: POINTER,
|
|
40
|
+
opacity: 1
|
|
41
|
+
},
|
|
42
|
+
position: BOTTOM,
|
|
43
|
+
align: CENTER,
|
|
44
|
+
border: {
|
|
45
|
+
width: 0
|
|
46
|
+
}
|
|
47
|
+
});
|
|
@@ -24,10 +24,12 @@ export class Node extends SankeyElement {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export const nodeColor = (node, nodesColors, index) => node.color || nodesColors[index % nodesColors.length];
|
|
28
|
+
|
|
27
29
|
export const resolveNodeOptions = (node, options, nodesColors, index) => {
|
|
28
30
|
const nodeOptions = deepExtend({}, options, options.node);
|
|
29
31
|
return deepExtend({},
|
|
30
|
-
{ color: nodesColors
|
|
32
|
+
{ color: nodeColor(node, nodesColors, index) },
|
|
31
33
|
nodeOptions,
|
|
32
34
|
{ node },
|
|
33
35
|
{
|
|
@@ -4,10 +4,12 @@ import { calculateSankey } from './calculation';
|
|
|
4
4
|
import { Node, resolveNodeOptions } from './node';
|
|
5
5
|
import { Link, resolveLinkOptions } from './link';
|
|
6
6
|
import { Label, resolveLabelOptions } from './label';
|
|
7
|
-
import {
|
|
7
|
+
import { Title } from './title';
|
|
8
|
+
import { BOTTOM, LEFT, RIGHT, TOP } from '../common/constants';
|
|
8
9
|
import Box from '../core/box';
|
|
9
10
|
import rectToBox from '../core/utils/rect-to-box';
|
|
10
11
|
import { Observable } from '../common/observable';
|
|
12
|
+
import { Legend } from './legend';
|
|
11
13
|
|
|
12
14
|
const LINK = 'link';
|
|
13
15
|
const NODE = 'node';
|
|
@@ -96,6 +98,7 @@ export class Sankey extends Observable {
|
|
|
96
98
|
const element = ev.element;
|
|
97
99
|
const isLink = element.type === LINK;
|
|
98
100
|
const isNode = element.type === NODE;
|
|
101
|
+
const isLegendItem = Boolean(element.chartElement && element.chartElement.options.node);
|
|
99
102
|
|
|
100
103
|
if ((isLink && this.trigger('linkEnter', ev)) ||
|
|
101
104
|
(isNode && this.trigger('nodeEnter', ev))) {
|
|
@@ -107,10 +110,10 @@ export class Sankey extends Observable {
|
|
|
107
110
|
this.setLinksOpacity(highlight.inactiveOpacity);
|
|
108
111
|
this.setOpacity(element, highlight.opacity);
|
|
109
112
|
} else if (isNode) {
|
|
110
|
-
this.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
this.highlightLinks(element, highlight);
|
|
114
|
+
} else if (isLegendItem) {
|
|
115
|
+
const nodeVisual = this.nodesVisuals.get(element.chartElement.options.node.id);
|
|
116
|
+
this.highlightLinks(nodeVisual, highlight);
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
|
|
@@ -118,6 +121,7 @@ export class Sankey extends Observable {
|
|
|
118
121
|
const element = ev.element;
|
|
119
122
|
const isLink = element.type === LINK;
|
|
120
123
|
const isNode = element.type === NODE;
|
|
124
|
+
const isLegendItem = Boolean(element.chartElement && element.chartElement.options.node);
|
|
121
125
|
const target = ev.originalEvent.relatedTarget;
|
|
122
126
|
|
|
123
127
|
if (isLink && target && target.nodeName === 'text') {
|
|
@@ -129,11 +133,20 @@ export class Sankey extends Observable {
|
|
|
129
133
|
return;
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
if (isLink || isNode) {
|
|
136
|
+
if (isLink || isNode || isLegendItem) {
|
|
133
137
|
this.setLinksOpacity(this.options.links.opacity);
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
|
|
141
|
+
highlightLinks(node, highlight) {
|
|
142
|
+
if (node) {
|
|
143
|
+
this.setLinksOpacity(highlight.inactiveOpacity);
|
|
144
|
+
node.links.forEach(link => {
|
|
145
|
+
this.setOpacity(link, highlight.opacity);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
137
150
|
_destroySurface() {
|
|
138
151
|
if (this.surface) {
|
|
139
152
|
this.surface.destroy();
|
|
@@ -190,9 +203,68 @@ export class Sankey extends Observable {
|
|
|
190
203
|
this.visual = this._render();
|
|
191
204
|
}
|
|
192
205
|
|
|
206
|
+
titleBox(title, drawingRect) {
|
|
207
|
+
if (!title || title.visible === false || !title.text) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const titleElement = new Title(Object.assign({}, {drawingRect}, title));
|
|
212
|
+
const titleVisual = titleElement.exportVisual();
|
|
213
|
+
return titleVisual.chartElement.box;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
legendBox(options, nodes, drawingRect) {
|
|
217
|
+
if (!options || options.visible === false) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const legend = new Legend(Object.assign({}, {nodes}, options, {drawingRect}));
|
|
222
|
+
const legendVisual = legend.exportVisual();
|
|
223
|
+
|
|
224
|
+
return legendVisual.chartElement.box;
|
|
225
|
+
}
|
|
226
|
+
|
|
193
227
|
calculateSankey(options) {
|
|
228
|
+
const { title, legend, data } = this.options;
|
|
194
229
|
const { nodes, labels, nodesColors } = this.options;
|
|
195
|
-
|
|
230
|
+
|
|
231
|
+
const sankeyBox = new Box(0, 0, options.width, options.height);
|
|
232
|
+
const titleBox = this.titleBox(title, sankeyBox);
|
|
233
|
+
|
|
234
|
+
let legendArea = sankeyBox.clone();
|
|
235
|
+
|
|
236
|
+
if (titleBox) {
|
|
237
|
+
const titleHeight = titleBox.height();
|
|
238
|
+
if (title.position === TOP) {
|
|
239
|
+
sankeyBox.unpad({ top: titleHeight });
|
|
240
|
+
legendArea = new Box(0, titleHeight, options.width, options.height);
|
|
241
|
+
} else {
|
|
242
|
+
sankeyBox.shrink(0, titleHeight);
|
|
243
|
+
legendArea = new Box(0, 0, options.width, options.height - titleHeight);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const legendBox = this.legendBox(legend, data.nodes, legendArea);
|
|
248
|
+
|
|
249
|
+
if (legendBox) {
|
|
250
|
+
if (legend.position === LEFT) {
|
|
251
|
+
sankeyBox.unpad({ left: legendBox.width() });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (legend.position === RIGHT) {
|
|
255
|
+
sankeyBox.shrink(legendBox.width(), 0);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (legend.position === TOP) {
|
|
259
|
+
sankeyBox.unpad({ top: legendBox.height() });
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (legend.position === BOTTOM) {
|
|
263
|
+
sankeyBox.shrink(0, legendBox.height());
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const calculatedNodes = calculateSankey(Object.assign({}, options, {offsetX: sankeyBox.x1, offsetY: sankeyBox.y1, width: sankeyBox.x2, height: sankeyBox.y2})).nodes;
|
|
196
268
|
const box = new Box();
|
|
197
269
|
|
|
198
270
|
calculatedNodes.forEach((nodeEl, i) => {
|
|
@@ -207,23 +279,40 @@ export class Sankey extends Observable {
|
|
|
207
279
|
}
|
|
208
280
|
});
|
|
209
281
|
|
|
210
|
-
|
|
211
|
-
|
|
282
|
+
let offsetX = (box.x1 < 0 ? -box.x1 : 0) + sankeyBox.x1;
|
|
283
|
+
let offsetY = (box.y1 < 0 ? -box.y1 : 0) + sankeyBox.y1;
|
|
212
284
|
|
|
213
|
-
|
|
214
|
-
|
|
285
|
+
let width = box.width() > sankeyBox.x2 ? offsetX + sankeyBox.x2 - (box.width() - sankeyBox.x2) : sankeyBox.x2;
|
|
286
|
+
let height = box.height() > sankeyBox.y2 ? offsetY + sankeyBox.y2 - (box.height() - sankeyBox.y2) : sankeyBox.y2;
|
|
215
287
|
|
|
216
|
-
return
|
|
288
|
+
return {
|
|
289
|
+
sankey: calculateSankey(Object.assign({}, options, {offsetX, offsetY, width, height})),
|
|
290
|
+
legendBox,
|
|
291
|
+
titleBox
|
|
292
|
+
};
|
|
217
293
|
}
|
|
218
294
|
|
|
219
295
|
_render() {
|
|
220
|
-
const { data, labels: labelOptions, nodes: nodesOptions, links: linkOptions, nodesColors } = this.options;
|
|
296
|
+
const { data, labels: labelOptions, nodes: nodesOptions, links: linkOptions, nodesColors, title, legend } = this.options;
|
|
221
297
|
const { width, height } = this.size;
|
|
222
|
-
const calcOptions = Object.assign({}, data, {width, height, nodesOptions});
|
|
223
|
-
|
|
298
|
+
const calcOptions = Object.assign({}, data, {width, height, nodesOptions, title, legend});
|
|
299
|
+
const { sankey, titleBox, legendBox } = this.calculateSankey(calcOptions);
|
|
300
|
+
const { nodes, links } = sankey;
|
|
224
301
|
|
|
225
302
|
const visual = new drawing.Group();
|
|
226
303
|
|
|
304
|
+
if (titleBox) {
|
|
305
|
+
const titleElement = new Title(Object.assign({}, title, {drawingRect: titleBox}));
|
|
306
|
+
const titleVisual = titleElement.exportVisual();
|
|
307
|
+
visual.append(titleVisual);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (legendBox) {
|
|
311
|
+
const legendElement = new Legend(Object.assign({}, legend, {drawingRect: legendBox, nodes, colors: nodesColors}));
|
|
312
|
+
const legendVisual = legendElement.exportVisual();
|
|
313
|
+
visual.append(legendVisual);
|
|
314
|
+
}
|
|
315
|
+
|
|
227
316
|
const visualNodes = new Map();
|
|
228
317
|
|
|
229
318
|
nodes.forEach((node, i) => {
|
|
@@ -238,11 +327,11 @@ export class Sankey extends Observable {
|
|
|
238
327
|
visual.append(nodeVisual);
|
|
239
328
|
});
|
|
240
329
|
|
|
241
|
-
|
|
330
|
+
const sortedLinks = links.slice().sort((a, b) => b.value - a.value);
|
|
242
331
|
|
|
243
332
|
const linksVisuals = [];
|
|
244
333
|
|
|
245
|
-
|
|
334
|
+
sortedLinks.forEach(link => {
|
|
246
335
|
const { source, target } = link;
|
|
247
336
|
const sourceNode = visualNodes.get(source.id);
|
|
248
337
|
const targetNode = visualNodes.get(target.id);
|
|
@@ -260,6 +349,7 @@ export class Sankey extends Observable {
|
|
|
260
349
|
});
|
|
261
350
|
|
|
262
351
|
this.linksVisuals = linksVisuals;
|
|
352
|
+
this.nodesVisuals = visualNodes;
|
|
263
353
|
|
|
264
354
|
nodes.forEach((node) => {
|
|
265
355
|
const textOps = resolveLabelOptions(node, labelOptions, width);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Title as ChartTitle } from "../core";
|
|
2
|
+
import { SankeyElement } from "./element";
|
|
3
|
+
import { setDefaultOptions, getSpacing } from '../common';
|
|
4
|
+
import { CENTER, TOP } from "../common/constants";
|
|
5
|
+
|
|
6
|
+
export class Title extends SankeyElement {
|
|
7
|
+
getElement() {
|
|
8
|
+
const options = this.options;
|
|
9
|
+
const { drawingRect, text } = options;
|
|
10
|
+
|
|
11
|
+
if (options.visible === false || !text) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const title = ChartTitle.buildTitle(text, options);
|
|
16
|
+
|
|
17
|
+
title.reflow(drawingRect);
|
|
18
|
+
|
|
19
|
+
title.renderVisual();
|
|
20
|
+
return title.visual;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
createElement() {
|
|
24
|
+
return this.getElement();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setDefaultOptions(Title, {
|
|
29
|
+
position: TOP, // 'top', 'bottom'
|
|
30
|
+
align: CENTER, // 'left', 'right', 'center'
|
|
31
|
+
opacity: 1,
|
|
32
|
+
border: {
|
|
33
|
+
width: 0
|
|
34
|
+
},
|
|
35
|
+
margin: getSpacing(5),
|
|
36
|
+
padding: getSpacing(5)
|
|
37
|
+
});
|