@syncfusion/ej2-treemap 30.2.4 → 31.1.17

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.
Files changed (47) hide show
  1. package/dist/ej2-treemap.min.js +2 -2
  2. package/dist/ej2-treemap.umd.min.js +2 -2
  3. package/dist/ej2-treemap.umd.min.js.map +1 -1
  4. package/dist/es6/ej2-treemap.es2015.js +0 -4
  5. package/dist/es6/ej2-treemap.es2015.js.map +1 -1
  6. package/dist/es6/ej2-treemap.es5.js +0 -4
  7. package/dist/es6/ej2-treemap.es5.js.map +1 -1
  8. package/dist/global/ej2-treemap.min.js +2 -2
  9. package/dist/global/ej2-treemap.min.js.map +1 -1
  10. package/dist/global/index.d.ts +1 -1
  11. package/dist/ts/index.d.ts +4 -0
  12. package/dist/ts/index.ts +4 -0
  13. package/dist/ts/treemap/index.d.ts +19 -0
  14. package/dist/ts/treemap/index.ts +19 -0
  15. package/dist/ts/treemap/layout/legend.d.ts +137 -0
  16. package/dist/ts/treemap/layout/legend.ts +1095 -0
  17. package/dist/ts/treemap/layout/render-panel.d.ts +47 -0
  18. package/dist/ts/treemap/layout/render-panel.ts +758 -0
  19. package/dist/ts/treemap/model/base-model.d.ts +795 -0
  20. package/dist/ts/treemap/model/base.d.ts +671 -0
  21. package/dist/ts/treemap/model/base.ts +798 -0
  22. package/dist/ts/treemap/model/constants.d.ts +117 -0
  23. package/dist/ts/treemap/model/constants.ts +118 -0
  24. package/dist/ts/treemap/model/image-export.d.ts +34 -0
  25. package/dist/ts/treemap/model/image-export.ts +117 -0
  26. package/dist/ts/treemap/model/interface.d.ts +555 -0
  27. package/dist/ts/treemap/model/interface.ts +583 -0
  28. package/dist/ts/treemap/model/pdf-export.d.ts +36 -0
  29. package/dist/ts/treemap/model/pdf-export.ts +105 -0
  30. package/dist/ts/treemap/model/print.d.ts +45 -0
  31. package/dist/ts/treemap/model/print.ts +106 -0
  32. package/dist/ts/treemap/model/theme.d.ts +19 -0
  33. package/dist/ts/treemap/model/theme.ts +450 -0
  34. package/dist/ts/treemap/treemap-model.d.ts +374 -0
  35. package/dist/ts/treemap/treemap.d.ts +724 -0
  36. package/dist/ts/treemap/treemap.ts +1817 -0
  37. package/dist/ts/treemap/user-interaction/highlight-selection.d.ts +118 -0
  38. package/dist/ts/treemap/user-interaction/highlight-selection.ts +799 -0
  39. package/dist/ts/treemap/user-interaction/tooltip.d.ts +42 -0
  40. package/dist/ts/treemap/user-interaction/tooltip.ts +228 -0
  41. package/dist/ts/treemap/utils/enum.d.ts +256 -0
  42. package/dist/ts/treemap/utils/enum.ts +263 -0
  43. package/dist/ts/treemap/utils/helper.d.ts +543 -0
  44. package/dist/ts/treemap/utils/helper.ts +1453 -0
  45. package/package.json +52 -17
  46. package/src/treemap/treemap.d.ts +0 -1
  47. package/src/treemap/treemap.js +0 -4
@@ -0,0 +1,1453 @@
1
+
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import { BorderModel, FontModel, ColorMappingModel, LeafItemSettingsModel } from '../model/base-model';
4
+ import { createElement, compile, merge, isNullOrUndefined, remove, SanitizeHtmlHelper } from '@syncfusion/ej2-base';
5
+ import { SvgRenderer } from '@syncfusion/ej2-svg-base';
6
+ import { Alignment, LabelPosition } from '../utils/enum';
7
+ import { TreeMap } from '../treemap';
8
+ import { IShapes } from '../model/interface';
9
+ import { ExportType } from '../utils/enum';
10
+ /**
11
+ * Specifies the size parameters.
12
+ */
13
+ export class Size {
14
+ /**
15
+ * Defines the height in the size object.
16
+ */
17
+ public height: number;
18
+ /**
19
+ * Defines the width in the size object.
20
+ */
21
+ public width: number;
22
+ constructor(width: number, height: number) {
23
+ this.width = width;
24
+ this.height = height;
25
+ }
26
+ }
27
+ /**
28
+ *
29
+ * @param {string} value - specifies the text.
30
+ * @param {number} containerSize - specifies the container size value.
31
+ * @returns {number} - Returns the number value which is converted from string.
32
+ */
33
+ export function stringToNumber(value: string, containerSize: number): number {
34
+ if (value !== null && value !== undefined) {
35
+ return value.indexOf('%') !== -1 ? (containerSize / 100) * parseInt(value, 10) : parseInt(value, 10);
36
+ }
37
+ return null;
38
+ }
39
+
40
+ /**
41
+ * Internal use of type rect
42
+ *
43
+ * @private
44
+ */
45
+ export class Rect {
46
+ public x: number;
47
+ public y: number;
48
+ public height: number;
49
+ public width: number;
50
+ constructor(x: number, y: number, width: number, height: number) {
51
+ this.x = x;
52
+ this.y = y;
53
+ this.width = width;
54
+ this.height = height;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Internal use of rectangle options
60
+ *
61
+ * @private
62
+ */
63
+ export class RectOption {
64
+ public id: string;
65
+ public fill: string;
66
+ public x: number;
67
+ public y: number;
68
+ public height: number;
69
+ public width: number;
70
+ public opacity: number;
71
+ public stroke: string;
72
+ public ['stroke-width']: number;
73
+ public ['stroke-dasharray']: string;
74
+ constructor(
75
+ id: string, fill: string, border: BorderModel, opacity: number, rect: Rect, dashArray?: string
76
+ ) {
77
+ this.y = rect.y;
78
+ this.x = rect.x;
79
+ this.height = rect.height;
80
+ this.width = rect.width;
81
+ this.id = id;
82
+ this.fill = fill;
83
+ this.opacity = opacity;
84
+ this.stroke = border.color;
85
+ this['stroke-width'] = border.width;
86
+ this['stroke-dasharray'] = dashArray;
87
+ }
88
+ }
89
+
90
+ export class PathOption {
91
+ public id: string;
92
+ public opacity: number;
93
+ public fill: string;
94
+ public stroke: string;
95
+ public ['stroke-width']: number;
96
+ public ['stroke-dasharray']: string;
97
+ public d: string;
98
+ constructor(
99
+ id: string, fill: string, width: number, color: string, opacity?: number,
100
+ dashArray?: string, d?: string
101
+ ) {
102
+ this.id = id;
103
+ this.opacity = opacity;
104
+ this.fill = fill;
105
+ this.stroke = color;
106
+ this['stroke-width'] = width;
107
+ this['stroke-dasharray'] = dashArray;
108
+ this.d = d;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Function to measure the height and width of the text.
114
+ *
115
+ * @param {string} text - Specifies the text.
116
+ * @param {FontModel} font - Specifies the font.
117
+ * @returns {Size} - Returns the size.
118
+ * @private
119
+ */
120
+ export function measureText(text: string, font: FontModel): Size {
121
+ let measureObject: HTMLElement = document.getElementById('treeMapMeasureText');
122
+ if (measureObject === null) {
123
+ measureObject = createElement('text', { id: 'treeMapMeasureText' });
124
+ document.body.appendChild(measureObject);
125
+ }
126
+ measureObject.innerHTML = SanitizeHtmlHelper.sanitize(text);
127
+ measureObject.style.position = 'absolute';
128
+ measureObject.style.fontSize = font.size;
129
+ measureObject.style.fontWeight = font.fontWeight;
130
+ measureObject.style.fontStyle = font.fontStyle;
131
+ measureObject.style.fontFamily = font.fontFamily;
132
+ measureObject.style.visibility = 'hidden';
133
+ measureObject.style.top = '-100';
134
+ measureObject.style.left = '0';
135
+ measureObject.style.whiteSpace = 'nowrap';
136
+ // For bootstrap line height issue
137
+ measureObject.style.lineHeight = 'normal';
138
+ return new Size(measureObject.clientWidth, measureObject.clientHeight);
139
+ }
140
+
141
+ /**
142
+ * Internal use of text options
143
+ *
144
+ * @private
145
+ */
146
+ export class TextOption {
147
+ public anchor: string;
148
+ public id: string;
149
+ public transform: string = '';
150
+ public x: number;
151
+ public y: number;
152
+ public text: string | string[];
153
+ public baseLine: string = 'auto';
154
+ public connectorText: string;
155
+ constructor(
156
+ id?: string, x?: number, y?: number, anchor?: string, text?: string | string[], transform: string = '',
157
+ baseLine?: string, connectorText?: string
158
+ ) {
159
+ this.id = id;
160
+ this.text = text;
161
+ this.transform = transform;
162
+ this.anchor = anchor;
163
+ this.x = x;
164
+ this.y = y;
165
+ this.baseLine = baseLine;
166
+ this.connectorText = connectorText;
167
+ }
168
+ }
169
+
170
+
171
+ /**
172
+ * Trim the title text
173
+ *
174
+ * @param {number} maxWidth - Specifies the maximum width
175
+ * @param {string} text - Specifies the text
176
+ * @param {FontModel} font - Specifies the font
177
+ * @returns {string} - Returns the string
178
+ * @private
179
+ */
180
+ export function textTrim(maxWidth: number, text: string, font: FontModel): string {
181
+ let label: string = text;
182
+ let size: number = measureText(text, font).width;
183
+ if (size > maxWidth) {
184
+ const textLength: number = text.length;
185
+ for (let i: number = textLength - 1; i >= 0; --i) {
186
+ label = text.substring(0, i) + '...';
187
+ size = measureText(label, font).width;
188
+ if (size <= maxWidth || label.length < 4) {
189
+ if (label.length < 4) {
190
+ label = ' ';
191
+ }
192
+ return label;
193
+ }
194
+ }
195
+ }
196
+ return label;
197
+ }
198
+
199
+ /**
200
+ * Specifies the location parameters.
201
+ */
202
+
203
+ export class Location {
204
+ /**
205
+ * Defines the horizontal position.
206
+ */
207
+ public x: number;
208
+ /**
209
+ * Defines the vertical position.
210
+ */
211
+ public y: number;
212
+ constructor(x: number, y: number) {
213
+ this.x = x;
214
+ this.y = y;
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Method to calculate x position of title
220
+ *
221
+ * @param {Rect} location - Specifies the location of text.
222
+ * @param {Alignment} alignment - Specifies the alignment of the text.
223
+ * @param {Size} textSize - Specifies the size of the text.
224
+ * @param {type} type - Specifies whether the provided text is title or subtitle.
225
+ * @returns {Location} - Returns the location of text.
226
+ * @private
227
+ */
228
+ export function findPosition(location: Rect, alignment: Alignment, textSize: Size, type: string): Location {
229
+ let x: number;
230
+ switch (alignment) {
231
+ case 'Near':
232
+ x = location.x;
233
+ break;
234
+ case 'Center':
235
+ x = (type === 'title') ? (location.width / 2 - textSize.width / 2) :
236
+ ((location.x + (location.width / 2)) - textSize.width / 2);
237
+ break;
238
+ case 'Far':
239
+ x = (type === 'title') ? (location.width - location.y - textSize.width) :
240
+ ((location.x + location.width) - textSize.width);
241
+ break;
242
+ }
243
+ const y: number = (type === 'title') ? location.y + (textSize.height / 2) : ((location.y + location.height / 2) + textSize.height / 2);
244
+ return new Location(x, y);
245
+ }
246
+
247
+ /**
248
+ *
249
+ * @param {SvgRenderer} renderer - Specifies the rendering element of the SVG.
250
+ * @param {any} renderOptions - Specifies the settings of the text.
251
+ * @param {string} text - Specifies the text.
252
+ * @returns {HTMLElement} - Returns the HTML element for the text.
253
+ */
254
+ export function createTextStyle(
255
+ renderer: SvgRenderer, renderOptions: any, text: string
256
+ ): HTMLElement {
257
+ const htmlObject: HTMLElement = <HTMLElement>renderer.createText(renderOptions, text);
258
+ htmlObject.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
259
+ htmlObject.style['user-select'] = 'none';
260
+ htmlObject.style['-moz-user-select'] = 'none';
261
+ htmlObject.style['-webkit-touch-callout'] = 'none';
262
+ htmlObject.style['-webkit-user-select'] = 'none';
263
+ htmlObject.style['-khtml-user-select'] = 'none';
264
+ htmlObject.style['-ms-user-select'] = 'none';
265
+ htmlObject.style['-o-user-select'] = 'none';
266
+ return htmlObject;
267
+ }
268
+
269
+ /**
270
+ * Internal rendering of text
271
+ *
272
+ * @param {TextOption} options - Specifies the text option
273
+ * @param {FontModel} font - Specifies the font model
274
+ * @param {string} color - Specifies the color
275
+ * @param {HTMLElement | Element} parent - Specifies the parent element of the text
276
+ * @param {boolean} isMinus - Specifies the boolean value
277
+ * @returns {Element} - Returns the element
278
+ * @private
279
+ */
280
+ export function renderTextElement(
281
+ options: TextOption, font: FontModel, color: string, parent: HTMLElement | Element, isMinus: boolean = false
282
+ ): Element {
283
+ const renderOptions: any = {
284
+ 'font-size': font.size,
285
+ 'font-style': font.fontStyle,
286
+ 'font-family': font.fontFamily,
287
+ 'font-weight': font.fontWeight,
288
+ 'text-anchor': options.anchor,
289
+ 'transform': options.transform,
290
+ 'opacity': font.opacity,
291
+ 'dominant-baseline': options.baseLine,
292
+ 'id': options.id,
293
+ 'x': options.x,
294
+ 'y': options.y,
295
+ 'fill': color
296
+ };
297
+ const text: string = typeof options.text === 'string' ? options.text : isMinus ? options.text[options.text.length - 1] : options.text[0];
298
+ let tspanElement: Element;
299
+ const renderer: SvgRenderer = new SvgRenderer('');
300
+ let height: number; let htmlObject: HTMLElement;
301
+ const breadCrumbText: boolean = !isNullOrUndefined(text) && !isNullOrUndefined(options.connectorText) ?
302
+ (text.includes(options.connectorText[1])) : false;
303
+ if (breadCrumbText) {
304
+ const drilledLabel: string = text;
305
+ const spacing: number = 5;
306
+ const drillLevelText: string[] = drilledLabel.split('#');
307
+ for (let z: number = 0; z < drillLevelText.length; z++) {
308
+ let drillText: string = (drillLevelText[z as number].search(options.connectorText) !== -1 &&
309
+ !isNullOrUndefined(options.connectorText)) ?
310
+ options.connectorText : drillLevelText[z as number];
311
+ renderOptions['id'] = options.id + '_' + z;
312
+ htmlObject = createTextStyle(renderer, renderOptions, drillText);
313
+ if (z % 2 === 0 && z !== 0) {
314
+ const re: RegExp = /\s+/g;
315
+ drillText = drillText.replace(re, '&nbsp');
316
+ }
317
+ const size: Size = measureText(drillText, font);
318
+ renderOptions['x'] = z !== 0 ? renderOptions['x'] + size.width : renderOptions['x'] + size.width + spacing;
319
+ parent.appendChild(htmlObject);
320
+ }
321
+ } else {
322
+ htmlObject = createTextStyle(renderer, renderOptions, text);
323
+ parent.appendChild(htmlObject);
324
+ }
325
+ if (typeof options.text !== 'string' && options.text.length > 1) {
326
+ for (let i: number = 1, len: number = options.text.length; i < len; i++) {
327
+ height = (measureText(options.text[i as number], font).height);
328
+ tspanElement = renderer.createTSpan(
329
+ {
330
+ 'x': options.x, 'id': options.id,
331
+ 'y': (options.y) + (i * height)
332
+ },
333
+ options.text[i as number]);
334
+ htmlObject.appendChild(tspanElement);
335
+ }
336
+ parent.appendChild(htmlObject);
337
+ }
338
+ return htmlObject;
339
+ }
340
+
341
+ /**
342
+ *
343
+ * @param {string} targetId - Specifies the id of the element to which template is to be appended.
344
+ * @param {Element} targetElement - Specifies the element to which template is to be appended.
345
+ * @param {string} contentItemTemplate - Specifies the content to be appended as template.
346
+ * @returns {void}
347
+ */
348
+ export function setItemTemplateContent(targetId: string, targetElement: Element, contentItemTemplate: string): void {
349
+ const itemSelect: string = targetId.split('_RectPath')[0];
350
+ let itemTemplate: Element;
351
+ if (targetId.indexOf('_LabelTemplate') > -1) {
352
+ itemTemplate = targetElement;
353
+ } else {
354
+ itemTemplate = document.querySelector('#' + itemSelect + '_LabelTemplate');
355
+ }
356
+ if (!isNullOrUndefined(itemTemplate)) {
357
+ itemTemplate.innerHTML = contentItemTemplate;
358
+ }
359
+ }
360
+
361
+ /**
362
+ *
363
+ * @param {string} id - Specifies the id of the element.
364
+ * @returns {Element} - Returns the element.
365
+ */
366
+ export function getElement(id: string): Element {
367
+ return document.getElementById(id);
368
+ }
369
+ /**
370
+ *
371
+ * @param {any} a - Specifies the first order of TreeMap leaf elements.
372
+ * @param {any} b - Specifies the second order of TreeMap leaf elements.
373
+ * @returns {number} - Returns the order of the TreeMap leaf element.
374
+ */
375
+ export function itemsToOrder(a: any, b: any): number {
376
+ return a['weight'] === b['weight'] ? 0 : a['weight'] < b['weight'] ? 1 : -1;
377
+ }
378
+
379
+ /**
380
+ *
381
+ * @param {string[]} source - Specifies the data from the data source.
382
+ * @param {string} pathName - Specifies the path name in the data source.
383
+ * @param {any} processData - Specifies the data source object.
384
+ * @param {TreeMap} treemap - Specifies the treemap instance.
385
+ * @returns {boolean} - Specifies whether data is available in the data source or not.
386
+ */
387
+ export function isContainsData(source: string[], pathName: string, processData: any, treemap: TreeMap): boolean {
388
+ let isExist: boolean = false; let name: string = ''; let path: string;
389
+ const leaf: LeafItemSettingsModel = treemap.leafItemSettings; for (let i: number = 0; i < source.length; i++) {
390
+ path = treemap.levels[i as number] ? treemap.levels[i as number].groupPath : leaf.labelPath ? leaf.labelPath :
391
+ treemap.weightValuePath;
392
+ const data: string = processData[path as string] || 'undefined';
393
+ if (source[i as number] === data) {
394
+ name += data + (i === source.length - 1 ? '' : '#');
395
+ if (name === pathName) {
396
+ isExist = true;
397
+ break;
398
+ }
399
+ }
400
+ }
401
+ return isExist;
402
+ }
403
+
404
+ /**
405
+ *
406
+ * @param {any} data - Specifies the data to which the children elements to be found.
407
+ * @returns {any} - Returns the children elements of the TreeMap leaf element.
408
+ */
409
+ export function findChildren(data: any): any {
410
+ let children: any;
411
+ if (data) {
412
+ const keys: string[] = Object.keys(data);
413
+ children = {};
414
+ for (let i: number = 0; i < keys.length; i++) {
415
+ if (data[keys[i as number]] instanceof Array) {
416
+ children['values'] = data[keys[i as number]];
417
+ children['key'] = keys[i as number];
418
+ break;
419
+ }
420
+ }
421
+ }
422
+ return children;
423
+ }
424
+
425
+ /**
426
+ *
427
+ * @param {any} data - Specifies the data to which highlight must be done.
428
+ * @param {items} items - Specifies the data source items.
429
+ * @param {string} mode - Specifies the mode of highlight.
430
+ * @param {TreeMap} treeMap - Specifies the treemap instance.
431
+ * @returns {string[]} - Returns the highlighted items.
432
+ */
433
+ export function findHightLightItems(data: any, items: string[], mode: string, treeMap: TreeMap): string[] {
434
+ if (mode === 'Child') {
435
+ items.push(data['levelOrderName']);
436
+ const children: any[] = findChildren(data)['values'];
437
+ if (children && children.length > 0) {
438
+ for (let i: number = 0; i < children.length; i++) {
439
+ if (items.indexOf(children[i as number]['levelOrderName']) === -1) {
440
+ items.push(children[i as number]['levelOrderName']);
441
+ }
442
+ }
443
+ for (let j: number = 0; j < children.length; j++) {
444
+ findHightLightItems(children[j as number], items, mode, treeMap);
445
+ }
446
+ }
447
+ } else if (mode === 'Parent') {
448
+ if (typeof data['levelOrderName'] === 'string' && items.indexOf(data['levelOrderName']) === -1) {
449
+ items.push(data['levelOrderName']);
450
+ findHightLightItems(data['parent'], items, mode, treeMap);
451
+ }
452
+ } else if (mode === 'All') {
453
+ const parentName: string = (data['levelOrderName'] as string).split('#')[0];
454
+ let currentItem: any;
455
+ for (let i: number = 0; i < treeMap.layout.renderItems.length; i++) {
456
+ currentItem = treeMap.layout.renderItems[i as number];
457
+ if ((currentItem['levelOrderName']).indexOf(parentName) > -1 && items.indexOf(currentItem['levelOrderName']) === -1) {
458
+ items.push(currentItem['levelOrderName']);
459
+ }
460
+ }
461
+ } else {
462
+ items.push(data['levelOrderName']);
463
+ }
464
+ return items;
465
+ }
466
+
467
+ /**
468
+ * Function to compile the template function for maps.
469
+ *
470
+ * @param {string} template - Specifies the template
471
+ * @returns {Function} - Returns the template function
472
+ * @private
473
+ */
474
+ export function getTemplateFunction(template: string | Function): any {
475
+ let templateFn: any = null;
476
+ try {
477
+ if (typeof template !== 'function' && document.querySelectorAll(template).length) {
478
+ templateFn = compile(document.querySelector(template).innerHTML.trim());
479
+ } else {
480
+ templateFn = compile(template);
481
+ }
482
+ } catch (e) {
483
+ templateFn = compile(template);
484
+ }
485
+ return templateFn;
486
+ }
487
+
488
+ /**
489
+ * @private
490
+ * @param {HTMLCollection} element - Specifies the element
491
+ * @param {string} labelId - Specifies the label id
492
+ * @param {Object} data - Specifies the data
493
+ * @returns {HTMLElement} - Returns the element
494
+ */
495
+ export function convertElement(element: HTMLCollection, labelId: string, data: any): HTMLElement {
496
+ const childElement: HTMLElement = createElement('div', {
497
+ id: labelId
498
+ });
499
+ childElement.style.cssText = 'position: absolute;pointer-events: auto;';
500
+ let elementLength: number = element.length;
501
+ while (elementLength > 0) {
502
+ childElement.appendChild(element[0]);
503
+ elementLength--;
504
+ }
505
+ let templateHtml: string = childElement.innerHTML;
506
+ const keys: any[] = Object.keys(data);
507
+ for (let i: number = 0; i < keys.length; i++) {
508
+ const regExp: RegExpConstructor = RegExp;
509
+ templateHtml = templateHtml.replace(new regExp('{{:' + <string>keys[i as number] + '}}', 'g'), data[keys[i as number].toString()]);
510
+ }
511
+ childElement.innerHTML = templateHtml;
512
+ return childElement;
513
+ }
514
+
515
+ /**
516
+ *
517
+ * @param {Rect} rect - Specifies the area.
518
+ * @param {LabelPosition} position - Specifies the position
519
+ * @param {Size} labelSize - Specifies the label size.
520
+ * @param {string} type - Specifies the type.
521
+ * @param {TreeMap} treemap - Specifies the treemap instance.
522
+ * @returns {Location} - Returns the text location.
523
+ */
524
+ export function findLabelLocation(rect: Rect, position: LabelPosition, labelSize: Size, type: string, treemap: TreeMap): Location {
525
+ const location: Location = new Location(0, 0);
526
+ const padding: number = 5;
527
+ const paddings: number = 2;
528
+ const x: number = (type === 'Template') ? treemap.areaRect.x : 0;
529
+ const y: number = (type === 'Template') ? treemap.areaRect.y : 0;
530
+ location.x = (Math.abs(x - ((position.indexOf('Left') > -1) ? rect.x + padding : !(position.indexOf('Right') > -1) ?
531
+ rect.x + ((rect.width / 2) - (labelSize.width / 2)) : (rect.x + rect.width) - labelSize.width))) - paddings;
532
+ if (treemap.enableDrillDown && (treemap.renderDirection === 'BottomLeftTopRight'
533
+ || treemap.renderDirection === 'BottomRightTopLeft')) {
534
+ location.y = Math.abs((rect.y + rect.height) - labelSize.height + padding);
535
+ } else {
536
+ location.y = Math.abs(y - ((position.indexOf('Top') > -1) ? (type === 'Template' ? rect.y : rect.y + labelSize.height) :
537
+ !(position.indexOf('Bottom') > -1) ? type === 'Template' ? (rect.y + ((rect.height / 2) - (labelSize.height / 2))) :
538
+ (rect.y + (rect.height / 2) + labelSize.height / 4) : (rect.y + rect.height) - labelSize.height));
539
+ }
540
+
541
+ return location;
542
+ }
543
+
544
+ /**
545
+ *
546
+ * @param {HTMLElement} element - Specifies the element to be measured.
547
+ * @param {HTMLElement} parentElement - Specifies the parent element of the element to be measured.
548
+ * @returns {Size} - Returns the element size.
549
+ */
550
+ export function measureElement(element: HTMLElement, parentElement: HTMLElement): Size {
551
+ const size: Size = new Size(0, 0);
552
+ parentElement.appendChild(element);
553
+ size.height = element.offsetHeight;
554
+ size.width = element.offsetWidth;
555
+ const measureElementId: HTMLElement = document.getElementById(element.id);
556
+ measureElementId.parentNode.removeChild(measureElementId);
557
+ return size;
558
+ }
559
+
560
+ /**
561
+ *
562
+ * @param {Rect} rect - Specifies the area.
563
+ * @returns {number} - Returns the area width.
564
+ */
565
+ export function getArea(rect: Rect): number {
566
+ return (rect.width - rect.x) * (rect.height - rect.y);
567
+ }
568
+ /**
569
+ *
570
+ * @param {Rect} input - Specifies input for the calculation.
571
+ * @returns {number} - Returns the shortest edge.
572
+ */
573
+ export function getShortestEdge(input: Rect): number {
574
+ const container: Rect = convertToContainer(input);
575
+ const width: number = container.width;
576
+ const height: number = container.height;
577
+ const result: number = Math.min(width, height);
578
+ return result;
579
+ }
580
+ /**
581
+ *
582
+ * @param {Rect} rect - Specifies the rectangle bounds of the container.
583
+ * @returns {Rect} - Returns the rectangle bounds.
584
+ */
585
+ export function convertToContainer(rect: Rect): Rect {
586
+ const x: number = rect.x;
587
+ const y: number = rect.y;
588
+ const width: number = rect.width;
589
+ const height: number = rect.height;
590
+ return {
591
+ x: x,
592
+ y: y,
593
+ width: width - x,
594
+ height: height - y
595
+ };
596
+ }
597
+ /**
598
+ *
599
+ * @param {Rect} container - Specifies the rectangle bounds of the container.
600
+ * @returns {Rect} - Returns the rectangle bounds.
601
+ */
602
+ export function convertToRect(container: Rect): Rect {
603
+ const xOffset: number = container.x;
604
+ const yOffset: number = container.y;
605
+ const width: number = container.width;
606
+ const height: number = container.height;
607
+ return {
608
+ x: xOffset,
609
+ y: yOffset,
610
+ width: xOffset + width,
611
+ height: yOffset + height
612
+ };
613
+ }
614
+ /**
615
+ *
616
+ * @param {number} pageX - Specifies the horizontal position of the mouse location.
617
+ * @param {number} pageY - Specifies the vertical position of the mouse location.
618
+ * @param {Element} element - Specifies the element to which the click is done.
619
+ * @returns {Location} - Returns the clicked location.
620
+ */
621
+ export function getMousePosition(pageX: number, pageY: number, element: Element): Location {
622
+ const elementRect: ClientRect = element.getBoundingClientRect();
623
+ const pageXOffset: number = element.ownerDocument.defaultView.pageXOffset;
624
+ const pageYOffset: number = element.ownerDocument.defaultView.pageYOffset;
625
+ const clientTop: number = element.ownerDocument.documentElement.clientTop;
626
+ const clientLeft: number = element.ownerDocument.documentElement.clientLeft;
627
+ const positionX: number = elementRect.left + pageXOffset - clientLeft;
628
+ const positionY: number = elementRect.top + pageYOffset - clientTop;
629
+ return new Location((pageX - positionX), (pageY - positionY));
630
+ }
631
+ /**
632
+ *
633
+ * @param {ColorMappingModel[]} colorMapping - Specifies the color mapping instance.
634
+ * @param {string} equalValue - Specifies the equal value.
635
+ * @param {number | string} value - Specifies the range value.
636
+ * @returns {any} - Returns the color mapping object.
637
+ * @private
638
+ */
639
+ export function colorMap(
640
+ colorMapping: ColorMappingModel[], equalValue: string,
641
+ value: number | string): any {
642
+ let fill: string; const paths: string[] = []; let opacity: string;
643
+ if (isNullOrUndefined(equalValue) && (isNullOrUndefined(value) && isNaN(<number>value))) {
644
+ return null;
645
+ }
646
+ for (let i: number = 0; i < colorMapping.length; i++) {
647
+ let isEqualColor: boolean = false; const dataValue: number = <number>value;
648
+ if (!isNullOrUndefined(colorMapping[i as number].from) && !isNullOrUndefined(colorMapping[i as number].to)
649
+ && !isNullOrUndefined(colorMapping[i as number].value)) {
650
+ if ((value >= colorMapping[i as number].from && colorMapping[i as number].to >= value) &&
651
+ (colorMapping[i as number].value === equalValue)) {
652
+ isEqualColor = true;
653
+ if (Object.prototype.toString.call(colorMapping[i as number].color) === '[object Array]') {
654
+ fill = !isEqualColor ? colorCollections(colorMapping[i as number], dataValue) : colorMapping[i as number].color[0];
655
+ } else {
656
+ fill = <string>colorMapping[i as number].color;
657
+ }
658
+ }
659
+ } else if ((!isNullOrUndefined(colorMapping[i as number].from) && !isNullOrUndefined(colorMapping[i as number].to))
660
+ || !isNullOrUndefined((colorMapping[i as number].value))) {
661
+ if ((value >= colorMapping[i as number].from && colorMapping[i as number].to >= value)
662
+ || (colorMapping[i as number].value === equalValue)) {
663
+ if (colorMapping[i as number].value === equalValue) {
664
+ isEqualColor = true;
665
+ }
666
+ if (Object.prototype.toString.call(colorMapping[i as number].color) === '[object Array]') {
667
+ fill = !isEqualColor ? colorCollections(colorMapping[i as number], dataValue) : colorMapping[i as number].color[0];
668
+ } else {
669
+ fill = <string>colorMapping[i as number].color;
670
+ }
671
+ }
672
+ }
673
+ if (((value >= colorMapping[i as number].from && value <= colorMapping[i as number].to)
674
+ || (colorMapping[i as number].value === equalValue))
675
+ && !isNullOrUndefined(colorMapping[i as number].minOpacity) && !isNullOrUndefined(colorMapping[i as number].maxOpacity)
676
+ && fill) {
677
+ opacity = deSaturationColor(colorMapping[i as number], value as number);
678
+ }
679
+ if ((fill === '' || isNullOrUndefined(fill))
680
+ && isNullOrUndefined(colorMapping[i as number].from) && isNullOrUndefined(colorMapping[i as number].to)
681
+ && isNullOrUndefined(colorMapping[i as number].minOpacity) && isNullOrUndefined(colorMapping[i as number].maxOpacity)
682
+ && isNullOrUndefined(colorMapping[i as number].value)) {
683
+ fill = (Object.prototype.toString.call(colorMapping[i as number].color) === '[object Array]') ?
684
+ <string>colorMapping[i as number].color[0] : <string>colorMapping[i as number].color;
685
+ }
686
+ opacity = !isNullOrUndefined(opacity) ? opacity : '1';
687
+ paths.push(fill);
688
+ }
689
+ for (let j: number = paths.length - 1; j >= 0; j--) {
690
+ fill = paths[j as number];
691
+ j = (fill) ? -1 : j;
692
+ }
693
+ return { fill: fill, opacity: opacity };
694
+ }
695
+
696
+ /**
697
+ *
698
+ * @param {ColorMappingModel} colorMapping - Specifies the color mapping object.
699
+ * @param {number} rangeValue - Specifies the range value.
700
+ * @returns {string} - Returns the opacity for the color mapping.
701
+ * @private
702
+ */
703
+ export function deSaturationColor(colorMapping: ColorMappingModel, rangeValue: number): string {
704
+ let opacity: number = 1;
705
+ if ((rangeValue >= colorMapping.from && rangeValue <= colorMapping.to)) {
706
+ const ratio: number = (rangeValue - colorMapping.from) / (colorMapping.to - colorMapping.from);
707
+ opacity = (ratio * (colorMapping.maxOpacity - colorMapping.minOpacity)) + colorMapping.minOpacity;
708
+ }
709
+ return opacity.toString();
710
+ }
711
+ /**
712
+ *
713
+ * @param {ColorMappingModel} colorMap - Specifies the color mapping object.
714
+ * @param {number} value - Specifies the range value.
715
+ * @returns {string} - Returns the fill color.
716
+ */
717
+ export function colorCollections(colorMap: ColorMappingModel, value: number): string {
718
+ const gradientFill: string = getColorByValue(colorMap, value);
719
+ return gradientFill;
720
+ }
721
+ /**
722
+ *
723
+ * @param {number} r - Specifies the red color value.
724
+ * @param {number} g - Specifies the green color value.
725
+ * @param {number} b - Specifies the blue color value.
726
+ * @returns {string} - Returns the fill color.
727
+ */
728
+ export function rgbToHex(r: number, g: number, b: number): string {
729
+ return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b);
730
+ }
731
+ /**
732
+ *
733
+ * @param {ColorMappingModel} colorMap - Specifies the color mapping.
734
+ * @param {number} value - Specifies the range value.
735
+ * @returns {string} - Returns the fill color.
736
+ */
737
+ export function getColorByValue(colorMap: ColorMappingModel, value: number): string {
738
+ let color: string = '';
739
+ let rbg: ColorValue;
740
+ if (Number(value) === colorMap.from) {
741
+ color = colorMap.color[0];
742
+ } else if (Number(value) === colorMap.to) {
743
+ color = colorMap.color[colorMap.color.length - 1];
744
+ } else {
745
+ rbg = getGradientColor(Number(value), colorMap);
746
+ color = rgbToHex(rbg.r, rbg.g, rbg.b);
747
+ }
748
+ return color;
749
+ }
750
+ /**
751
+ *
752
+ * @param {number} value - Specifies the range value.
753
+ * @param {ColorMappingModel} colorMap - Specifies the color mapping.
754
+ * @returns {ColorValue} - Returns the color value object.
755
+ */
756
+ export function getGradientColor(value: number, colorMap: ColorMappingModel): ColorValue {
757
+ const previousOffset: number = colorMap.from;
758
+ const nextOffset: number = colorMap.to;
759
+ let percent: number = 0;
760
+ const full: number = nextOffset - previousOffset; let midColor: string;
761
+ percent = (value - previousOffset) / full; let previousColor: string; let nextColor: string;
762
+ if (colorMap.color.length <= 2) {
763
+ previousColor = colorMap.color[0].charAt(0) === '#' ? colorMap.color[0] : colorNameToHex(colorMap.color[0]);
764
+ nextColor = colorMap.color[colorMap.color.length - 1].charAt(0) === '#' ?
765
+ colorMap.color[colorMap.color.length - 1] : colorNameToHex(colorMap.color[colorMap.color.length - 1]);
766
+ } else {
767
+ previousColor = colorMap.color[0].charAt(0) === '#' ? colorMap.color[0] : colorNameToHex(colorMap.color[0]);
768
+ nextColor = colorMap.color[colorMap.color.length - 1].charAt(0) === '#' ?
769
+ colorMap.color[colorMap.color.length - 1] : colorNameToHex(colorMap.color[colorMap.color.length - 1]);
770
+ const a: number = full / (colorMap.color.length - 1); let b: number; let c: number;
771
+
772
+ const length: number = colorMap.color.length - 1;
773
+ const splitColorValueOffset: any[] = []; let splitColor: any = {};
774
+ for (let j: number = 1; j < length; j++) {
775
+ c = j * a;
776
+ b = previousOffset + c;
777
+ splitColor = { b: b, color: colorMap.color[j as number] };
778
+ splitColorValueOffset.push(splitColor);
779
+ }
780
+ for (let i: number = 0; i < splitColorValueOffset.length; i++) {
781
+ if (previousOffset <= value && value <= splitColorValueOffset[i as number]['b'] && i === 0) {
782
+ midColor = splitColorValueOffset[i as number]['color'].charAt(0) === '#' ?
783
+ splitColorValueOffset[i as number]['color'] : colorNameToHex(splitColorValueOffset[i as number]['color']);
784
+ nextColor = midColor;
785
+ percent = value < splitColorValueOffset[i as number]['b'] ? 1 - Math.abs((value - splitColorValueOffset[i as number]['b']) / a)
786
+ : (value - splitColorValueOffset[i as number]['b']) / a;
787
+ } else if (splitColorValueOffset[i as number]['b'] <= value && value <= nextOffset && i === (splitColorValueOffset.length - 1)) {
788
+ midColor = splitColorValueOffset[i as number]['color'].charAt(0) === '#' ?
789
+ splitColorValueOffset[i as number]['color'] : colorNameToHex(splitColorValueOffset[i as number]['color']);
790
+ previousColor = midColor;
791
+ percent = value < splitColorValueOffset[i as number]['b'] ?
792
+ 1 - Math.abs((value - splitColorValueOffset[i as number]['b']) / a) : (value - splitColorValueOffset[i as number]['b']) / a;
793
+ }
794
+ if (i !== splitColorValueOffset.length - 1 && i < splitColorValueOffset.length) {
795
+ if (splitColorValueOffset[i as number]['b'] <= value && value <= splitColorValueOffset[i + 1]['b']) {
796
+ midColor = splitColorValueOffset[i as number]['color'].charAt(0) === '#' ?
797
+ splitColorValueOffset[i as number]['color'] : colorNameToHex(splitColorValueOffset[i as number]['color']);
798
+ previousColor = midColor;
799
+ nextColor = splitColorValueOffset[i + 1]['color'].charAt(0) === '#' ?
800
+ splitColorValueOffset[i + 1]['color'] : colorNameToHex(splitColorValueOffset[i + 1]['color']);
801
+ percent = Math.abs((value - splitColorValueOffset[i + 1]['b'])) / a;
802
+ }
803
+ }
804
+ }
805
+ }
806
+ return getPercentageColor(percent, previousColor, nextColor);
807
+ }
808
+ /**
809
+ *
810
+ * @param {number} percent - Specifies the percentage of the color.
811
+ * @param {number} previous - Specifies the previous color.
812
+ * @param {number} next - Specifies the next color.
813
+ * @returns {ColorValue} - Returns the color value object.
814
+ */
815
+ export function getPercentageColor(percent: number, previous: string, next: string): ColorValue {
816
+ const nextColor: string = next.split('#')[1];
817
+ const prevColor: string = previous.split('#')[1];
818
+ const r: number = getPercentage(percent, parseInt(prevColor.substr(0, 2), 16), parseInt(nextColor.substr(0, 2), 16));
819
+ const g: number = getPercentage(percent, parseInt(prevColor.substr(2, 2), 16), parseInt(nextColor.substr(2, 2), 16));
820
+ const b: number = getPercentage(percent, parseInt(prevColor.substr(4, 2), 16), parseInt(nextColor.substr(4, 2), 16));
821
+ return new ColorValue(r, g, b);
822
+ }
823
+ /**
824
+ *
825
+ * @param {number} percent - Specifies the percentage of the color.
826
+ * @param {number} previous - Specifies the previous color.
827
+ * @param {number} next - Specifies the next color.
828
+ * @returns {number} - Returns the color value.
829
+ */
830
+ export function getPercentage(percent: number, previous: number, next: number): number {
831
+ const full: number = next - previous;
832
+ return Math.round((previous + (full * percent)));
833
+ }
834
+ /**
835
+ *
836
+ * @param {number} maximumWidth - Specifies the length of the text.
837
+ * @param {string} dataLabel - Specifies the label.
838
+ * @param {FontModel} font - Specifies the font of the label.
839
+ * @returns {string[]} - Returns the labels.
840
+ */
841
+ export function wordWrap(maximumWidth: number, dataLabel: string, font: FontModel): string[] {
842
+ const textCollection: string[] = dataLabel.split(' ');
843
+ let label: string = '';
844
+ const labelCollection: string[] = [];
845
+ let text: string;
846
+ for (let i: number = 0, len: number = textCollection.length; i < len; i++) {
847
+ text = textCollection[i as number];
848
+ if (measureText(label.concat(text), font).width < maximumWidth) {
849
+ label = label.concat((label === '' ? '' : ' ') + text);
850
+ } else {
851
+ if (label !== '') {
852
+ labelCollection.push(textTrim(maximumWidth, label, font));
853
+ label = text;
854
+ } else {
855
+ labelCollection.push(textTrim(maximumWidth, text, font));
856
+ text = '';
857
+ }
858
+ }
859
+ if (label && i === len - 1) {
860
+ labelCollection.push(textTrim(maximumWidth, label, font));
861
+ }
862
+ }
863
+ return labelCollection;
864
+ }
865
+ /**
866
+ *
867
+ * @param {number} maxWidth - Specifies the length of the text.
868
+ * @param {string} label - Specifies the label.
869
+ * @param {FontModel} font - Specifies the font of the label.
870
+ * @returns {string[]} - Returns the labels.
871
+ */
872
+ export function textWrap(maxWidth: number, label: string, font: FontModel): string[] {
873
+ const resultText: string[] = [];
874
+ let currentLength: number = 0;
875
+ let totalWidth: number = measureText(label, font).width;
876
+ const totalLength: number = label.length;
877
+ if (maxWidth >= totalWidth) {
878
+ resultText.push(label);
879
+ return resultText;
880
+ } else {
881
+ for (let i: number = label.length; i > currentLength; i--) {
882
+ const sliceString: string = label.slice(currentLength, i);
883
+ totalWidth = measureText(sliceString, font).width;
884
+ if (totalWidth <= maxWidth) {
885
+ resultText.push(sliceString);
886
+ currentLength += sliceString.length;
887
+ if (totalLength === currentLength) {
888
+ return resultText;
889
+ }
890
+ i = totalLength + 1;
891
+ }
892
+ }
893
+ }
894
+ return resultText;
895
+ }
896
+ /**
897
+ * hide function
898
+ *
899
+ * @param {number} maxWidth - Specifies the maximum width.
900
+ * @param {number} maxHeight - Specifies the maximum height.
901
+ * @param {string} text - Specifies the text.
902
+ * @param {FontModel} font - Specifies the font.
903
+ * @returns {string} - Returns the hidden text.
904
+ * @private
905
+ */
906
+ export function hide(maxWidth: number, maxHeight: number, text: string, font: FontModel): string {
907
+ let hideText: string = text;
908
+ const textSize: Size = measureText(text, font);
909
+ hideText = (textSize.width > maxWidth || textSize.height > maxHeight) ? ' ' : text;
910
+ return hideText;
911
+ }
912
+ /**
913
+ *
914
+ * @param {number} a - Specifies the first value of the leaf.
915
+ * @param {number} b - Specifies the second value of the leaf.
916
+ * @returns {number} - Returns whether values are equal or not.
917
+ */
918
+ export function orderByArea(a: number, b: number): number {
919
+ if (a['itemArea'] === b['itemArea']) {
920
+ return 0;
921
+ } else if (a['itemArea'] < b['itemArea']) {
922
+ return 1;
923
+ }
924
+ return -1;
925
+ }
926
+ /**
927
+ *
928
+ * @param {TreeMap} treemap - Specifies the treemap instance.
929
+ * @param {Element} element - Specifies the selected TreeMap leaf item.
930
+ * @param {string} className -Specifies the selected class name.
931
+ * @returns {void}
932
+ */
933
+ export function maintainSelection(treemap: TreeMap, element: Element, className: string): void {
934
+ const elementId: string[] = treemap.levelSelection;
935
+ if (elementId) {
936
+ for (let index: number = 0; index < elementId.length; index++) {
937
+ if (element.getAttribute('id') === elementId[index as number] ||
938
+ element.children[0].id === elementId[index as number]) {
939
+ if (element.childElementCount > 0 && element.children[0].id.indexOf('_Group') === -1) {
940
+ element.children[0].setAttribute('class', className);
941
+ applyOptions(
942
+ element.childNodes[0] as SVGPathElement,
943
+ {
944
+ border: treemap.selectionSettings.border, fill: treemap.selectionSettings.fill,
945
+ opacity: treemap.selectionSettings.opacity
946
+ }
947
+ );
948
+ }
949
+ } else {
950
+ element.setAttribute('class', '');
951
+ }
952
+ }
953
+ }
954
+ }
955
+ /**
956
+ *
957
+ * @param {TreeMap} treemap - Specifies the treemap instance.
958
+ * @param {Element} legendGroup - Specifies the selected element.
959
+ * @returns {void}
960
+ */
961
+ export function legendMaintain(treemap: TreeMap, legendGroup: Element): void {
962
+ const elementId: string[] = treemap.legendId;
963
+ if (elementId) {
964
+ for (let i: number = 0; i < elementId.length; i++) {
965
+ if (treemap.legendSettings.mode === 'Interactive') {
966
+ for (let j: number = 0; j < legendGroup.childElementCount; j++) {
967
+ if (legendGroup.childNodes[j as number]['id'] === elementId[i as number] ||
968
+ parseFloat(legendGroup.childNodes[j as number]['id'].split('Index_')[1]) === parseFloat(elementId[i as number].split('Index_')[1])) {
969
+ const treemapSVGRectElement: SVGRectElement = <SVGRectElement>legendGroup.childNodes[j as number];
970
+ treemapSVGRectElement.setAttribute('fill', treemap.selectionSettings.fill);
971
+ treemapSVGRectElement.setAttribute('opacity', treemap.selectionSettings.opacity);
972
+ if (treemapSVGRectElement.id.indexOf('Text') === -1) {
973
+ treemapSVGRectElement.setAttribute('stroke-width', (treemap.selectionSettings.border.width).toString());
974
+ treemapSVGRectElement.setAttribute('stroke', treemap.selectionSettings.border.color);
975
+ } else {
976
+ treemapSVGRectElement.setAttribute('stroke', null);
977
+ treemapSVGRectElement.setAttribute('stroke-width', null);
978
+ }
979
+ }
980
+ }
981
+ } else {
982
+ const legendItem: Element = document.getElementById(elementId[i as number]);
983
+ if (!isNullOrUndefined(legendItem)) {
984
+ legendItem.setAttribute('fill', treemap.selectionSettings.fill);
985
+ legendItem.setAttribute('opacity', treemap.selectionSettings.opacity);
986
+ if (legendItem.id.indexOf('Text') === -1) {
987
+ legendItem.setAttribute('stroke', treemap.selectionSettings.border.color);
988
+ legendItem.setAttribute('stroke-width', (treemap.selectionSettings.border.width).toString());
989
+ } else {
990
+ legendItem.setAttribute('stroke', null);
991
+ legendItem.setAttribute('stroke-width', null);
992
+ }
993
+ }
994
+ }
995
+ }
996
+ }
997
+ }
998
+ /**
999
+ *
1000
+ * @param {HTMLCollection} elements - Specifies the selected TreeMap element.
1001
+ * @param {string} type - Specifies the selection type.
1002
+ * @param {TreeMap} treemap - Specifies the TreeMap instance.
1003
+ * @returns {void}
1004
+ */
1005
+ export function removeClassNames(elements: HTMLCollection, type: string, treemap: TreeMap): void {
1006
+ let element: SVGPathElement;
1007
+ let options: any = {};
1008
+ for (let j: number = 0; j < elements.length; j++) {
1009
+ element = isNullOrUndefined(elements[j as number].childNodes[0] as SVGPathElement) ? elements[j as number] as SVGPathElement :
1010
+ elements[j as number].childNodes[0] as SVGPathElement;
1011
+ options = treemap.layout.renderItems[parseFloat(element.id.split('_Item_Index_')[1])]['options'];
1012
+ applyOptions(element, options);
1013
+ elements[j as number].classList.remove(type);
1014
+ j -= 1;
1015
+ }
1016
+ }
1017
+ /**
1018
+ *
1019
+ * @param {SVGPathElement} element - Specifies the SVG path element.
1020
+ * @param {any} options - Specifies the settings for the SVG path element.
1021
+ * @returns {void}
1022
+ */
1023
+ export function applyOptions(element: SVGPathElement, options: any): void {
1024
+ element.setAttribute('opacity', options['opacity']);
1025
+ if (!isNullOrUndefined(options['fill'])) {
1026
+ element.setAttribute('fill', options['fill']);
1027
+ } else {
1028
+ element.setAttribute('fill', 'black');
1029
+ }
1030
+ element.setAttribute('stroke', options['border']['color']);
1031
+ element.setAttribute('stroke-width', options['border']['width']);
1032
+ }
1033
+ /**
1034
+ *
1035
+ * @param {string} format - Specifies the format value.
1036
+ * @param {any} data - Specifies the data source object.
1037
+ * @param {TreeMap} treemap - Specifies the TreeMap instance.
1038
+ * @returns {string} - Returns the formatted text.
1039
+ */
1040
+ export function textFormatter(format: string, data: any, treemap: TreeMap): string {
1041
+ if (isNullOrUndefined(format)) {
1042
+ return null;
1043
+ }
1044
+ const keys: string[] = Object.keys(data);
1045
+ for (const key of keys) {
1046
+ format = format.split('${' + key + '}').join(formatValue(data[key as string], treemap).toString());
1047
+ }
1048
+ return format;
1049
+ }
1050
+ /**
1051
+ *
1052
+ * @param {number} value - Specifies the text to be formatted.
1053
+ * @param {TreeMap} treemap - Specifies the TreeMap instance.
1054
+ * @returns {string | number} - Returns the formatted text.
1055
+ */
1056
+ export function formatValue(value: number, treemap: TreeMap): string | number {
1057
+ let formatValue: string | number; let formatFunction: any;
1058
+ if (treemap.format && !isNaN(Number(value))) {
1059
+ formatFunction = treemap.intl.getNumberFormat(
1060
+ { format: treemap.format, useGrouping: treemap.useGroupingSeparator });
1061
+ formatValue = formatFunction(Number(value));
1062
+ } else {
1063
+ formatValue = value;
1064
+ }
1065
+ return formatValue ? formatValue : '';
1066
+ }
1067
+
1068
+ /**
1069
+ * @private
1070
+ */
1071
+ export class ColorValue {
1072
+ public r: number;
1073
+ public g: number;
1074
+ public b: number;
1075
+ constructor(r?: number, g?: number, b?: number) {
1076
+ this.r = r;
1077
+ this.g = g;
1078
+ this.b = b;
1079
+ }
1080
+ }
1081
+
1082
+ /**
1083
+ * @param {ColorValue} value - Specfies the color value
1084
+ * @returns {string} - Returns the string
1085
+ * @private
1086
+ */
1087
+ export function convertToHexCode(value: ColorValue): string {
1088
+ return '#' + componentToHex(value.r) + componentToHex(value.g) + componentToHex(value.b);
1089
+ }
1090
+
1091
+ /**
1092
+ * @param {number} value - Specifies the value
1093
+ * @returns {string} - Returns the string
1094
+ * @private */
1095
+ export function componentToHex(value: number): string {
1096
+ const hex: string = value.toString(16);
1097
+ return hex.length === 1 ? '0' + hex : hex;
1098
+ }
1099
+
1100
+ /**
1101
+ * @param {string} hex - Specifies the hex value
1102
+ * @returns {ColorValue} - Returns the color value
1103
+ * @private
1104
+ */
1105
+ export function convertHexToColor(hex: string): ColorValue {
1106
+ const result: RegExpExecArray = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
1107
+ return result ? new ColorValue(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)) :
1108
+ new ColorValue(255, 255, 255);
1109
+ }
1110
+
1111
+ /**
1112
+ * @param {string} color - Specifies the color
1113
+ * @returns {string} - Returns the string
1114
+ * @private
1115
+ */
1116
+ export function colorNameToHex(color: string): string {
1117
+ color = color === 'transparent' ? 'white' : color;
1118
+ const element: HTMLElement = document.getElementById('treeMapMeasureText');
1119
+ element.style.color = color;
1120
+ color = window.getComputedStyle(element).color;
1121
+ const isRGBValue: string[] = color.replace(/[()RGBrgba ]/g, '').split(',');
1122
+ return convertToHexCode(
1123
+ new ColorValue(parseInt(isRGBValue[0], 10), parseInt(isRGBValue[1], 10), parseInt(isRGBValue[2], 10))
1124
+ );
1125
+ }
1126
+
1127
+ /**
1128
+ * @param {Location} location - Specifies the location
1129
+ * @param {string} shape - Specifies the shape
1130
+ * @param {Size} size - Specifies the size
1131
+ * @param {string} url - Specifies the url
1132
+ * @param {PathOption} options - Specifies the options
1133
+ * @returns {Element} - Returns the element
1134
+ * @private
1135
+ */
1136
+ export function drawSymbol(location: Location, shape: string, size: Size, url: string, options: PathOption): Element {
1137
+ const svgRenderer: SvgRenderer = new SvgRenderer('');
1138
+ const temp: IShapes = renderLegendShape(location, size, shape, options, url);
1139
+ const htmlElement: Element = svgRenderer['draw' + temp.functionName](temp.renderOption);
1140
+ return htmlElement;
1141
+ }
1142
+ /**
1143
+ * @param {Location} location - Specifies the location
1144
+ * @param {Size} size - Specifies the size
1145
+ * @param {string} shape - Specifies the shape
1146
+ * @param {PathOption} options - Specifies the path option
1147
+ * @param {string} url - Specifies the string
1148
+ * @returns {IShapes} - Returns the shapes
1149
+ * @private
1150
+ */
1151
+ export function renderLegendShape(location: Location, size: Size, shape: string, options: PathOption, url: string): IShapes {
1152
+ let renderPath: string;
1153
+ let functionName: string = 'Path';
1154
+ const shapeWidth: number = size.width;
1155
+ const shapeHeight: number = size.height;
1156
+ const shapeX: number = location.x;
1157
+ const shapeY: number = location.y;
1158
+ const x: number = location.x + (-shapeWidth / 2);
1159
+ const y: number = location.y + (-shapeHeight / 2);
1160
+ switch (shape) {
1161
+ case 'Circle':
1162
+ case 'Bubble':
1163
+ functionName = 'Ellipse';
1164
+ merge(options, { 'rx': shapeWidth / 2, 'ry': shapeHeight / 2, 'cx': shapeX, 'cy': shapeY });
1165
+ break;
1166
+ case 'VerticalLine':
1167
+ renderPath = 'M' + ' ' + shapeX + ' ' + (shapeY + (shapeHeight / 2)) + ' ' + 'L' + ' ' + shapeX + ' '
1168
+ + (shapeY + (-shapeHeight / 2));
1169
+ merge(options, { 'd': renderPath });
1170
+ break;
1171
+ case 'Diamond':
1172
+ renderPath = 'M' + ' ' + x + ' ' + shapeY + ' ' +
1173
+ 'L' + ' ' + shapeX + ' ' + (shapeY + (-shapeHeight / 2)) + ' ' +
1174
+ 'L' + ' ' + (shapeX + (shapeWidth / 2)) + ' ' + shapeY + ' ' +
1175
+ 'L' + ' ' + shapeX + ' ' + (shapeY + (shapeHeight / 2)) + ' ' +
1176
+ 'L' + ' ' + x + ' ' + shapeY + ' z';
1177
+ merge(options, { 'd': renderPath });
1178
+ break;
1179
+ case 'Rectangle':
1180
+ renderPath = 'M' + ' ' + x + ' ' + (shapeY + (-shapeHeight / 2)) + ' ' +
1181
+ 'L' + ' ' + (shapeX + (shapeWidth / 2)) + ' ' + (shapeY + (-shapeHeight / 2)) + ' ' +
1182
+ 'L' + ' ' + (shapeX + (shapeWidth / 2)) + ' ' + (shapeY + (shapeHeight / 2)) + ' ' +
1183
+ 'L' + ' ' + x + ' ' + (shapeY + (shapeHeight / 2)) + ' ' +
1184
+ 'L' + ' ' + x + ' ' + (shapeY + (-shapeHeight / 2)) + ' z';
1185
+ merge(options, { 'd': renderPath });
1186
+ break;
1187
+ case 'Triangle':
1188
+ renderPath = 'M' + ' ' + x + ' ' + (shapeY + (shapeHeight / 2)) + ' ' +
1189
+ 'L' + ' ' + shapeX + ' ' + (shapeY + (-shapeHeight / 2)) + ' ' +
1190
+ 'L' + ' ' + (shapeX + (shapeWidth / 2)) + ' ' + (shapeY + (shapeHeight / 2)) + ' ' +
1191
+ 'L' + ' ' + x + ' ' + (shapeY + (shapeHeight / 2)) + ' z';
1192
+ merge(options, { 'd': renderPath });
1193
+ break;
1194
+ case 'InvertedTriangle':
1195
+ renderPath = 'M' + ' ' + (shapeX + (shapeWidth / 2)) + ' ' + (shapeY - (shapeHeight / 2)) + ' ' +
1196
+ 'L' + ' ' + shapeX + ' ' + (shapeY + (shapeHeight / 2)) + ' ' +
1197
+ 'L' + ' ' + (shapeX - (shapeWidth / 2)) + ' ' + (shapeY - (shapeHeight / 2)) + ' ' +
1198
+ 'L' + ' ' + (shapeX + (shapeWidth / 2)) + ' ' + (shapeY - (shapeHeight / 2)) + ' z';
1199
+ merge(options, { 'd': renderPath });
1200
+ break;
1201
+ case 'Pentagon':
1202
+ // eslint-disable-next-line no-case-declarations
1203
+ const eq: number = 72;
1204
+ // eslint-disable-next-line no-case-declarations
1205
+ let xValue: number;
1206
+ // eslint-disable-next-line no-case-declarations
1207
+ let yValue: number;
1208
+ for (let i: number = 0; i <= 5; i++) {
1209
+ xValue = (shapeWidth / 2) * Math.cos((Math.PI / 180) * (i * eq));
1210
+ yValue = (shapeWidth / 2) * Math.sin((Math.PI / 180) * (i * eq));
1211
+ if (i === 0) {
1212
+ renderPath = 'M' + ' ' + (shapeX + xValue) + ' ' + (shapeY + yValue) + ' ';
1213
+ } else {
1214
+ renderPath = renderPath.concat('L' + ' ' + (shapeX + xValue) + ' ' + (shapeY + yValue) + ' ');
1215
+ }
1216
+ }
1217
+ renderPath = renderPath.concat('Z');
1218
+ merge(options, { 'd': renderPath });
1219
+ break;
1220
+ case 'Star':
1221
+ renderPath = 'M ' + (location.x + size.width / 3) + ' ' + (location.y - size.height / 2) + ' L ' + (location.x - size.width / 2)
1222
+ + ' ' + (location.y + size.height / 6) + ' L ' + (location.x + size.width / 2) + ' ' + (location.y + size.height / 6)
1223
+ + ' L ' + (location.x - size.width / 3) + ' ' + (location.y - size.height / 2) + ' L ' + location.x + ' ' +
1224
+ (location.y + size.height / 2) + ' L ' + (location.x + size.width / 3) + ' ' + (location.y - size.height / 2) + ' Z';
1225
+ merge(options, { 'd': renderPath });
1226
+ break;
1227
+ case 'Cross':
1228
+ renderPath = 'M' + ' ' + x + ' ' + shapeY + ' ' + 'L' + ' ' + (shapeX + (shapeWidth / 2)) + ' ' + shapeY + ' ' +
1229
+ 'M' + ' ' + shapeX + ' ' + (shapeY + (shapeHeight / 2)) + ' ' + 'L' + ' ' + shapeX + ' ' +
1230
+ (shapeY + (-shapeHeight / 2));
1231
+ merge(options, { 'd': renderPath });
1232
+ break;
1233
+ case 'Image':
1234
+ functionName = 'Image';
1235
+ merge(options, { 'href': url, 'height': shapeHeight, 'width': shapeWidth, x: x, y: y });
1236
+ break;
1237
+ }
1238
+ return { renderOption: options, functionName: functionName };
1239
+ }
1240
+
1241
+ /**
1242
+ *
1243
+ * @param {any} data - Specifies the data source object.
1244
+ * @param {any} item - Specifies the leaf item.
1245
+ * @returns {boolean} - Returns whether the TreeMap item is level item or leaf item.
1246
+ */
1247
+ export function isParentItem(data: any[], item: any): boolean {
1248
+ let isParentItem: boolean = false;
1249
+ for (let j: number = 0; j < data.length; j++) {
1250
+ if (item['levelOrderName'] === data[j as number]['levelOrderName']) {
1251
+ isParentItem = true;
1252
+ break;
1253
+ }
1254
+ }
1255
+ return isParentItem;
1256
+ }
1257
+ /**
1258
+ * Specifies the data to be received through Ajax request for treemap.
1259
+ */
1260
+ export class TreeMapAjax {
1261
+ /** Defines the options for the data for treemap. */
1262
+ public dataOptions: string | any;
1263
+ /** Defines the type of the data. */
1264
+ public type: string;
1265
+ /** Specifies whether the request is asynchronous or not. */
1266
+ public async: boolean;
1267
+ /** Defines the type of the content. */
1268
+ public contentType: string;
1269
+ /** Defines the data to be sent through the request. */
1270
+ public sendData: string | any;
1271
+ constructor(options: string | any, type?: string, async?: boolean, contentType?: string, sendData?: string | any) {
1272
+ this.dataOptions = options;
1273
+ this.type = type || 'GET';
1274
+ this.async = async || true;
1275
+ this.contentType = contentType;
1276
+ this.sendData = sendData;
1277
+ }
1278
+ }
1279
+ /**
1280
+ *
1281
+ * @param {any[]} collection - Specifies the legend collection.
1282
+ * @returns {void}
1283
+ * @private
1284
+ */
1285
+ export function removeShape(collection: any[]): void {
1286
+ if (collection.length > 0) {
1287
+ for (let i: number = 0; i < collection.length; i++) {
1288
+ const item: any = collection[i as number];
1289
+ setColor(item['legendEle'], item['oldFill'], item['oldOpacity'], item['oldBorderColor'], item['oldBorderWidth']);
1290
+ }
1291
+ }
1292
+ }
1293
+ /**
1294
+ *
1295
+ * @param {any[]} collection - Specifies the legend collection.
1296
+ * @param {TreeMap} treeMap - Specifies the treemap instance.
1297
+ * @returns {void}
1298
+ * @private
1299
+ */
1300
+ export function removeLegend(collection: any[], treeMap: TreeMap): void {
1301
+ if (collection.length > 0) {
1302
+ for (let j: number = 0; j < collection.length; j++) {
1303
+ const item: any = collection[j as number];
1304
+ const legendIndex: number = parseFloat(item['legendEle'].id.split('_Index_')[1]);
1305
+ const isText: boolean = item['legendEle'].id.indexOf('Text') > -1;
1306
+ const shapeId: string = isText ? item['legendEle'].id.replace('_Text', '') : item['legendEle'].id;
1307
+ const legendShape: Element = treeMap.legendSettings.mode === 'Interactive'
1308
+ ? document.getElementById(shapeId)
1309
+ : document.getElementById(treeMap.element.id + '_Legend_Shape_Index_' + legendIndex);
1310
+ const legendText: Element = treeMap.legendSettings.mode === 'Interactive'
1311
+ ? document.getElementById(shapeId + '_Text')
1312
+ : document.getElementById(treeMap.element.id + '_Legend_Text_Index_' + legendIndex);
1313
+ if (!isNullOrUndefined(legendShape)) {
1314
+ setColor(legendShape, item['oldFill'], item['oldOpacity'], 'none', '0px');
1315
+ }
1316
+ if (!isNullOrUndefined(legendText)) {
1317
+ setColor(legendText, treeMap.legendSettings.textStyle.color || treeMap.themeStyle.legendTextColor, item['oldOpacity'], null, null);
1318
+ }
1319
+ const dataCount: number = !isNullOrUndefined(item['ShapeCollection']) ? item['ShapeCollection']['Elements'].length : 0;
1320
+ for (let k: number = 0; k < dataCount; k++) {
1321
+ const shapeElement: Element = document.getElementById(item['ShapeCollection']['Elements'][k as number].id);
1322
+ if (!isNullOrUndefined(shapeElement)) {
1323
+ setColor(
1324
+ shapeElement, item['shapeOldFill'], item['shapeOldOpacity'],
1325
+ item['shapeOldBorderColor'], item['shapeOldBorderWidth']);
1326
+ }
1327
+ }
1328
+ }
1329
+ }
1330
+ }
1331
+ /**
1332
+ *
1333
+ * @param {Element} element - Specifies the selected element.
1334
+ * @param {string} fill - Specifies the fill color.
1335
+ * @param {string} opacity - Specifies the opacity.
1336
+ * @param {string} borderColor - Specifies the border color.
1337
+ * @param {string} borderWidth - Specifies the border width.
1338
+ * @returns {void}
1339
+ */
1340
+ export function setColor(element: Element, fill: string, opacity: string, borderColor: string, borderWidth: string): void {
1341
+ element.setAttribute('fill', fill);
1342
+ element.setAttribute('opacity', opacity);
1343
+ if (!isNullOrUndefined(borderColor)) {
1344
+ element.setAttribute('stroke', borderColor);
1345
+ }
1346
+ if (!isNullOrUndefined(borderWidth)) {
1347
+ element.setAttribute('stroke-width', borderWidth);
1348
+ }
1349
+ }
1350
+ /**
1351
+ *
1352
+ * @param {any[]} collection - Specifies the selected item collection.
1353
+ * @param {any[]} element - Specifies the selected element collection.
1354
+ * @param {TreeMap} treemap - Specifies the TreeMap instance.
1355
+ * @returns {void}
1356
+ */
1357
+ export function removeSelectionWithHighlight(collection: any[], element: any[], treemap: TreeMap): void {
1358
+ removeLegend(collection, treemap);
1359
+ element = [];
1360
+ removeClassNames(document.getElementsByClassName('treeMapHighLight'), 'treeMapHighLight', treemap);
1361
+ }
1362
+ /**
1363
+ *
1364
+ * @param {number} length - Specifies the length of the legend group.
1365
+ * @param {any} item - Specifies the legend item.
1366
+ * @param {TreeMap} treemap - Specifies the TreeMap instance.
1367
+ * @returns {number} - Returns the legend index.
1368
+ */
1369
+ export function getLegendIndex(length: number, item: any, treemap: TreeMap): number {
1370
+ let index: number;
1371
+ const valuePath: string = (treemap.rangeColorValuePath !== '') ? treemap.rangeColorValuePath : null;
1372
+ let indexFound: boolean = false;
1373
+ for (let i: number = 0; i < length && !indexFound; i++) {
1374
+ const dataLength: number = treemap.treeMapLegendModule.legendCollections[i as number]['legendData'].length;
1375
+ if (dataLength > 0) {
1376
+ for (let j: number = 0; j < dataLength; j++) {
1377
+ if ((!isNullOrUndefined(valuePath) && treemap.leafItemSettings.colorMapping.length > 0 ?
1378
+ (treemap.treeMapLegendModule.legendCollections[i as number]['legendData'][j as number]['data'][valuePath as string] === item['data'][valuePath as string])
1379
+ : treemap.treeMapLegendModule.legendCollections[i as number]['legendData'][j as number]['levelOrderName'] === item['levelOrderName']
1380
+ || item['levelOrderName'].indexOf(treemap.treeMapLegendModule.legendCollections[i as number]['legendName']) > -1)
1381
+ ) {
1382
+ index = i;
1383
+ indexFound = true;
1384
+ break;
1385
+ }
1386
+ }
1387
+ } else if (treemap.palette && treemap.palette.length > 0) {
1388
+ if ((treemap.treeMapLegendModule.legendCollections[i as number]['levelOrderName'] === item['levelOrderName'] ||
1389
+ (item['levelOrderName'].indexOf(treemap.treeMapLegendModule.legendCollections[i as number]['levelOrderName'])) > -1)
1390
+ && treemap.treeMapLegendModule.legendCollections[i as number]['legendName'] === item['name']) {
1391
+ index = i;
1392
+ break;
1393
+ }
1394
+ }
1395
+ }
1396
+ return index;
1397
+ }
1398
+ /**
1399
+ *
1400
+ * @param {any[]} collection - Specifies the legend collection.
1401
+ * @param {number} index - Specifies the index of legend.
1402
+ * @param {number} number - Specifies the leaf item index.
1403
+ * @param {Element} legendElement - Specifies the legend element.
1404
+ * @param {Element} shapeElement - Specifies the shape element.
1405
+ * @param {any[]} renderItems - Specifies the item index.
1406
+ * @param {any[]} legendCollection - Specifies the legend collection.
1407
+ * @returns {void}
1408
+ */
1409
+ export function pushCollection(
1410
+ collection: any[], index: number, number: number, legendElement: Element, shapeElement: Element,
1411
+ renderItems: any[], legendCollection: any[]): void {
1412
+ collection.push({
1413
+ legendEle: legendElement, oldFill: legendCollection[index as number]['legendFill'],
1414
+ oldOpacity: legendCollection[index as number]['opacity'], oldBorderColor: legendCollection[index as number]['borderColor'],
1415
+ oldBorderWidth: legendCollection[index as number]['borderWidth'],
1416
+ shapeElement: shapeElement, shapeOldFill: renderItems[number as number]['options']['fill'],
1417
+ shapeOldOpacity: renderItems[number as number]['options']['opacity'],
1418
+ shapeOldBorderColor: renderItems[number as number]['options']['border']['color'],
1419
+ shapeOldBorderWidth: renderItems[number as number]['options']['border']['width']
1420
+ });
1421
+ }
1422
+
1423
+ /**
1424
+ * To trigger the download element
1425
+ *
1426
+ * @param {string} fileName - Specifies the file name
1427
+ * @param {ExportType} type - Specifies the type
1428
+ * @param {string} url - Specifies the url
1429
+ * @param {boolean} isDownload - Specifies the boolean value
1430
+ * @returns {void}
1431
+ * @private
1432
+ */
1433
+ export function triggerDownload(fileName: string, type: ExportType, url: string, isDownload: boolean): void {
1434
+ createElement('a', {
1435
+ attrs: {
1436
+ 'download': fileName + '.' + (type as string).toLocaleLowerCase(),
1437
+ 'href': url
1438
+ }
1439
+ }).dispatchEvent(new MouseEvent(isDownload ? 'click' : 'move', {
1440
+ view: window,
1441
+ bubbles: false,
1442
+ cancelable: true
1443
+ }));
1444
+ }
1445
+ /**
1446
+ *
1447
+ * @param {string} id - Specifies the id of the element to be removed.
1448
+ * @returns {void}
1449
+ */
1450
+ export function removeElement(id: string): void {
1451
+ const element: Element = document.getElementById(id);
1452
+ return element ? remove(element) : null;
1453
+ }