@progress/kendo-charts 2.2.0-dev.202401301155 → 2.2.0-dev.202402121742

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.
@@ -9,7 +9,7 @@ import { BAR, OUTSIDE_END, INSIDE_END } from '../constants';
9
9
 
10
10
  import anyHasZIndex from '../utils/any-has-z-index';
11
11
 
12
- import { STRING, X, Y } from '../../common/constants';
12
+ import { OBJECT, STRING, X, Y } from '../../common/constants';
13
13
  import { defined, isFunction, setDefaultOptions } from '../../common';
14
14
 
15
15
  var BarChart = (function (CategoricalChart) {
@@ -101,7 +101,7 @@ var BarChart = (function (CategoricalChart) {
101
101
  };
102
102
 
103
103
  BarChart.prototype.getStackWrap = function getStackWrap (stack, cluster) {
104
- var stackGroup = stack ? stack.group || stack : stack;
104
+ var stackGroup = (typeof stack === OBJECT) ? (stack.group || true) : stack;
105
105
  var wraps = cluster.children;
106
106
  var stackWrap;
107
107
 
@@ -7,7 +7,7 @@ import { evalOptions, categoriesCount } from './utils';
7
7
 
8
8
  import { ChartElement, Box } from '../core';
9
9
 
10
- import { VALUE, STRING, MIN_VALUE, MAX_VALUE } from '../common/constants';
10
+ import { VALUE, STRING, MIN_VALUE, MAX_VALUE, OBJECT } from '../common/constants';
11
11
  import { convertableToNumber, deepExtend, defined, isNumber, last, setDefaultOptions, sparseArrayLimits } from '../common';
12
12
 
13
13
  var CategoricalChart = (function (ChartElement) {
@@ -99,6 +99,7 @@ var CategoricalChart = (function (ChartElement) {
99
99
  var prevValue = startValue;
100
100
  var isStackedBar = false;
101
101
  var stack = defined(point.series.stack) ? point.series.stack : this.options.defaultStack;
102
+ var isNonGroupStack = function (stack) { return stack === true || typeof stack === OBJECT && !stack.group; };
102
103
 
103
104
  if (stack) {
104
105
  for (var i = 0; i < categoryPoints.length; i++) {
@@ -118,7 +119,7 @@ var CategoricalChart = (function (ChartElement) {
118
119
  continue;
119
120
  }
120
121
 
121
- if (stack === true && otherStack !== true) {
122
+ if (isNonGroupStack(stack) && !isNonGroupStack(otherStack)) {
122
123
  continue;
123
124
  }
124
125
 
@@ -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
+ });
@@ -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[index % nodesColors.length] },
42
+ { color: nodeColor(node, nodesColors, index) },
41
43
  nodeOptions,
42
44
  { node: node },
43
45
  {
@@ -1,14 +1,15 @@
1
1
  import { drawing } from '@progress/kendo-drawing';
2
- import { deepExtend, addClass, setDefaultOptions, getSpacing } from '../common';
2
+ import { deepExtend, addClass, setDefaultOptions } from '../common';
3
3
  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
7
  import { Title } from './title';
8
- import { CENTER, LEFT, TOP } from '../common/constants';
8
+ import { BOTTOM, LEFT, RIGHT, TOP } from '../common/constants';
9
9
  import Box from '../core/box';
10
10
  import rectToBox from '../core/utils/rect-to-box';
11
11
  import { Observable } from '../common/observable';
12
+ import { Legend } from './legend';
12
13
 
13
14
  var LINK = 'link';
14
15
  var NODE = 'node';
@@ -104,11 +105,10 @@ export var Sankey = (function (Observable) {
104
105
  };
105
106
 
106
107
  Sankey.prototype._mouseenter = function _mouseenter (ev) {
107
- var this$1 = this;
108
-
109
108
  var element = ev.element;
110
109
  var isLink = element.type === LINK;
111
110
  var isNode = element.type === NODE;
111
+ var isLegendItem = Boolean(element.chartElement && element.chartElement.options.node);
112
112
 
113
113
  if ((isLink && this.trigger('linkEnter', ev)) ||
114
114
  (isNode && this.trigger('nodeEnter', ev))) {
@@ -121,10 +121,10 @@ export var Sankey = (function (Observable) {
121
121
  this.setLinksOpacity(highlight.inactiveOpacity);
122
122
  this.setOpacity(element, highlight.opacity);
123
123
  } else if (isNode) {
124
- this.setLinksOpacity(highlight.inactiveOpacity);
125
- element.links.forEach(function (link) {
126
- this$1.setOpacity(link, highlight.opacity);
127
- });
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);
128
128
  }
129
129
  };
130
130
 
@@ -132,6 +132,7 @@ export var Sankey = (function (Observable) {
132
132
  var element = ev.element;
133
133
  var isLink = element.type === LINK;
134
134
  var isNode = element.type === NODE;
135
+ var isLegendItem = Boolean(element.chartElement && element.chartElement.options.node);
135
136
  var target = ev.originalEvent.relatedTarget;
136
137
 
137
138
  if (isLink && target && target.nodeName === 'text') {
@@ -143,11 +144,22 @@ export var Sankey = (function (Observable) {
143
144
  return;
144
145
  }
145
146
 
146
- if (isLink || isNode) {
147
+ if (isLink || isNode || isLegendItem) {
147
148
  this.setLinksOpacity(this.options.links.opacity);
148
149
  }
149
150
  };
150
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
+
151
163
  Sankey.prototype._destroySurface = function _destroySurface () {
152
164
  if (this.surface) {
153
165
  this.surface.destroy();
@@ -206,25 +218,74 @@ export var Sankey = (function (Observable) {
206
218
  this.visual = this._render();
207
219
  };
208
220
 
209
- Sankey.prototype.titleHeight = function titleHeight (title, totalWidth) {
210
- if (!title.visible || !title.text) {
211
- return 0;
221
+ Sankey.prototype.titleBox = function titleBox (title, drawingRect) {
222
+ if (!title || title.visible === false || !title.text) {
223
+ return null;
212
224
  }
213
225
 
214
- var titleElement = new Title(deepExtend({}, { totalWidth: totalWidth }, title));
226
+ var titleElement = new Title(Object.assign({}, {drawingRect: drawingRect}, title));
215
227
  var titleVisual = titleElement.exportVisual();
216
- return titleVisual.chartElement.box.height();
228
+ return titleVisual.chartElement.box;
217
229
  };
218
230
 
219
- Sankey.prototype.calculateSankey = function calculateSankey$1 (options) {
220
- var title = this.options.title;
221
- var titleHeight = this.titleHeight(title, options.width);
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
+ };
222
241
 
242
+ Sankey.prototype.calculateSankey = function calculateSankey$1 (options) {
223
243
  var ref = this.options;
224
- var nodes = ref.nodes;
225
- var labels = ref.labels;
226
- var nodesColors = ref.nodesColors;
227
- var calculatedNodes = calculateSankey(Object.assign({}, options, {offsetX: 0, offsetY: titleHeight})).nodes;
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;
228
289
  var box = new Box();
229
290
 
230
291
  calculatedNodes.forEach(function (nodeEl, i) {
@@ -239,16 +300,17 @@ export var Sankey = (function (Observable) {
239
300
  }
240
301
  });
241
302
 
242
- var offsetX = box.x1 < 0 ? -box.x1 : 0;
243
- 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;
244
305
 
245
- var width = box.width() > options.width ? offsetX + options.width - (box.width() - options.width) : options.width;
246
- var height = box.height() > options.height ? offsetY + options.height - (box.height() - options.height) : options.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;
247
308
 
248
- height -= titleHeight;
249
- offsetY += title.position === TOP ? titleHeight : 0;
250
-
251
- return calculateSankey(Object.assign({}, options, {width: width, height: height, offsetX: offsetX, offsetY: offsetY}));
309
+ return {
310
+ sankey: calculateSankey(Object.assign({}, options, {offsetX: offsetX, offsetY: offsetY, width: width, height: height})),
311
+ legendBox: legendBox,
312
+ titleBox: titleBox
313
+ };
252
314
  };
253
315
 
254
316
  Sankey.prototype._render = function _render () {
@@ -259,22 +321,32 @@ export var Sankey = (function (Observable) {
259
321
  var linkOptions = ref.links;
260
322
  var nodesColors = ref.nodesColors;
261
323
  var title = ref.title;
324
+ var legend = ref.legend;
262
325
  var ref$1 = this.size;
263
326
  var width = ref$1.width;
264
327
  var height = ref$1.height;
265
- var calcOptions = Object.assign({}, data, {width: width, height: height, nodesOptions: nodesOptions, title: title});
328
+ var calcOptions = Object.assign({}, data, {width: width, height: height, nodesOptions: nodesOptions, title: title, legend: legend});
266
329
  var ref$2 = this.calculateSankey(calcOptions);
267
- var nodes = ref$2.nodes;
268
- var links = ref$2.links;
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;
269
335
 
270
336
  var visual = new drawing.Group();
271
337
 
272
- if (title.visible && title.text) {
273
- var titleElement = new Title(deepExtend({}, { wrapWidth: width, wrapHeight: height }, title));
338
+ if (titleBox) {
339
+ var titleElement = new Title(Object.assign({}, title, {drawingRect: titleBox}));
274
340
  var titleVisual = titleElement.exportVisual();
275
341
  visual.append(titleVisual);
276
342
  }
277
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
+
278
350
  var visualNodes = new Map();
279
351
 
280
352
  nodes.forEach(function (node, i) {
@@ -289,11 +361,11 @@ export var Sankey = (function (Observable) {
289
361
  visual.append(nodeVisual);
290
362
  });
291
363
 
292
- links = links.slice().sort(function (a, b) { return b.value - a.value; });
364
+ var sortedLinks = links.slice().sort(function (a, b) { return b.value - a.value; });
293
365
 
294
366
  var linksVisuals = [];
295
367
 
296
- links.forEach(function (link) {
368
+ sortedLinks.forEach(function (link) {
297
369
  var source = link.source;
298
370
  var target = link.target;
299
371
  var sourceNode = visualNodes.get(source.id);
@@ -312,6 +384,7 @@ export var Sankey = (function (Observable) {
312
384
  });
313
385
 
314
386
  this.linksVisuals = linksVisuals;
387
+ this.nodesVisuals = visualNodes;
315
388
 
316
389
  nodes.forEach(function (node) {
317
390
  var textOps = resolveLabelOptions(node, labelOptions, width);
@@ -365,16 +438,5 @@ setDefaultOptions(Sankey, {
365
438
  opacity: 0.8,
366
439
  inactiveOpacity: 0.2
367
440
  }
368
- },
369
- title: {
370
- visible: true,
371
- position: TOP,
372
- align: CENTER,
373
- opacity: 1,
374
- border: {
375
- width: 0
376
- },
377
- margin: getSpacing(5),
378
- padding: getSpacing(5)
379
- },
441
+ }
380
442
  });
@@ -1,9 +1,7 @@
1
+ import { Title as ChartTitle } from "../core";
1
2
  import { SankeyElement } from "./element";
2
- import { Title as CoreTitle } from "../core";
3
- import Box from "../core/box";
4
- import { deepExtend } from "../common";
5
- import { BOTTOM } from "../common/constants";
6
- import { getSpacing } from "../common";
3
+ import { setDefaultOptions, getSpacing } from '../common';
4
+ import { CENTER, TOP } from "../common/constants";
7
5
 
8
6
  export var Title = (function (SankeyElement) {
9
7
  function Title () {
@@ -15,25 +13,17 @@ export var Title = (function (SankeyElement) {
15
13
  Title.prototype.constructor = Title;
16
14
 
17
15
  Title.prototype.getElement = function getElement () {
18
- var options = deepExtend({}, this.options, this.options.title);
19
- var wrapWidth = options.wrapWidth;
20
- var wrapHeight = options.wrapHeight;
16
+ var options = this.options;
17
+ var drawingRect = options.drawingRect;
21
18
  var text = options.text;
22
- var border = options.border;
23
- var padding = getSpacing(options.padding);
24
- var margin = getSpacing(options.margin);
25
19
 
26
- if (!options.visible || !text) {
20
+ if (options.visible === false || !text) {
27
21
  return null;
28
22
  }
29
23
 
30
- var title = CoreTitle.buildTitle(text, options);
31
- var titleSizeBox = title.children[0].container.box;
32
- var totalTitleHeight = margin.top + border.width + padding.top + titleSizeBox.height() + padding.bottom + border.width + margin.bottom;
33
- var offsetTop = options.position === BOTTOM ? wrapHeight - totalTitleHeight : 0;
34
- var titleRect = new Box(0, offsetTop, wrapWidth, offsetTop + totalTitleHeight);
24
+ var title = ChartTitle.buildTitle(text, options);
35
25
 
36
- title.reflow(titleRect);
26
+ title.reflow(drawingRect);
37
27
 
38
28
  title.renderVisual();
39
29
  return title.visual;
@@ -45,3 +35,14 @@ export var Title = (function (SankeyElement) {
45
35
 
46
36
  return Title;
47
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
+ });
@@ -9,7 +9,7 @@ import { BAR, OUTSIDE_END, INSIDE_END } from '../constants';
9
9
 
10
10
  import anyHasZIndex from '../utils/any-has-z-index';
11
11
 
12
- import { STRING, X, Y } from '../../common/constants';
12
+ import { OBJECT, STRING, X, Y } from '../../common/constants';
13
13
  import { defined, isFunction, setDefaultOptions } from '../../common';
14
14
 
15
15
  class BarChart extends CategoricalChart {
@@ -90,7 +90,7 @@ class BarChart extends CategoricalChart {
90
90
  }
91
91
 
92
92
  getStackWrap(stack, cluster) {
93
- const stackGroup = stack ? stack.group || stack : stack;
93
+ const stackGroup = (typeof stack === OBJECT) ? (stack.group || true) : stack;
94
94
  const wraps = cluster.children;
95
95
  let stackWrap;
96
96
 
@@ -7,7 +7,7 @@ import { evalOptions, categoriesCount } from './utils';
7
7
 
8
8
  import { ChartElement, Box } from '../core';
9
9
 
10
- import { VALUE, STRING, MIN_VALUE, MAX_VALUE } from '../common/constants';
10
+ import { VALUE, STRING, MIN_VALUE, MAX_VALUE, OBJECT } from '../common/constants';
11
11
  import { convertableToNumber, deepExtend, defined, isNumber, last, setDefaultOptions, sparseArrayLimits } from '../common';
12
12
 
13
13
  class CategoricalChart extends ChartElement {
@@ -92,6 +92,7 @@ class CategoricalChart extends ChartElement {
92
92
  let prevValue = startValue;
93
93
  let isStackedBar = false;
94
94
  const stack = defined(point.series.stack) ? point.series.stack : this.options.defaultStack;
95
+ const isNonGroupStack = (stack) => stack === true || typeof stack === OBJECT && !stack.group;
95
96
 
96
97
  if (stack) {
97
98
  for (let i = 0; i < categoryPoints.length; i++) {
@@ -111,7 +112,7 @@ class CategoricalChart extends ChartElement {
111
112
  continue;
112
113
  }
113
114
 
114
- if (stack === true && otherStack !== true) {
115
+ if (isNonGroupStack(stack) && !isNonGroupStack(otherStack)) {
115
116
  continue;
116
117
  }
117
118
 
@@ -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[index % nodesColors.length] },
32
+ { color: nodeColor(node, nodesColors, index) },
31
33
  nodeOptions,
32
34
  { node },
33
35
  {