@progress/kendo-charts 2.0.0-dev.202401111417 → 2.1.0-dev.202401181402
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/{map/scroller → common}/observable.js +1 -1
- package/dist/es/main.js +1 -0
- package/dist/es/map/attribution.js +1 -1
- package/dist/es/map/map.js +1 -1
- package/dist/es/map/navigator.js +1 -1
- package/dist/es/map/scroller/draggable.js +1 -1
- package/dist/es/map/scroller/scroller.js +1 -1
- package/dist/es/map/scroller/user-events.js +1 -1
- package/dist/es/map/zoom.js +1 -1
- package/dist/es/sankey/calculation.js +176 -0
- package/dist/es/sankey/element.js +49 -0
- package/dist/es/sankey/label.js +83 -0
- package/dist/es/sankey/link.js +62 -0
- package/dist/es/sankey/node.js +50 -0
- package/dist/es/sankey/sankey.js +345 -0
- package/dist/es/sankey.js +1 -0
- package/dist/es2015/{map/scroller → common}/observable.js +1 -1
- package/dist/es2015/main.js +1 -0
- package/dist/es2015/map/attribution.js +1 -1
- package/dist/es2015/map/map.js +1 -1
- package/dist/es2015/map/navigator.js +1 -1
- package/dist/es2015/map/scroller/draggable.js +1 -1
- package/dist/es2015/map/scroller/scroller.js +1 -1
- package/dist/es2015/map/scroller/user-events.js +1 -1
- package/dist/es2015/map/zoom.js +1 -1
- package/dist/es2015/sankey/calculation.js +170 -0
- package/dist/es2015/sankey/element.js +41 -0
- package/dist/es2015/sankey/label.js +69 -0
- package/dist/es2015/sankey/link.js +49 -0
- package/dist/es2015/sankey/node.js +40 -0
- package/dist/es2015/sankey/sankey.js +315 -0
- package/dist/es2015/sankey.js +1 -0
- package/dist/npm/main.d.ts +1 -0
- package/dist/npm/main.js +743 -1
- package/dist/npm/sankey.d.ts +244 -0
- package/dist/systemjs/kendo-charts.js +1 -1
- package/package.json +1 -1
package/dist/es/main.js
CHANGED
package/dist/es/map/map.js
CHANGED
package/dist/es/map/navigator.js
CHANGED
package/dist/es/map/zoom.js
CHANGED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { deepExtend } from '../common';
|
|
2
|
+
|
|
3
|
+
var max = function (array, mapFn) { return Math.max.apply(null, array.map(mapFn)); };
|
|
4
|
+
var min = function (array, mapFn) { return Math.min.apply(null, array.map(mapFn)); };
|
|
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; };
|
|
7
|
+
var sortSource = function (a, b) { return sortAsc(a.source, b.source); };
|
|
8
|
+
var sortTarget = function (a, b) { return sortAsc(a.target, b.target); };
|
|
9
|
+
var value = function (node) { return node.value; };
|
|
10
|
+
|
|
11
|
+
function sortLinks(nodes) {
|
|
12
|
+
nodes.forEach(function (node) {
|
|
13
|
+
var sourceLinks = node.sourceLinks;
|
|
14
|
+
var targetLinks = node.targetLinks;
|
|
15
|
+
sourceLinks.sort(sortTarget);
|
|
16
|
+
targetLinks.sort(sortSource);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var Sankey = function Sankey(options) {
|
|
21
|
+
var offset = options.nodesOptions.offset || {};
|
|
22
|
+
this.data = {
|
|
23
|
+
nodes: options.nodes.map(function (node) { return deepExtend({}, { offset: offset }, node); }),
|
|
24
|
+
links: options.links.map(function (link) { return deepExtend({}, link); })
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
this.width = options.width;
|
|
28
|
+
this.height = options.height;
|
|
29
|
+
this.offsetX = options.offsetX || 0;
|
|
30
|
+
this.offsetY = options.offsetY || 0;
|
|
31
|
+
this.nodeWidth = options.nodesOptions.width;
|
|
32
|
+
this.nodePadding = options.nodesOptions.padding;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
Sankey.prototype.calculate = function calculate () {
|
|
36
|
+
var ref = this.data;
|
|
37
|
+
var nodes = ref.nodes;
|
|
38
|
+
var links = ref.links;
|
|
39
|
+
this.connectLinksToNodes(nodes, links);
|
|
40
|
+
this.calculateNodeValues(nodes);
|
|
41
|
+
this.calculateNodeDepths(nodes);
|
|
42
|
+
|
|
43
|
+
var columns = this.calculateNodeColumns(nodes);
|
|
44
|
+
this.calculateNodeBreadths(columns);
|
|
45
|
+
this.applyNodesOffset(nodes);
|
|
46
|
+
this.calculateLinkBreadths(nodes);
|
|
47
|
+
|
|
48
|
+
return this.data;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
Sankey.prototype.connectLinksToNodes = function connectLinksToNodes (nodes, links) {
|
|
52
|
+
var nodesMap = new Map();
|
|
53
|
+
|
|
54
|
+
nodes.forEach(function (node) {
|
|
55
|
+
node.sourceLinks = [];
|
|
56
|
+
node.targetLinks = [];
|
|
57
|
+
node.id = node.id !== undefined ? node.id : node.label.text;
|
|
58
|
+
nodesMap.set(node.id, node);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
links.forEach(function (link) {
|
|
62
|
+
link.source = nodesMap.get(link.sourceId);
|
|
63
|
+
link.target = nodesMap.get(link.targetId);
|
|
64
|
+
link.source.sourceLinks.push(link);
|
|
65
|
+
link.target.targetLinks.push(link);
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
Sankey.prototype.calculateNodeValues = function calculateNodeValues (nodes) {
|
|
70
|
+
nodes.forEach(function (node) {
|
|
71
|
+
node.value = Math.max(
|
|
72
|
+
sum(node.sourceLinks, value),
|
|
73
|
+
sum(node.targetLinks, value)
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
Sankey.prototype.calculateNodeDepths = function calculateNodeDepths (nodes) {
|
|
79
|
+
var current = new Set(nodes);
|
|
80
|
+
var next = new Set();
|
|
81
|
+
var currDepth = 0;
|
|
82
|
+
while (current.size) {
|
|
83
|
+
var currentNodes = Array.from(current);
|
|
84
|
+
for (var n = 0; n < currentNodes.length; n++) {
|
|
85
|
+
var node = currentNodes[n];
|
|
86
|
+
node.depth = currDepth;
|
|
87
|
+
for (var l = 0; l < node.sourceLinks.length; l++) {
|
|
88
|
+
var link = node.sourceLinks[l];
|
|
89
|
+
next.add(link.target);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
currDepth++;
|
|
93
|
+
current = next;
|
|
94
|
+
next = new Set();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
Sankey.prototype.calculateNodeColumns = function calculateNodeColumns (nodes) {
|
|
99
|
+
var this$1 = this;
|
|
100
|
+
|
|
101
|
+
var maxDepth = max(nodes, function (d) { return d.depth; });
|
|
102
|
+
var columnWidth = (this.width - this.offsetX - this.nodeWidth) / maxDepth;
|
|
103
|
+
var columns = new Array(maxDepth + 1);
|
|
104
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
105
|
+
var node = nodes[i];
|
|
106
|
+
var depth = Math.max(0, Math.min(maxDepth, node.sourceLinks.length ? node.depth : maxDepth));
|
|
107
|
+
node.x0 = this$1.offsetX + depth * columnWidth;
|
|
108
|
+
node.x1 = node.x0 + this$1.nodeWidth;
|
|
109
|
+
columns[depth] = columns[depth] || [];
|
|
110
|
+
columns[depth].push(node);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return columns;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
Sankey.prototype.calculateNodeBreadths = function calculateNodeBreadths (columns) {
|
|
117
|
+
var this$1 = this;
|
|
118
|
+
|
|
119
|
+
var kSize = min(columns, function (c) { return (this$1.height - this$1.offsetY - (c.length - 1) * this$1.nodePadding) / sum(c, value); });
|
|
120
|
+
|
|
121
|
+
for (var c = 0; c < columns.length; c++) {
|
|
122
|
+
var nodes = columns[c];
|
|
123
|
+
var y = this$1.offsetY;
|
|
124
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
125
|
+
var node = nodes[i];
|
|
126
|
+
node.y0 = y;
|
|
127
|
+
node.y1 = y + node.value * kSize;
|
|
128
|
+
y = node.y1 + this$1.nodePadding;
|
|
129
|
+
for (var l = 0; l < node.sourceLinks.length; l++) {
|
|
130
|
+
var link = node.sourceLinks[l];
|
|
131
|
+
link.width = link.value * kSize;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
y = (this$1.height - y + this$1.nodePadding) / (nodes.length + 1);
|
|
136
|
+
for (var i$1 = 0; i$1 < nodes.length; ++i$1) {
|
|
137
|
+
var node$1 = nodes[i$1];
|
|
138
|
+
node$1.y0 += y * (i$1 + 1);
|
|
139
|
+
node$1.y1 += y * (i$1 + 1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for (var c$1 = 0; c$1 < columns.length; c$1++) {
|
|
144
|
+
sortLinks(columns[c$1]);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
Sankey.prototype.applyNodesOffset = function applyNodesOffset (nodes) {
|
|
149
|
+
nodes.forEach(function (node) {
|
|
150
|
+
var offsetX = (node.offset ? node.offset.left : 0) || 0;
|
|
151
|
+
var offsetY = (node.offset ? node.offset.top : 0) || 0;
|
|
152
|
+
node.x0 += offsetX;
|
|
153
|
+
node.x1 += offsetX;
|
|
154
|
+
node.y0 += offsetY;
|
|
155
|
+
node.y1 += offsetY;
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
Sankey.prototype.calculateLinkBreadths = function calculateLinkBreadths (nodes) {
|
|
160
|
+
nodes.forEach(function (node) {
|
|
161
|
+
var sourceLinks = node.sourceLinks;
|
|
162
|
+
var targetLinks = node.targetLinks;
|
|
163
|
+
var y = node.y0;
|
|
164
|
+
var y1 = y;
|
|
165
|
+
sourceLinks.forEach(function (link) {
|
|
166
|
+
link.y0 = y + link.width / 2;
|
|
167
|
+
y += link.width;
|
|
168
|
+
});
|
|
169
|
+
targetLinks.forEach(function (link) {
|
|
170
|
+
link.y1 = y1 + link.width / 2;
|
|
171
|
+
y1 += link.width;
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export var calculateSankey = function (options) { return new Sankey(options).calculate(); };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Class,
|
|
3
|
+
deepExtend
|
|
4
|
+
} from '../common';
|
|
5
|
+
|
|
6
|
+
export var SankeyElement = (function (Class) {
|
|
7
|
+
function SankeyElement(options) {
|
|
8
|
+
Class.call(this);
|
|
9
|
+
this.options = deepExtend({}, this.options, options);
|
|
10
|
+
this.createVisual();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if ( Class ) SankeyElement.__proto__ = Class;
|
|
14
|
+
SankeyElement.prototype = Object.create( Class && Class.prototype );
|
|
15
|
+
SankeyElement.prototype.constructor = SankeyElement;
|
|
16
|
+
|
|
17
|
+
SankeyElement.prototype.createVisual = function createVisual () {
|
|
18
|
+
this.visual = this.createElement();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
SankeyElement.prototype.exportVisual = function exportVisual () {
|
|
22
|
+
return this.visual;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
SankeyElement.prototype.createElement = function createElement () {
|
|
26
|
+
var this$1 = this;
|
|
27
|
+
|
|
28
|
+
var customVisual = this.options.visual;
|
|
29
|
+
var visual;
|
|
30
|
+
|
|
31
|
+
if (customVisual) {
|
|
32
|
+
visual = customVisual({
|
|
33
|
+
sender: this.getSender(),
|
|
34
|
+
options: this.visualOptions(),
|
|
35
|
+
createVisual: function () { return this$1.getElement(); }
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
visual = this.getElement();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return visual;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
SankeyElement.prototype.getSender = function getSender () {
|
|
45
|
+
return this;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return SankeyElement;
|
|
49
|
+
}(Class));
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { setDefaultOptions, deepExtend } from '../common';
|
|
2
|
+
import { SankeyElement } from './element';
|
|
3
|
+
import { Box, TextBox } from '../core';
|
|
4
|
+
var INSIDE = 'inside';
|
|
5
|
+
var BEFORE = 'before';
|
|
6
|
+
var AFTER = 'after';
|
|
7
|
+
|
|
8
|
+
export var Label = (function (SankeyElement) {
|
|
9
|
+
function Label () {
|
|
10
|
+
SankeyElement.apply(this, arguments);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if ( SankeyElement ) Label.__proto__ = SankeyElement;
|
|
14
|
+
Label.prototype = Object.create( SankeyElement && SankeyElement.prototype );
|
|
15
|
+
Label.prototype.constructor = Label;
|
|
16
|
+
|
|
17
|
+
Label.prototype.getElement = function getElement () {
|
|
18
|
+
var options = deepExtend({}, this.options, this.options.node.label);
|
|
19
|
+
var node = options.node;
|
|
20
|
+
var totalWidth = options.totalWidth;
|
|
21
|
+
var position = options.position;
|
|
22
|
+
var text = options.text;
|
|
23
|
+
var offset = options.offset;
|
|
24
|
+
|
|
25
|
+
if (!options.visible || !text) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var nodeBox = new Box(node.x0, node.y0, node.x1, node.y1);
|
|
30
|
+
var visualOptions = this.visualOptions();
|
|
31
|
+
var textbox = new TextBox(text, visualOptions);
|
|
32
|
+
textbox.reflow(new Box());
|
|
33
|
+
var textSizeBox = textbox.box;
|
|
34
|
+
|
|
35
|
+
var goesOutside = node.x1 + textSizeBox.width() > totalWidth;
|
|
36
|
+
var textY = nodeBox.center().y - (textSizeBox.height() / 2);
|
|
37
|
+
var side = position === BEFORE || (position === INSIDE && goesOutside) ? BEFORE : AFTER;
|
|
38
|
+
var textOrigin = [side === BEFORE ? node.x0 - textSizeBox.width() : node.x1, textY];
|
|
39
|
+
|
|
40
|
+
var textRect = new Box(textOrigin[0], textOrigin[1], textOrigin[0] + textSizeBox.width(), textOrigin[1] + textSizeBox.height());
|
|
41
|
+
textRect.translate(offset.left || 0, offset.top || 0);
|
|
42
|
+
textbox.reflow(textRect);
|
|
43
|
+
|
|
44
|
+
textbox.renderVisual();
|
|
45
|
+
|
|
46
|
+
return textbox.visual;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
Label.prototype.visualOptions = function visualOptions () {
|
|
50
|
+
var options = deepExtend({}, this.options, this.options.node.label);
|
|
51
|
+
return {
|
|
52
|
+
color: options.color,
|
|
53
|
+
opacity: options.opacity,
|
|
54
|
+
font: options.font,
|
|
55
|
+
border: options.border,
|
|
56
|
+
margin: options.margin,
|
|
57
|
+
padding: options.padding,
|
|
58
|
+
align: options.align,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return Label;
|
|
63
|
+
}(SankeyElement));
|
|
64
|
+
|
|
65
|
+
setDefaultOptions(Label, {
|
|
66
|
+
position: INSIDE, // inside, before, after
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export var resolveLabelOptions = function (node, options, totalWidth) { return deepExtend({},
|
|
70
|
+
options,
|
|
71
|
+
{
|
|
72
|
+
node: node,
|
|
73
|
+
totalWidth: totalWidth,
|
|
74
|
+
visual: node.label.visual,
|
|
75
|
+
visible: node.label.visible,
|
|
76
|
+
margin: node.label.margin,
|
|
77
|
+
padding: node.label.padding,
|
|
78
|
+
border: node.label.border,
|
|
79
|
+
align: node.label.align,
|
|
80
|
+
opacity: node.label.opacity,
|
|
81
|
+
offset: node.label.offset
|
|
82
|
+
}
|
|
83
|
+
); };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { drawing } from '@progress/kendo-drawing';
|
|
2
|
+
import { SankeyElement } from './element';
|
|
3
|
+
import { deepExtend } from '../common';
|
|
4
|
+
import { defined } from '../drawing-utils';
|
|
5
|
+
|
|
6
|
+
export var Link = (function (SankeyElement) {
|
|
7
|
+
function Link () {
|
|
8
|
+
SankeyElement.apply(this, arguments);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if ( SankeyElement ) Link.__proto__ = SankeyElement;
|
|
12
|
+
Link.prototype = Object.create( SankeyElement && SankeyElement.prototype );
|
|
13
|
+
Link.prototype.constructor = Link;
|
|
14
|
+
|
|
15
|
+
Link.prototype.getElement = function getElement () {
|
|
16
|
+
var link = this.options.link;
|
|
17
|
+
var source = link.source;
|
|
18
|
+
var target = link.target;
|
|
19
|
+
var y0 = link.y0;
|
|
20
|
+
var y1 = link.y1;
|
|
21
|
+
var xC = (source.x0 + target.x1) / 2;
|
|
22
|
+
|
|
23
|
+
return new drawing.Path(this.visualOptions())
|
|
24
|
+
.moveTo(source.x1, y0).curveTo([xC, y0], [xC, y1], [target.x0, y1]);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
Link.prototype.visualOptions = function visualOptions () {
|
|
28
|
+
var options = this.options;
|
|
29
|
+
var link = this.options.link;
|
|
30
|
+
return {
|
|
31
|
+
stroke: {
|
|
32
|
+
width: options.link.width,
|
|
33
|
+
color: link.color || options.color,
|
|
34
|
+
opacity: defined(link.opacity) ? link.opacity : options.opacity
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return Link;
|
|
40
|
+
}(SankeyElement));
|
|
41
|
+
|
|
42
|
+
export var resolveLinkOptions = function (link, options, sourceNode, targetNode) {
|
|
43
|
+
var linkOptions = deepExtend({},
|
|
44
|
+
options,
|
|
45
|
+
{
|
|
46
|
+
link: link,
|
|
47
|
+
opacity: link.opacity,
|
|
48
|
+
color: link.color,
|
|
49
|
+
colorType: link.colorType,
|
|
50
|
+
visual: link.visual,
|
|
51
|
+
highlight: link.highlight
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (linkOptions.colorType === 'source') {
|
|
56
|
+
linkOptions.color = sourceNode.options.fill.color;
|
|
57
|
+
} else if (linkOptions.colorType === 'target') {
|
|
58
|
+
linkOptions.color = targetNode.options.fill.color;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return linkOptions;
|
|
62
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { geometry, drawing } from '@progress/kendo-drawing';
|
|
2
|
+
import { SankeyElement } from './element';
|
|
3
|
+
import { deepExtend } from '../common';
|
|
4
|
+
|
|
5
|
+
export var Node = (function (SankeyElement) {
|
|
6
|
+
function Node () {
|
|
7
|
+
SankeyElement.apply(this, arguments);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if ( SankeyElement ) Node.__proto__ = SankeyElement;
|
|
11
|
+
Node.prototype = Object.create( SankeyElement && SankeyElement.prototype );
|
|
12
|
+
Node.prototype.constructor = Node;
|
|
13
|
+
|
|
14
|
+
Node.prototype.getElement = function getElement () {
|
|
15
|
+
var options = this.options;
|
|
16
|
+
var node = options.node;
|
|
17
|
+
var rect = new geometry.Rect([node.x0, node.y0], [node.x1 - node.x0, node.y1 - node.y0]);
|
|
18
|
+
|
|
19
|
+
return drawing.Path.fromRect(rect, this.visualOptions());
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
Node.prototype.visualOptions = function visualOptions () {
|
|
23
|
+
var options = deepExtend({}, this.options, this.options.node);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
fill: {
|
|
27
|
+
color: options.color,
|
|
28
|
+
opacity: options.opacity
|
|
29
|
+
},
|
|
30
|
+
stroke: { width: 0 },
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return Node;
|
|
35
|
+
}(SankeyElement));
|
|
36
|
+
|
|
37
|
+
export var resolveNodeOptions = function (node, options, nodesColors, index) {
|
|
38
|
+
var nodeOptions = deepExtend({}, options, options.node);
|
|
39
|
+
return deepExtend({},
|
|
40
|
+
{ color: nodesColors[index % nodesColors.length] },
|
|
41
|
+
nodeOptions,
|
|
42
|
+
{ node: node },
|
|
43
|
+
{
|
|
44
|
+
visual: node.visual,
|
|
45
|
+
opacity: node.opacity,
|
|
46
|
+
offset: node.offset,
|
|
47
|
+
color: node.color
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
};
|