@syncfusion/ej2-treemap 19.3.53 → 19.4.38

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.
@@ -0,0 +1,1571 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ /* eslint-disable @typescript-eslint/dot-notation */
3
+ /* eslint-disable brace-style */
4
+ /* eslint-disable max-len */
5
+ /**
6
+ * Tree Map Components
7
+ */
8
+
9
+ import { Component, NotifyPropertyChanges, INotifyPropertyChanged, Property, extend, Ajax } from '@syncfusion/ej2-base';
10
+ import { Complex, Collection, ModuleDeclaration } from '@syncfusion/ej2-base';
11
+ import { Event, EmitType, Internationalization } from '@syncfusion/ej2-base';
12
+ import { SvgRenderer } from '@syncfusion/ej2-svg-base';
13
+ import { isNullOrUndefined, createElement, EventHandler, Browser, remove } from '@syncfusion/ej2-base';
14
+ import { BorderModel, TitleSettingsModel, MarginModel, LevelSettingsModel, FontModel } from './model/base-model';
15
+ import { LeafItemSettingsModel, TooltipSettingsModel, LegendSettingsModel, InitialDrillSettingsModel } from './model/base-model';
16
+ import { HighlightSettingsModel, SelectionSettingsModel } from './model/base-model';
17
+ import { Border, Margin, TitleSettings, LegendSettings, InitialDrillSettings } from './model/base';
18
+ import { SelectionSettings, TooltipSettings, LevelSettings, LeafItemSettings, HighlightSettings } from './model/base';
19
+ import { TreeMapModel } from './treemap-model';
20
+ import { LayoutMode, TreeMapTheme, RenderingMode } from './utils/enum';
21
+ import { ILoadEventArgs, ILoadedEventArgs, IPrintEventArgs } from '../treemap/model/interface';
22
+ import { ILegendItemRenderingEventArgs, ILegendRenderingEventArgs, IItemDataEventArgs } from '../treemap/model/interface';
23
+ import { IItemRenderingEventArgs, IResizeEventArgs, IDoubleClickEventArgs, IRightClickEventArgs } from '../treemap/model/interface';
24
+ import { IItemClickEventArgs, IItemMoveEventArgs, IClickEventArgs, IMouseMoveEventArgs } from '../treemap/model/interface';
25
+ import { IDrillStartEventArgs, IItemSelectedEventArgs, ITreeMapTooltipRenderEventArgs } from '../treemap/model/interface';
26
+ import { IItemHighlightEventArgs, IDrillEndEventArgs, IThemeStyle } from '../treemap/model/interface';
27
+ import { Size, stringToNumber, RectOption, Rect, textTrim, measureText, findChildren, removeElement, setItemTemplateContent } from '../treemap/utils/helper';
28
+ import { removeClassNames, removeShape, textFormatter } from '../treemap/utils/helper';
29
+ import { findPosition, Location, TextOption, renderTextElement, isContainsData, TreeMapAjax } from '../treemap/utils/helper';
30
+ import { load, loaded, itemSelected, drillStart, drillEnd } from '../treemap/model/constants';
31
+ import { itemClick, itemMove, click, mouseMove, resize, doubleClick, rightClick } from '../treemap/model/constants';
32
+ import { LayoutPanel } from './layout/render-panel';
33
+ import { TreeMapTooltip } from './user-interaction/tooltip';
34
+ import { ExportType } from '../treemap/utils/enum';
35
+ import { PdfPageOrientation } from '@syncfusion/ej2-pdf-export';
36
+ import { TreeMapHighlight, TreeMapSelection } from './user-interaction/highlight-selection';
37
+ import { TreeMapLegend } from './layout/legend';
38
+ import { DataManager, Query } from '@syncfusion/ej2-data';
39
+ import { getThemeStyle } from './model/theme';
40
+ import { Print } from './model/print';
41
+ import { ImageExport } from './model/image-export';
42
+ import { PdfExport } from './model/pdf-export';
43
+ /**
44
+ * Represents the treemap component.
45
+ * ```html
46
+ * <div id="container"/>
47
+ * <script>
48
+ * var treemap = new TreeMap();
49
+ * treemap.appendTo("#container");
50
+ * </script>
51
+ * ```
52
+ */
53
+
54
+ @NotifyPropertyChanges
55
+ export class TreeMap extends Component<HTMLElement> implements INotifyPropertyChanged {
56
+ //Module Declaration for treemap.
57
+ /**
58
+ * Sets and gets the module that is used to add tooltip in the treemap.
59
+ */
60
+ public treeMapTooltipModule: TreeMapTooltip;
61
+ /**
62
+ * Sets and gets the module that is used to add highlight functionality in the treemap.
63
+ */
64
+ public treeMapHighlightModule: TreeMapHighlight;
65
+ /**
66
+ * Sets and gets the module that is used to add selection functionality in the treemap.
67
+ */
68
+ public treeMapSelectionModule: TreeMapSelection;
69
+ /**
70
+ * Sets and gets the module that is used to add legend in the treemap.
71
+ */
72
+ public treeMapLegendModule: TreeMapLegend;
73
+ /**
74
+ * Sets and gets the module that is used to add print functionality in the treemap.
75
+ *
76
+ * @private
77
+ */
78
+ public printModule: Print;
79
+ /**
80
+ * Sets and gets the module that is used to add imageExport functionality in the treemap.
81
+ *
82
+ * @private
83
+ */
84
+ public imageExportModule: ImageExport;
85
+ /**
86
+ * Sets and gets the module that is used to add pdf export functionality in the treemap.
87
+ *
88
+ * @private
89
+ */
90
+ public pdfExportModule: PdfExport ;
91
+ /**
92
+ * Enables and disables the print functionality in treemap.
93
+ *
94
+ * @default false
95
+ */
96
+ @Property(false)
97
+ public allowPrint: boolean;
98
+ /**
99
+ * Enables and disables the export to image functionality in treemap.
100
+ *
101
+ * @default false
102
+ */
103
+ @Property(false)
104
+ public allowImageExport: boolean;
105
+ /**
106
+ * Enables and disables the export to pdf functionality in treemap.
107
+ *
108
+ * @default false
109
+ */
110
+ @Property(false)
111
+ public allowPdfExport: boolean;
112
+ /**
113
+ * Sets and gets the width of the treemap component.
114
+ *
115
+ * @default null
116
+ */
117
+ @Property(null)
118
+ public width: string;
119
+ /**
120
+ * Sets and gets the height of the treemap component.
121
+ *
122
+ * @default null
123
+ */
124
+ @Property(null)
125
+ public height: string;
126
+ /**
127
+ * Sets and gets the options for customizing the color and width of the treemap border.
128
+ */
129
+ @Complex<BorderModel>({}, Border)
130
+ public border: BorderModel;
131
+ /**
132
+ * Sets and gets the options for customizing the margin in the treemap component.
133
+ */
134
+ @Complex<MarginModel>({}, Margin)
135
+ public margin: MarginModel;
136
+ /**
137
+ * Sets and gets the background color of the treemap.
138
+ */
139
+ @Property(null)
140
+ public background: string;
141
+ /**
142
+ * Sets and gets the options for customizing the theme of the treemap component.
143
+ */
144
+ @Property('Material')
145
+ public theme: TreeMapTheme;
146
+ /**
147
+ * Sets and gets the options for customizing the title of the treemap component.
148
+ */
149
+ @Complex<TitleSettingsModel>({}, TitleSettings)
150
+ public titleSettings: TitleSettingsModel;
151
+ /**
152
+ * Specifies the rendering type of layout of the treemap component.
153
+ */
154
+ @Property('Squarified')
155
+ public layoutType: LayoutMode;
156
+ /**
157
+ * Sets and gets the data source for the treemap component.
158
+ *
159
+ * @isGenericType true
160
+ * @isObservable true
161
+ * @default null
162
+ */
163
+ @Property(null)
164
+ public dataSource: DataManager | TreeMapAjax | Object[];
165
+ /**
166
+ * Sets and gets the query to select particular data from the shape data.
167
+ * This property is applicable only when the data source is created by data manager.
168
+ *
169
+ * @default null
170
+ */
171
+ @Property(null)
172
+ public query: Query;
173
+ /**
174
+ * Sets and gets the value path of the weight from the data source, based on which the map item is rendered.
175
+ */
176
+ @Property(null)
177
+ public weightValuePath: string;
178
+ /**
179
+ * Sets and gets the value path from the data source, based on it color is filled in treemap.
180
+ */
181
+ @Property('')
182
+ public rangeColorValuePath: string;
183
+ /**
184
+ * Sets and gets the value path from the data source, based on it color is filled in treemap.
185
+ */
186
+ @Property('')
187
+ public equalColorValuePath: string;
188
+ /**
189
+ * Sets and gets the value path from the data source, based on it color is filled in treemap.
190
+ */
191
+ @Property(null)
192
+ public colorValuePath: string;
193
+ /**
194
+ * Sets and gets the set of colors to apply in the treemap items.
195
+ */
196
+ @Property([])
197
+ public palette: string[];
198
+ /**
199
+ * Specifies the rendering direction of layout of the treemap items.
200
+ *
201
+ * @default TopLeftBottomRight
202
+ */
203
+ @Property('TopLeftBottomRight')
204
+ public renderDirection: RenderingMode;
205
+ /**
206
+ * Enables or disables the drill down functionality in treemap.
207
+ */
208
+ @Property(false)
209
+ public enableDrillDown: boolean;
210
+ /**
211
+ * Enables or disables the connection text in the header of the treemap.
212
+ */
213
+ @Property(false)
214
+ public enableBreadcrumb: boolean;
215
+ /**
216
+ * Specifies the connection between the two words.
217
+ */
218
+ @Property(' - ')
219
+ public breadcrumbConnector: string;
220
+ /**
221
+ * Enables or disables the initial drill in the treemap.
222
+ */
223
+ @Property(false)
224
+ public drillDownView: boolean;
225
+ /**
226
+ * Specifies the options for customizing the initial drill down in treemap.
227
+ */
228
+ @Complex<InitialDrillSettingsModel>({}, InitialDrillSettings)
229
+ public initialDrillDown: InitialDrillSettingsModel;
230
+ /**
231
+ * Sets and gets the options for customizing the leaf item of the treemap.
232
+ */
233
+ @Complex<LeafItemSettingsModel>({}, LeafItemSettings)
234
+ public leafItemSettings: LeafItemSettingsModel;
235
+ /**
236
+ * Sets and gets the options for customizing the levels of the treemap.
237
+ */
238
+ @Collection<LevelSettingsModel>([], LevelSettings)
239
+ public levels: LevelSettingsModel[];
240
+ /**
241
+ * Sets and gets the options for customizing the highlight of the treemap item on mouse over on the treemap component.
242
+ */
243
+ @Complex<HighlightSettingsModel>({}, HighlightSettings)
244
+ public highlightSettings: HighlightSettingsModel;
245
+ /**
246
+ * Sets and gets the options for customizing the selection of the treemap item on click event on the treemap component.
247
+ */
248
+ @Complex<SelectionSettingsModel>({}, SelectionSettings)
249
+ public selectionSettings: SelectionSettingsModel;
250
+ /**
251
+ * Sets and gets the options for customizing the tooltip of the treemap.
252
+ */
253
+ @Complex<TooltipSettingsModel>({}, TooltipSettings)
254
+ public tooltipSettings: TooltipSettingsModel;
255
+ /**
256
+ * Sets and gets the options for customizing the legend of the treemap.
257
+ */
258
+ @Complex<LegendSettingsModel>({}, LegendSettings)
259
+ public legendSettings: LegendSettingsModel;
260
+ /**
261
+ * Enables or disables the visibility state of the separator for grouping.
262
+ *
263
+ * @default false
264
+ */
265
+ @Property(false)
266
+ public useGroupingSeparator: boolean;
267
+ /**
268
+ * Sets and gets the description for treemap.
269
+ *
270
+ * @default null
271
+ */
272
+ @Property(null)
273
+ public description: string;
274
+
275
+ /**
276
+ * Sets and gets the tab index value for treemap.
277
+ *
278
+ * @default 1
279
+ */
280
+ @Property(1)
281
+ public tabIndex: number;
282
+ /**
283
+ * Sets and gets format for the texts in the treemap.
284
+ *
285
+ * @default null
286
+ */
287
+ @Property(null)
288
+ public format: string;
289
+ /**
290
+ * Triggers when the treemap is on load.
291
+ *
292
+ * @event
293
+ */
294
+ @Event()
295
+ public load: EmitType<ILoadEventArgs>;
296
+ /**
297
+ * Triggers before the prints gets started.
298
+ *
299
+ * @event
300
+ */
301
+ @Event()
302
+ public beforePrint: EmitType<IPrintEventArgs>;
303
+ /**
304
+ * Triggers after treemap is rendered.
305
+ *
306
+ * @event
307
+ */
308
+ @Event()
309
+ public loaded: EmitType<ILoadedEventArgs>;
310
+ /**
311
+ * Triggers before item rendering in the treemap component.
312
+ *
313
+ * @event
314
+ */
315
+ @Event()
316
+ public itemRendering: EmitType<IItemRenderingEventArgs>;
317
+ /**
318
+ * Triggers on performing drill down functionality in the treemap.
319
+ *
320
+ * @event
321
+ */
322
+ @Event()
323
+ public drillStart: EmitType<IDrillStartEventArgs>;
324
+ /**
325
+ * Triggers after drill down functionality gets completed in the treemap.
326
+ *
327
+ * @event
328
+ */
329
+ @Event()
330
+ public drillEnd: EmitType<IDrillEndEventArgs>;
331
+ /**
332
+ * Triggers after selecting a treemap item.
333
+ *
334
+ * @event
335
+ */
336
+ @Event()
337
+ public itemSelected: EmitType<IItemSelectedEventArgs>;
338
+ /**
339
+ * Triggers after highlighting on the treemap item.
340
+ *
341
+ * @event
342
+ */
343
+ @Event()
344
+ public itemHighlight: EmitType<IItemHighlightEventArgs>;
345
+ /**
346
+ * Triggers on rendering of the tooltip in the treemap component.
347
+ *
348
+ * @event
349
+ */
350
+ @Event()
351
+ public tooltipRendering: EmitType<ITreeMapTooltipRenderEventArgs>;
352
+ /**
353
+ * Triggers after clicking an item in the treemap.
354
+ *
355
+ * @event
356
+ */
357
+ @Event()
358
+ public itemClick: EmitType<IItemClickEventArgs>;
359
+ /**
360
+ * Triggers after mouse hover on the treemap item.
361
+ *
362
+ * @event
363
+ */
364
+ @Event()
365
+ public itemMove: EmitType<IItemMoveEventArgs>;
366
+ /**
367
+ * Triggers after clicking on the treemap.
368
+ *
369
+ * @event
370
+ */
371
+ @Event()
372
+ public click: EmitType<IItemClickEventArgs>;
373
+ /**
374
+ * Triggers after double clicking on the treemap.
375
+ *
376
+ * @event
377
+ */
378
+ @Event()
379
+ public doubleClick: EmitType<IDoubleClickEventArgs>;
380
+ /**
381
+ * Triggers after right clicking on the treemap.
382
+ *
383
+ * @event
384
+ */
385
+ @Event()
386
+ public rightClick: EmitType<IMouseMoveEventArgs>;
387
+ /**
388
+ * Triggers after mouse hover on the treemap.
389
+ *
390
+ * @event
391
+ */
392
+ @Event()
393
+ public mouseMove: EmitType<IMouseMoveEventArgs>;
394
+ /**
395
+ * Triggers after resizing the treemap component.
396
+ *
397
+ * @event
398
+ */
399
+ @Event()
400
+ public resize: EmitType<IResizeEventArgs>;
401
+ /**
402
+ * Triggers before rendering each legend item in the treemap.
403
+ *
404
+ * @event
405
+ */
406
+ @Event()
407
+ public legendItemRendering: EmitType<ILegendItemRenderingEventArgs>;
408
+ /**
409
+ * Triggers before rendering the legend items in the treemap.
410
+ *
411
+ * @event
412
+ * @deprecated
413
+ */
414
+ @Event()
415
+ public legendRendering: EmitType<ILegendRenderingEventArgs>;
416
+
417
+ /**
418
+ * resize the treemap
419
+ */
420
+ private isResize: boolean = false;
421
+ /**
422
+ * svg renderer object.
423
+ *
424
+ * @private
425
+ */
426
+ public renderer: SvgRenderer;
427
+ /**
428
+ * treemap svg element object
429
+ *
430
+ * @private
431
+ */
432
+ public svgObject: Element;
433
+ /**
434
+ * Stores the exact size of treemap.
435
+ *
436
+ * @private
437
+ */
438
+ public availableSize: Size;
439
+ /**
440
+ * Internal use of internationalization instance.
441
+ *
442
+ * @private
443
+ */
444
+ public intl: Internationalization;
445
+ /**
446
+ * @private
447
+ * Stores the area bounds.
448
+ */
449
+ public areaRect: Rect;
450
+ /**
451
+ * Define the theme style for treemap components
452
+ *
453
+ * @private
454
+ */
455
+ public themeStyle: IThemeStyle;
456
+ /**
457
+ * @private
458
+ * Stores the legend bounds.
459
+ */
460
+ public totalRect: Rect;
461
+ /** @private */
462
+ public layout: LayoutPanel;
463
+ /** @private */
464
+ public orientation: string = 'Horizontal';
465
+ /** @private */
466
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
467
+ public drilledItems: any[] = [];
468
+ /** @private */
469
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
470
+ public drilledLegendItems: any;
471
+ /** @private */
472
+ public currentLevel: number;
473
+ /** @private */
474
+ public isHierarchicalData: boolean = false;
475
+ /** @private */
476
+ private resizeTo: number;
477
+ /** @private */
478
+ private mouseDown: boolean;
479
+ /** @private */
480
+ private drillMouseMove: boolean;
481
+ /** @private */
482
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
483
+ public doubleTapTimer: any;
484
+ /** @private */
485
+ public levelSelection: string[] = [];
486
+ /** @private */
487
+ public legendId: string[] = [];
488
+ /** @private */
489
+ public selectionId: string;
490
+
491
+ /**s
492
+ * Constructor for TreeMap component.
493
+ */
494
+ // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility
495
+ constructor(options?: TreeMapModel, element?: string | HTMLElement) {
496
+ super(options, element);
497
+ }
498
+
499
+ protected preRender(): void {
500
+ this.trigger(load, { treemap: this }, () => {
501
+ this.initPrivateVariable();
502
+ this.unWireEVents();
503
+ this.createSvg();
504
+ this.wireEVents();
505
+ this.setCulture();
506
+ });
507
+
508
+ }
509
+
510
+ protected render(): void {
511
+ this.renderElements();
512
+ }
513
+
514
+ private renderElements(): void {
515
+ LevelsData.levelsData = null;
516
+ LevelsData.defaultLevelsData = null;
517
+ LevelsData.hierarchyData = null;
518
+ this.createSecondaryElement();
519
+ this.addTabIndex();
520
+ this.themeStyle = getThemeStyle(this.theme);
521
+ this.renderBorder();
522
+ this.renderTitle(this.titleSettings, 'title', null, null);
523
+ if (!isNullOrUndefined(LevelsData.levelsData)) {
524
+ LevelsData.defaultLevelsData = LevelsData.levelsData;
525
+ }
526
+ this.processDataManager();
527
+ }
528
+
529
+ private processDataManager(): void {
530
+ let dataModule: DataManager; let queryModule: Query; let ajaxModule: Ajax;
531
+ let localAjax: TreeMapAjax;
532
+ if (this.dataSource instanceof DataManager) {
533
+ dataModule = this.dataSource;
534
+ queryModule = this.query instanceof Query ? this.query : new Query();
535
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
536
+ const dataManager: Promise<any> = dataModule.executeQuery(queryModule);
537
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
538
+ dataManager.then((e: any) => {
539
+ this.dataSource = e['result'];
540
+ this.renderTreeMapElements();
541
+ });
542
+ } else if (this.dataSource instanceof TreeMapAjax) {
543
+ localAjax = this.dataSource as TreeMapAjax;
544
+ ajaxModule = new Ajax(localAjax.dataOptions, localAjax.type, localAjax.async, localAjax.contentType);
545
+ ajaxModule.onSuccess = (args: string) => {
546
+ this.dataSource = JSON.parse('[' + args + ']')[0];
547
+ this.renderTreeMapElements();
548
+ };
549
+ ajaxModule.send(localAjax.sendData);
550
+ } else {
551
+ this.renderTreeMapElements();
552
+ }
553
+ }
554
+
555
+ private renderTreeMapElements(): void {
556
+
557
+ this.processingData();
558
+
559
+ if (this.treeMapLegendModule && this.legendSettings.visible) {
560
+
561
+ this.treeMapLegendModule.renderLegend();
562
+
563
+ }
564
+
565
+ this.layout.processLayoutPanel();
566
+
567
+ this.element.appendChild(this.svgObject);
568
+
569
+ this.elementChange();
570
+
571
+ this.trigger(loaded, {treemap: this, isResized: this.isResize});
572
+ this.isResize = false;
573
+
574
+ this.renderComplete();
575
+ }
576
+
577
+ protected createSvg(): void {
578
+ if (this.svgObject) {
579
+ while (this.svgObject.childNodes.length > 0) {
580
+ this.svgObject.removeChild(this.svgObject.firstChild);
581
+ }
582
+ if (!this.svgObject.hasChildNodes() && this.svgObject.parentNode) {
583
+ remove(this.svgObject);
584
+ }
585
+ }
586
+ this.clearTemplate();
587
+ const containerWidth: number = this.element.clientWidth;
588
+ const containerHeight: number = this.element.clientHeight;
589
+ this.availableSize = new Size(
590
+ stringToNumber(this.width, containerWidth) || containerWidth || 600,
591
+ stringToNumber(this.height, containerHeight) || containerHeight || 450
592
+ );
593
+ this.svgObject = this.renderer.createSvg({
594
+ id: this.element.id + '_svg',
595
+ width: this.availableSize.width,
596
+ height: this.availableSize.height
597
+ });
598
+ }
599
+
600
+
601
+ /**
602
+ * To initilize the private varibales of treemap.
603
+ *
604
+ * @returns {void}
605
+ */
606
+ private initPrivateVariable(): void {
607
+ if (this.element.id === '') {
608
+ const collection: number = document.getElementsByClassName('e-treemap').length;
609
+ this.element.id = 'treemap_control_' + collection;
610
+ }
611
+ this.renderer = new SvgRenderer(this.element.id);
612
+
613
+ this.layout = new LayoutPanel(this);
614
+
615
+ }
616
+
617
+ private createSecondaryElement(): void {
618
+ const secondaryEle: Element = document.getElementById(this.element.id + '_Secondary_Element');
619
+ if (secondaryEle && secondaryEle.childElementCount > 0) {
620
+ secondaryEle.parentNode.removeChild(secondaryEle);
621
+ }
622
+ if (isNullOrUndefined(document.getElementById(this.element.id + '_Secondary_Element'))) {
623
+ const secondaryElement: Element = createElement('div', {
624
+ id: this.element.id + '_Secondary_Element',
625
+ styles: 'position: absolute;z-index:1;'
626
+ });
627
+ this.element.appendChild(secondaryElement);
628
+ }
629
+ }
630
+
631
+ private elementChange(): void {
632
+ if (this.treeMapLegendModule && this.legendSettings.visible && this.treeMapLegendModule.legendGroup && this.layout.layoutGroup) {
633
+ this.svgObject.insertBefore(this.layout.layoutGroup, this.treeMapLegendModule.legendGroup);
634
+ }
635
+ }
636
+
637
+ /**
638
+ * @private
639
+ * Render the treemap border
640
+ *
641
+ * @returns {void}
642
+ */
643
+ private renderBorder(): void {
644
+ const width: number = this.border.width;
645
+ const borderElement: Element = this.svgObject.querySelector('#' + this.element.id + '_TreeMap_Border');
646
+ if ((this.border.width > 0 || (this.background || this.themeStyle.backgroundColor)) && isNullOrUndefined(borderElement)) {
647
+ const borderRect: RectOption = new RectOption(
648
+ this.element.id + '_TreeMap_Border', this.background || this.themeStyle.backgroundColor, this.border, 1,
649
+ new Rect(width / 2, width / 2, this.availableSize.width - width, this.availableSize.height - width));
650
+ this.svgObject.appendChild(this.renderer.drawRectangle(borderRect) as SVGRectElement);
651
+ } else if (borderElement) {
652
+ borderElement.setAttribute('fill', this.background || this.themeStyle.backgroundColor);
653
+ }
654
+ }
655
+
656
+ private renderTitle(title: TitleSettingsModel, type: string, bounds: Rect, groupEle: Element): void {
657
+ const style: FontModel = title.textStyle;
658
+ let height: number; const titlePadding: number = 10;
659
+ const width: number = (this.availableSize.width - this.margin.right - this.margin.left);
660
+ title.textStyle.fontFamily = this.themeStyle.fontFamily || title.textStyle.fontFamily;
661
+ title.textStyle.size = this.themeStyle.fontSize || title.textStyle.size;
662
+ if (title.text) {
663
+ if (isNullOrUndefined(groupEle)) {
664
+ groupEle = this.renderer.createGroup({ id: this.element.id + '_Title_Group' });
665
+ }
666
+ const trimmedTitle: string = textTrim(width, title.text, style);
667
+ const elementSize: Size = measureText(trimmedTitle, style);
668
+ const rect: Rect = (isNullOrUndefined(bounds)) ? new Rect(
669
+ this.margin.left, this.margin.top, this.availableSize.width, this.availableSize.height) : bounds;
670
+ const location: Location = findPosition(rect, title.alignment, elementSize, type);
671
+ const options: TextOption = new TextOption(
672
+ this.element.id + '_TreeMap_' + type, location.x, location.y, 'start', trimmedTitle
673
+ );
674
+ const titleBounds: Rect = new Rect(location.x, location.y, elementSize.width, elementSize.height);
675
+ const element: Element = renderTextElement(
676
+ options, style, style.color || (type === 'title' ? this.themeStyle.titleFontColor : this.themeStyle.subTitleFontColor),
677
+ groupEle
678
+ );
679
+ element.setAttribute('aria-label', title.description || title.text);
680
+ element.setAttribute('tabindex', (this.tabIndex + (type === 'title' ? 1 : 2)).toString());
681
+ if ((type === 'title' && !title.subtitleSettings.text) || (type === 'subtitle')) {
682
+ height = (this.availableSize.height - titleBounds.y - titlePadding - this.margin.bottom);
683
+ this.areaRect = new Rect(this.margin.left, titleBounds.y + titlePadding, width, height);
684
+ }
685
+ if (type !== 'subtitle' && title.subtitleSettings.text) {
686
+ this.renderTitle(title.subtitleSettings, 'subtitle', titleBounds, groupEle);
687
+ } else {
688
+ this.svgObject.appendChild(groupEle);
689
+ }
690
+ } else {
691
+ height = (this.availableSize.height - this.margin.top - this.margin.bottom);
692
+ this.areaRect = new Rect(this.margin.left, this.margin.top, width, height);
693
+ }
694
+ }
695
+
696
+
697
+
698
+ protected processingData(): void {
699
+ let path: string;
700
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
701
+ this.dataSource = this.dataSource as any[];
702
+ if (!isNullOrUndefined(this.dataSource) && this.dataSource.length > 0 && this.weightValuePath) {
703
+ LevelsData.levelsData = [];
704
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
705
+ this.dataSource.map((data: any) => {
706
+ data[this.weightValuePath] = (data[this.weightValuePath]) ? (data[this.weightValuePath] as string).toString() :
707
+ data[this.weightValuePath];
708
+ });
709
+ this.leafItemSettings.labelPath = this.leafItemSettings.labelPath || this.weightValuePath;
710
+ this.checkIsHierarchicalData();
711
+ if (this.levels.length === 0) {
712
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
713
+ const data: any = {};
714
+ data['level'] = 0;
715
+ path = this.leafItemSettings.labelPath;
716
+ data[path] = [];
717
+ for (let i: number = 0; i < this.dataSource.length; i++) {
718
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
719
+ const child: any[] = findChildren(this.dataSource[i])['values'];
720
+ if (this.isHierarchicalData && child && child.length > 0) {
721
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
722
+ child.forEach((currentData: any, dataIndex: number) => {
723
+ if (currentData[path]) {
724
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
725
+ (<any[]>data[path]).push({
726
+ groupIndex: 0, name: currentData[path], levelOrderName: (currentData[path] as string).toString(),
727
+ data: currentData, weight: currentData[this.weightValuePath]
728
+ });
729
+ }
730
+ });
731
+ } else {
732
+ if (this.dataSource[i][path]) {
733
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
734
+ (<any[]>data[path]).push({
735
+ groupIndex: 0, name: this.dataSource[i][path], levelOrderName: (
736
+ this.dataSource[i][path] as string).toString(), data: this.dataSource[i],
737
+ weight: this.dataSource[i][this.weightValuePath]
738
+ });
739
+ }
740
+ }
741
+ }
742
+ LevelsData.levelsData.push(data);
743
+ } else {
744
+ if (this.isHierarchicalData) {
745
+ LevelsData.hierarchyData = [];
746
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
747
+ LevelsData.hierarchyData = extend([], this.dataSource, LevelsData.hierarchyData, true) as any[];
748
+ for (let i: number = 0; i < LevelsData.hierarchyData.length; i++) {
749
+ this.processHierarchicalData(LevelsData.hierarchyData[i], i);
750
+ }
751
+ LevelsData.levelsData = LevelsData.hierarchyData;
752
+ } else {
753
+ this.processFlatJsonData();
754
+ if (LevelsData.levelsData.length > 1) {
755
+ this.reOrderLevelData(LevelsData.levelsData.length - 1);
756
+ }
757
+ }
758
+ path = this.levels[0].groupPath;
759
+ }
760
+ if (!this.isHierarchicalData) {
761
+ this.findTotalWeight(LevelsData.levelsData[0][path], 'Parent');
762
+ }
763
+ }
764
+ }
765
+
766
+ private checkIsHierarchicalData(): void {
767
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
768
+ let child: any[]; this.dataSource = this.dataSource as any[];
769
+ for (let i: number = 0; i < this.dataSource.length; i++) {
770
+ child = findChildren(this.dataSource[i])['values'];
771
+ if (child && child.length) {
772
+ this.isHierarchicalData = true;
773
+ break;
774
+ } else if (i === this.dataSource.length - 1) {
775
+ this.isHierarchicalData = false;
776
+ }
777
+ }
778
+ }
779
+
780
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
781
+ private processHierarchicalData(data: any, dataCount: number): void {
782
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
783
+ let childData: any[]; const levelData: any[] = [];
784
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
785
+ let newData: any = {};
786
+ let levelIndex: number;
787
+ const path: string = this.leafItemSettings.labelPath ? this.leafItemSettings.labelPath : this.weightValuePath;
788
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
789
+ const currentData: any = {};
790
+ let level: LevelSettingsModel; let key: string;
791
+ newData = findChildren(data);
792
+ childData = newData ? newData['values'] : null;
793
+ if (childData && childData.length > 0) {
794
+ key = newData['key'];
795
+ for (let i: number = 0; i < this.levels.length; i++) {
796
+ if (key === this.levels[i].groupPath) {
797
+ level = this.levels[i];
798
+ levelIndex = i;
799
+ }
800
+ }
801
+ for (let j: number = 0; j < childData.length; j++) {
802
+ childData[j]['name'] = childData[j][path];
803
+ childData[j]['levelOrderName'] = (levelIndex === 0 ? childData[j]['name'] :
804
+ data['levelOrderName'] + '#' + childData[j]['name']) + '';
805
+ const childItemLevel: string = childData[j]['levelOrderName']; let childLevel: number;
806
+ if (childItemLevel.search('#') > 0) {
807
+ childLevel = childItemLevel.split('#').length - 1;
808
+ }
809
+ childData[j]['groupIndex'] = isNullOrUndefined(levelIndex) ? childLevel === this.levels.length
810
+ ? this.levels.length : childLevel : levelIndex;
811
+ if (levelIndex !== 0) {
812
+ childData[j]['parent'] = data;
813
+ }
814
+ childData[j]['groupName'] = key;
815
+ childData[j]['data'] = childData[j];
816
+ childData[j]['isDrilled'] = false;
817
+ childData[j]['weight'] = childData[j][this.weightValuePath];
818
+ }
819
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
820
+ childData.forEach((currentData: any) => {
821
+ this.processHierarchicalData(currentData, dataCount);
822
+ });
823
+ }
824
+ if (dataCount === LevelsData.hierarchyData.length - 1) {
825
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
826
+ let mainData: any[] = LevelsData.hierarchyData[0][this.levels[0].groupPath];
827
+ for (let k: number = 0; k < LevelsData.hierarchyData.length; k++) {
828
+ childData = findChildren(LevelsData.hierarchyData[k])['values'];
829
+ if (k !== 0 && childData) {
830
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
831
+ childData.forEach((currentData: any) => { mainData.push(currentData); });
832
+ LevelsData.hierarchyData.splice(k, 1);
833
+ k -= 1;
834
+ }
835
+ }
836
+ mainData = LevelsData.hierarchyData[0][this.levels[0].groupPath];
837
+ for (let l: number = 0; l < mainData.length; l++) {
838
+ newData[this.levels[0].groupPath] = mainData;
839
+ mainData[l]['parent'] = newData;
840
+ }
841
+ }
842
+ }
843
+ /* eslint-disable valid-jsdoc */
844
+ /**
845
+ * This method is used to perform the print functionality in treemap.
846
+ *
847
+ * @param id - Specifies the element to print the treemap.
848
+ */
849
+ public print(id?: string[] | string | Element): void {
850
+ if (this.allowPrint && this.printModule) {
851
+ this.printModule.print(id);
852
+ }
853
+ }
854
+ /**
855
+ * This method is used to perform the export functionality for the rendered treemap.
856
+ *
857
+ * @param type - Specifies the index of the axis.
858
+ * @param fileName - Specifies file name for exporting the rendered treemap.
859
+ * @param orientation - Specifies the orientation of the pdf document.
860
+ */
861
+ public export(type: ExportType, fileName: string, orientation?: PdfPageOrientation, allowDownload?: boolean): Promise<string> {
862
+ if (isNullOrUndefined(allowDownload)) {
863
+ allowDownload = true;
864
+ }
865
+ if (type === 'PDF' && this.allowPdfExport && this.pdfExportModule) {
866
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
867
+ return new Promise((resolve: any, reject: any) => {
868
+ resolve(this.pdfExportModule.export(type, fileName, orientation, allowDownload));
869
+ });
870
+
871
+ } else if (this.allowImageExport && (type !== 'PDF') && this.imageExportModule) {
872
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
873
+ return new Promise((resolve: any, reject: any) => {
874
+ resolve(this.imageExportModule.export(type, fileName, allowDownload));
875
+ });
876
+ }
877
+ return null;
878
+ }
879
+ private processFlatJsonData(): void {
880
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
881
+ this.dataSource = this.dataSource as any[];
882
+ let groupPath: string; let childGroupPath: string;
883
+ const orderNames: string[] = []; const process: boolean = false;
884
+ for (let i: number = 0; i < this.levels.length + 1; i++) {
885
+ groupPath = this.levels[i] ? this.levels[i].groupPath : this.leafItemSettings.labelPath;
886
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
887
+ const level: any = {};
888
+ level['level'] = i;
889
+ level[groupPath] = [];
890
+ LevelsData.levelsData.push(level);
891
+ for (let j: number = 0; j < this.dataSource.length; j++) {
892
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
893
+ const currentData: any = {}; let childName: string = '';
894
+ if (!isNullOrUndefined(groupPath)) {
895
+ const name: string = this.dataSource[j][groupPath];
896
+ if (i !== 0) {
897
+ for (let k: number = 0; k <= i; k++) {
898
+ const childGroupPath: string = this.levels[k] ? this.levels[k].groupPath : groupPath;
899
+ childName += (this.dataSource[j][childGroupPath]) + ((k === i) ? '' : '#');
900
+ }
901
+ }
902
+ if (!(orderNames.length > 0 ? orderNames.indexOf(childName ?
903
+ childName : name) !== -1 : false)) {
904
+ currentData['name'] = name;
905
+ currentData['levelOrderName'] = ((childName) ? childName : name) + '';
906
+ currentData['groupIndex'] = i;
907
+ currentData['isDrilled'] = false;
908
+ currentData['groupName'] = groupPath;
909
+ currentData['data'] = this.dataSource[j];
910
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
911
+ (<any[]>LevelsData.levelsData[LevelsData.levelsData.length - 1][groupPath]).push(currentData);
912
+ orderNames.push((childName) ? childName : name);
913
+ }
914
+ }
915
+ }
916
+ }
917
+ }
918
+
919
+ /**
920
+ * This method orders the treemap level data.
921
+ *
922
+ * @param start - Specifies the start value of the treemap level.
923
+ */
924
+ public reOrderLevelData(start: number): void {
925
+ let currentName: string;
926
+ const currentPath: string = this.levels[start] ? this.levels[start].groupPath : this.leafItemSettings.labelPath;
927
+ const prevPath: string = this.levels[start - 1].groupPath;
928
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
929
+ const currentData: any[] = LevelsData.levelsData[start][currentPath] as any[];
930
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
931
+ const previousData: any[] = LevelsData.levelsData[start - 1][prevPath] as any[];
932
+ for (let i: number = 0; i < currentData.length; i++) {
933
+ currentName = currentData[i]['levelOrderName'] as string;
934
+ for (let j: number = 0; j < previousData.length; j++) {
935
+ previousData[j][currentPath] = isNullOrUndefined(previousData[j][currentPath]) ? [] : previousData[j][currentPath];
936
+ if (this.IsChildHierarchy(currentName.split('#'), (previousData[j]['levelOrderName'] as string).split('#'))) {
937
+ if (isNullOrUndefined(currentData[i]['parent'])) {
938
+ currentData[i]['parent'] = previousData[j];
939
+ }
940
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
941
+ (<any[]>previousData[j][currentPath]).push(currentData[i]);
942
+ break;
943
+ }
944
+ }
945
+ }
946
+ this.findTotalWeight(LevelsData.levelsData[LevelsData.levelsData.length - 1][currentPath], 'Child');
947
+ LevelsData.levelsData.splice(start, 1);
948
+ if ((start - 1) > 0) {
949
+ this.reOrderLevelData(start - 1);
950
+ }
951
+ }
952
+
953
+ private IsChildHierarchy (current: string[], previous: string[]): boolean {
954
+ let isChild: boolean = false;
955
+ for (let i: number = 0; i < previous.length; i++)
956
+ {
957
+ if (current.length < i || previous[i] !== current[i])
958
+ {
959
+ return false;
960
+ }
961
+ else
962
+ {
963
+ isChild = true;
964
+ }
965
+ }
966
+ return isChild;
967
+ }
968
+
969
+ /**
970
+ * This method finds the weight value of the treemap level.
971
+ *
972
+ * @param processData - Specifies the treemap data.
973
+ * @param type - Specifies the type of the data.
974
+ */
975
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
976
+ public findTotalWeight(processData: any[], type: string): void {
977
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
978
+ let totalWeight: number; const childData: any[] = [];
979
+ let levelName: string; const start: number = 0; let split: string[];
980
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
981
+ let groupName: string; const groupObj: any = {};
982
+ for (let i: number = 0; i < processData.length; i++) {
983
+ totalWeight = 0;
984
+ groupName = processData[i]['groupName'];
985
+ split = (processData[i]['levelOrderName'] as string).split('#');
986
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
987
+ (<any[]>this.dataSource).forEach((data: any) => {
988
+ if (isContainsData(split, processData[i]['levelOrderName'], data, this)) {
989
+ totalWeight += parseFloat(data[this.weightValuePath]);
990
+ }
991
+ });
992
+ if (type === 'Parent') {
993
+ groupObj[groupName] = processData;
994
+ processData[i]['parent'] = groupObj;
995
+ }
996
+ processData[i]['weight'] = totalWeight;
997
+ }
998
+ }
999
+
1000
+ /**
1001
+ * To unbind event handlers for treemap.
1002
+ *
1003
+ * @returns {void}
1004
+ */
1005
+ private unWireEVents(): void {
1006
+ EventHandler.remove(this.element, 'click', this.clickOnTreeMap);
1007
+ EventHandler.remove(this.element, 'dblclick', this.doubleClickOnTreeMap);
1008
+ EventHandler.remove(this.element, 'contextmenu', this.rightClickOnTreeMap);
1009
+ EventHandler.remove(this.element, Browser.touchStartEvent, this.mouseDownOnTreeMap);
1010
+ EventHandler.remove(this.element, Browser.touchMoveEvent, this.mouseMoveOnTreeMap);
1011
+ EventHandler.remove(this.element, Browser.touchEndEvent, this.mouseEndOnTreeMap);
1012
+ EventHandler.remove(this.element, 'pointerleave mouseleave', this.mouseLeaveOnTreeMap);
1013
+ window.removeEventListener('resize', this.resizeOnTreeMap);
1014
+ }
1015
+
1016
+ /**
1017
+ * To bind event handlers for treemap.
1018
+ *
1019
+ * @returns {void}
1020
+ */
1021
+ private wireEVents(): void {
1022
+ EventHandler.add(this.element, 'click', this.clickOnTreeMap, this);
1023
+ EventHandler.add(this.element, 'dblclick', this.doubleClickOnTreeMap, this);
1024
+ EventHandler.add(this.element, 'contextmenu', this.rightClickOnTreeMap, this);
1025
+ EventHandler.add(this.element, Browser.touchStartEvent, this.mouseDownOnTreeMap, this);
1026
+ EventHandler.add(this.element, Browser.touchMoveEvent, this.mouseMoveOnTreeMap, this);
1027
+ EventHandler.add(this.element, Browser.touchEndEvent, this.mouseEndOnTreeMap, this);
1028
+ EventHandler.add(this.element, 'pointerleave mouseleave', this.mouseLeaveOnTreeMap, this);
1029
+ window.addEventListener('resize', this.resizeOnTreeMap.bind(this));
1030
+ }
1031
+
1032
+ /**
1033
+ * Method to set culture for maps
1034
+ *
1035
+ * @returns {void}
1036
+ */
1037
+ private setCulture(): void {
1038
+ this.intl = new Internationalization();
1039
+ }
1040
+
1041
+ /**
1042
+ * To add tab index for treemap element
1043
+ *
1044
+ * @returns {void}
1045
+ */
1046
+ private addTabIndex(): void {
1047
+ this.element.setAttribute('aria-label', this.description || 'TreeMap Element');
1048
+ this.element.setAttribute('tabindex', this.tabIndex.toString());
1049
+ }
1050
+
1051
+ /**
1052
+ * This method handles the window resize event on treemap.
1053
+ *
1054
+ * @param e - Specifies the pointer event.
1055
+ */
1056
+ public resizeOnTreeMap(e: Event): void {
1057
+ this.isResize = true;
1058
+ let args: IResizeEventArgs = {
1059
+ name: resize,
1060
+ cancel: false,
1061
+ previousSize: this.availableSize,
1062
+ currentSize: new Size(0, 0),
1063
+ treemap: this
1064
+ };
1065
+ if (this.resizeTo) {
1066
+ clearTimeout(this.resizeTo);
1067
+ }
1068
+ if (!isNullOrUndefined(this.element) && this.element.classList.contains('e-treemap')) {
1069
+ this.resizeTo = setTimeout(
1070
+ (): void => {
1071
+ this.unWireEVents();
1072
+ this.createSvg();
1073
+ this.refreshing = true;
1074
+ this.wireEVents();
1075
+ args.currentSize = this.availableSize;
1076
+ this.trigger(resize, args, (observedArgs: IResizeEventArgs) => {
1077
+ this.render();
1078
+ });
1079
+ },
1080
+ 500);
1081
+ }
1082
+ }
1083
+
1084
+ /**
1085
+ * This method handles the click event on the treemap.
1086
+ *
1087
+ * @param e - Specifies the mouse click event in the treemap.
1088
+ */
1089
+ public clickOnTreeMap(e: PointerEvent): void {
1090
+ const targetEle: Element = <Element>e.target;
1091
+ const targetId: string = targetEle.id;
1092
+ let eventArgs: IItemClickEventArgs;
1093
+ let itemIndex: number;
1094
+ const labelText : string = targetEle.innerHTML;
1095
+ const clickArgs: IClickEventArgs = { cancel: false, name: click, treemap: this, mouseEvent: e };
1096
+ this.trigger(click, clickArgs);
1097
+ if (targetId.indexOf('_Item_Index') > -1) {
1098
+ e.preventDefault();
1099
+ itemIndex = parseFloat(targetId.split('_')[6]);
1100
+ eventArgs = {
1101
+ cancel: false, name: itemClick, treemap: this, item: this.layout.renderItems[itemIndex], mouseEvent: e,
1102
+ groupIndex: this.layout.renderItems[itemIndex]['groupIndex'], groupName: this.layout.renderItems[itemIndex]['name'],
1103
+ text: labelText, contentItemTemplate : labelText
1104
+ };
1105
+ this.trigger(itemClick, eventArgs, (observedArgs: IItemClickEventArgs) => {
1106
+ if (observedArgs.text !== labelText || observedArgs.contentItemTemplate !== labelText) {
1107
+ if (isNullOrUndefined(this.leafItemSettings.labelTemplate)) {
1108
+ observedArgs.text = textFormatter(observedArgs.text, observedArgs['item']['data'], observedArgs.treemap);
1109
+ targetEle.innerHTML = observedArgs.text;
1110
+ } else {
1111
+ setItemTemplateContent(targetId, targetEle, observedArgs.contentItemTemplate);
1112
+ }
1113
+ }
1114
+ });
1115
+ }
1116
+ const end: number = new Date().getMilliseconds();
1117
+ let doubleTapTimer1: number;
1118
+ if (!isNullOrUndefined(this.doubleClick)) {
1119
+ if (!isNullOrUndefined(doubleTapTimer1) && end - doubleTapTimer1 < 500) {
1120
+ this.doubleClickOnTreeMap(e);
1121
+ }
1122
+ doubleTapTimer1 = end;
1123
+ }
1124
+
1125
+ }
1126
+
1127
+ /**
1128
+ * This method handles the double click event in the treemap.
1129
+ *
1130
+ * @param e - Specifies the pointer event of mouse click.
1131
+ */
1132
+ public doubleClickOnTreeMap(e: PointerEvent): void {
1133
+ const doubleClickArgs: IDoubleClickEventArgs = { cancel: false, name: doubleClick, treemap: this, mouseEvent: e };
1134
+ this.trigger(doubleClick, doubleClickArgs);
1135
+ //this.notify('dblclick', e);
1136
+ }
1137
+
1138
+ /**
1139
+ * This method handles the right click event in the treemap.
1140
+ *
1141
+ * @param e - Specifies the pointer event of mouse click.
1142
+ */
1143
+ public rightClickOnTreeMap(e: PointerEvent): void {
1144
+ const rightClickArgs: IRightClickEventArgs = { cancel: false, name: rightClick, treemap: this, mouseEvent: e };
1145
+ this.trigger(rightClick, rightClickArgs);
1146
+ }
1147
+
1148
+
1149
+ /**
1150
+ * This method handles the mouse down event in the treemap.
1151
+ *
1152
+ * @param e - Specifies the pointer event of mouse click.
1153
+ */
1154
+ public mouseDownOnTreeMap(e: PointerEvent): void {
1155
+ if ((<Element>e.target).id.indexOf('_Item_Index') > -1) {
1156
+ this.mouseDown = true;
1157
+ }
1158
+ this.notify(Browser.touchStartEvent, e);
1159
+ }
1160
+
1161
+ /**
1162
+ * This method handles the mouse move event in the treemap.
1163
+ *
1164
+ * @param e - Specifies the pointer event of mouse click.
1165
+ */
1166
+ public mouseMoveOnTreeMap(e: PointerEvent): void {
1167
+ const targetEle: Element = <Element>e.target;
1168
+ const targetId: string = targetEle.id;
1169
+ let eventArgs: IItemMoveEventArgs;
1170
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1171
+ let item: any;
1172
+ const moveArgs: IMouseMoveEventArgs = { cancel: false, name: mouseMove, treemap: this, mouseEvent: e };
1173
+ this.trigger(mouseMove, moveArgs);
1174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1175
+ let childItems: any[];
1176
+ if (targetId.indexOf('_Item_Index') > -1) {
1177
+ item = this.layout.renderItems[parseFloat(targetId.split('_')[6])];
1178
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1179
+ childItems = findChildren(item)['values'] as any[];
1180
+ this.element.style.cursor = (!item['isLeafItem'] && childItems && childItems.length > 0 && this.enableDrillDown) ?
1181
+ 'pointer' : 'auto';
1182
+ eventArgs = { cancel: false, name: itemMove, treemap: this, item: item, mouseEvent: e };
1183
+ this.trigger(itemMove, eventArgs);
1184
+ }
1185
+ this.notify(Browser.touchMoveEvent, e);
1186
+ }
1187
+
1188
+ /**
1189
+ * This method calculates the selected treemap levels.
1190
+ *
1191
+ * @param labelText - Specifies the label text.
1192
+ * @param item - Specifies the treemap item.
1193
+ */
1194
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1195
+ public calculateSelectedTextLevels(labelText: string, item: any): any {
1196
+ //to find the levels by clicking the particular text both for drillDownView as true / false.
1197
+ let drillLevel: number; let k: string; let text: String;
1198
+ const levelLabels: string = item['levelOrderName'];
1199
+ const levelText: string[] = levelLabels.split('#');
1200
+ for (k of Object.keys(levelText)) {
1201
+ if (levelText[k] === labelText) {
1202
+ drillLevel = parseInt(k, 10);
1203
+ text = labelText;
1204
+ }
1205
+ }
1206
+ return { drillLevel: drillLevel, currentLevelLabel: text, levelText: levelText };
1207
+ }
1208
+
1209
+ /**
1210
+ * This method calculates the previous level of child items in treemap.
1211
+ *
1212
+ * @param labelText - Specifies the label text in treemap
1213
+ * @param drillLevelValues - Specifies the values of drill level.
1214
+ * @param item - Specifies the treemap item.
1215
+ * @param directLevel - Specifies the current level.
1216
+ */
1217
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1218
+ public calculatePreviousLevelChildItems(labelText: string, drillLevelValues: any, item: any, directLevel: boolean): boolean {
1219
+ //By clicking any child items drilldown to the particular level.
1220
+ //At the time store all the previous drilled level items in drilledItems
1221
+ // This condition satisfies while drilldown View is set as false and the text contains '[+]'
1222
+ let text: string; let p: number = 0; let levelItems: string; let text1: string;
1223
+ const drillTextLevel: number = this.layout.renderItems[0]['levelOrderName'].split('#').length;
1224
+ for (let h: number = 0; h < drillTextLevel; h++) {
1225
+ text1 = h === 0 ? drillLevelValues['levelText'][h] : text1 + '#' + drillLevelValues['levelText'][h];
1226
+ }
1227
+ p = drillTextLevel > 1 ? drillTextLevel : p;
1228
+ for (levelItems of Object['values'](this.layout.renderItems)) {
1229
+ const drillLevelText: string = levelItems['levelOrderName'].split('#');
1230
+ if (drillLevelText[0] === drillLevelValues['levelText'][0]) {
1231
+ text = p === 0 ? isNullOrUndefined(text1) ? text1 : drillLevelValues['levelText'][p] :
1232
+ directLevel ? text1 : text1 + '#' + drillLevelValues['levelText'][p];
1233
+ if (text === levelItems['levelOrderName']) {
1234
+ this.drilledItems.push({ name: levelItems['levelOrderName'], data: levelItems });
1235
+ p++;
1236
+ directLevel = true;
1237
+ if (p <= item['groupIndex']) {
1238
+ text = text + '#' + drillLevelValues['levelText'][p];
1239
+ text1 = text;
1240
+ }
1241
+ }
1242
+ }
1243
+ }
1244
+ return directLevel;
1245
+ }
1246
+
1247
+ /**
1248
+ * This method compares the selected labels with the drill down items.
1249
+ *
1250
+ * @param drillLevelValues - Specifies the values of drill level.
1251
+ * @param item - Specifies the treemap item.
1252
+ * @param i - Specifies the treemap item.
1253
+ */
1254
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1255
+ public compareSelectedLabelWithDrillDownItems(drillLevelValues: any, item: any, i: number): any {
1256
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1257
+ let drillLevelChild: any; const newDrillItem: any = {};
1258
+ const b: number = drillLevelValues['drillLevel'] + 1;
1259
+ if (b === this.drilledItems[i]['data']['groupIndex']) {
1260
+ drillLevelChild = this.drilledItems[i]['data']['parent'];
1261
+ drillLevelChild['isDrilled'] = true;
1262
+ newDrillItem[drillLevelChild[this.drilledItems[i]['data']['groupName']]]
1263
+ = [drillLevelChild];
1264
+ // to remove all the items after matched drilled items
1265
+ this.drilledItems.splice(i, this.drilledItems.length);
1266
+ } else if (drillLevelValues['drillLevel'] === (this.drilledItems.length - 1)
1267
+ || drillLevelValues['drillLevel'] === item['groupIndex']) {
1268
+ newDrillItem[item['groupName']] = [item];
1269
+ }
1270
+ return newDrillItem;
1271
+ }
1272
+
1273
+ /**
1274
+ * This method handles mouse end event in treemap.
1275
+ *
1276
+ * @param e - Specifies the pointer event of mouse.
1277
+ */
1278
+ public mouseEndOnTreeMap(e: PointerEvent): void {
1279
+ const targetEle: Element = <Element>e.target; const targetId: string = targetEle.id; let totalRect: Rect;
1280
+ let startEvent: IDrillStartEventArgs; let endEvent: IDrillEndEventArgs; let directLevel: boolean = false;
1281
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1282
+ let index: number; let newDrillItem: any = {}; let item: any; const process: boolean = true;
1283
+ const layoutID: string = this.element.id + '_TreeMap_' + this.layoutType + '_Layout'; let drillLevel: number;
1284
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1285
+ const templateID: string = this.element.id + '_Label_Template_Group'; let drillLevelValues: any;
1286
+ if (targetId.indexOf('_Item_Index') > -1 && this.enableDrillDown && !this.drillMouseMove) {
1287
+ if (e.cancelable) {
1288
+ e.preventDefault();
1289
+ }
1290
+ index = parseFloat(targetId.split('_')[6]); item = this.layout.renderItems[index]; const labelText: string = targetEle.innerHTML;
1291
+ if (this.enableBreadcrumb) {
1292
+ drillLevelValues = this.calculateSelectedTextLevels(labelText, item);
1293
+ drillLevel = drillLevelValues['drillLevel'];
1294
+ if (!this.drillDownView && labelText.search('[+]') !== -1) {
1295
+ directLevel = this.calculatePreviousLevelChildItems(labelText, drillLevelValues, item, directLevel);
1296
+ }
1297
+ }
1298
+ if (this.levels.length !== 0 && !item['isLeafItem'] && findChildren(item)['values'] &&
1299
+ findChildren(item)['values'].length > 0) {
1300
+ if (this.drilledItems.length > 0) {
1301
+ item = directLevel ? this.drilledItems[this.drilledItems.length - 1]['data'] : item;
1302
+ for (let i: number = 0; i < this.drilledItems.length; i++) {
1303
+ if (!isNullOrUndefined(drillLevel)) { //Compare the selected text level with drilled items
1304
+ const drillLength: number = this.drilledItems.length;
1305
+ newDrillItem = this.compareSelectedLabelWithDrillDownItems(drillLevelValues, item, i);
1306
+ if (drillLength !== this.drilledItems.length) {
1307
+ i -= 1; break;
1308
+ }
1309
+ } //when clicking the levels drill back to the previous level process takes place
1310
+ if (item['levelOrderName'] === this.drilledItems[i]['name'] && !directLevel && isNullOrUndefined(drillLevel)) {
1311
+ if (item['groupIndex'] === 0 && item['parent'][item['groupName']] instanceof Array) {
1312
+ item['isDrilled'] = !(item['isDrilled']);
1313
+ if (!item['isDrilled']) {
1314
+ newDrillItem = item['parent'];
1315
+ } else {
1316
+ newDrillItem[item['groupName']] = [item];
1317
+ }
1318
+ } else {
1319
+ item['isDrilled'] = false; item['parent']['isDrilled'] = true; item = item['parent'];
1320
+ newDrillItem[item['groupName']] = [item];
1321
+ }
1322
+ this.drilledItems.splice(i, 1);
1323
+ i -= 1; break;
1324
+ } else if (i === this.drilledItems.length - 1 && isNullOrUndefined(drillLevel)) {
1325
+ item['isDrilled'] = true; // click the items move to next level.
1326
+ newDrillItem[item['groupName']] = [item];
1327
+ }
1328
+ }
1329
+ } else {
1330
+ item['isDrilled'] = true;
1331
+ newDrillItem[item['groupName']] = [item];
1332
+ }
1333
+ startEvent = {
1334
+ cancel: false, name: drillStart, treemap: this,
1335
+ element: targetEle, groupIndex: this.enableBreadcrumb &&
1336
+ this.drilledItems.length !== 0 && !isNullOrUndefined(drillLevel) ?
1337
+ this.drilledItems[this.drilledItems.length - 1]['data']['groupIndex'] : item['groupIndex'],
1338
+ groupName: this.enableBreadcrumb && this.drilledItems.length !== 0 && !isNullOrUndefined(drillLevel) ?
1339
+ this.drilledItems[this.drilledItems.length - 1]['data']['name'] : item['name'],
1340
+ rightClick: e.which === 3 ? true : false, childItems: null, item: newDrillItem
1341
+ };
1342
+ this.trigger(drillStart, startEvent, (observedArgs: IDrillStartEventArgs) => {
1343
+ this.currentLevel = item['isDrilled'] && isNullOrUndefined(drillLevel) ? item['groupIndex'] :
1344
+ (!isNullOrUndefined(drillLevel) && this.enableBreadcrumb && item['isDrilled']) ? drillLevel : null;
1345
+ if (!observedArgs.cancel) {
1346
+ if (document.getElementById(layoutID)) {
1347
+ const layerElementId: HTMLElement = document.getElementById(layoutID);
1348
+ layerElementId.parentNode.removeChild(layerElementId);
1349
+ }
1350
+ totalRect = extend({}, this.areaRect, totalRect, true) as Rect;
1351
+ if (this.legendSettings.visible && !isNullOrUndefined(this.treeMapLegendModule)) {
1352
+ if (!isNullOrUndefined(newDrillItem)) {
1353
+ this.treeMapLegendModule.legendGroup.textContent = ''; this.treeMapLegendModule.legendGroup = null;
1354
+ this.treeMapLegendModule.widthIncrement = 0; this.treeMapLegendModule.heightIncrement = 0;
1355
+ if (this.enableBreadcrumb && !isNullOrUndefined(drillLevel)) {
1356
+ this.drilledLegendItems = {
1357
+ name: this.drilledItems[this.drilledItems.length - 1]['data']['levelOrderName'],
1358
+ data: this.drilledItems[this.drilledItems.length - 1]['data']
1359
+ };
1360
+ } else {
1361
+ this.drilledLegendItems = { name: item['levelOrderName'], data: item };
1362
+ }
1363
+ this.treeMapLegendModule.renderLegend();
1364
+ }
1365
+ totalRect = !isNullOrUndefined(this.totalRect) ? this.totalRect : totalRect;
1366
+ }
1367
+ if (document.getElementById(templateID)) {
1368
+ const drillElementId: HTMLElement = document.getElementById(templateID);
1369
+ drillElementId.parentNode.removeChild(drillElementId);
1370
+ }
1371
+ if (!isNullOrUndefined(observedArgs.childItems) && !observedArgs.cancel) {
1372
+ this.layout.onDemandProcess(observedArgs.childItems);
1373
+ } else {
1374
+ this.layout.calculateLayoutItems(newDrillItem, totalRect);
1375
+ this.layout.renderLayoutItems(newDrillItem);
1376
+ }
1377
+ }
1378
+ });
1379
+ endEvent = { cancel: false, name: drillEnd, treemap: this, renderItems: this.layout.renderItems };
1380
+ this.trigger(drillEnd, endEvent);
1381
+ if (process) {
1382
+ if (!directLevel && isNullOrUndefined(drillLevel)) {
1383
+ this.drilledItems.push({ name: item['levelOrderName'], data: item });
1384
+ }
1385
+ }
1386
+ }
1387
+ }
1388
+ this.mouseDown = false;
1389
+ this.notify(Browser.touchEndEvent, e);
1390
+ }
1391
+
1392
+ /**
1393
+ * This method handles mouse leave event in treemap.
1394
+ *
1395
+ * @param e - Specifies the pointer event of mouse.
1396
+ */
1397
+ public mouseLeaveOnTreeMap(e: PointerEvent): void {
1398
+ if (this.treeMapTooltipModule) {
1399
+ this.treeMapTooltipModule.removeTooltip();
1400
+ }
1401
+ if (this.treeMapLegendModule) {
1402
+ this.treeMapLegendModule.removeInteractivePointer();
1403
+ }
1404
+ removeClassNames(document.getElementsByClassName('treeMapHighLight'), 'treeMapHighLight', this);
1405
+ if (this.treeMapHighlightModule) {
1406
+ removeShape(this.treeMapHighlightModule.shapeHighlightCollection, 'highlight');
1407
+ this.treeMapHighlightModule.highLightId = '';
1408
+ }
1409
+ }
1410
+
1411
+ /**
1412
+ * This method is used to select or remove the selection of treemap item based on the provided selection settings.
1413
+ */
1414
+ public selectItem(levelOrder: string[], isSelected ?: boolean): void {
1415
+ if (isNullOrUndefined(isSelected)) {
1416
+ isSelected = true;
1417
+ }
1418
+ let levelOrderName: string = '';
1419
+ for (let i: number = 0; i < levelOrder.length; i++) {
1420
+ if (i !== levelOrder.length - 1) {
1421
+ levelOrderName += levelOrder[i] + '#';
1422
+ } else {
1423
+ levelOrderName += levelOrder[i];
1424
+ }
1425
+ }
1426
+ if (this.treeMapSelectionModule && this.selectionSettings.enable) {
1427
+ this.treeMapSelectionModule.selectTreemapItem(levelOrderName, isSelected);
1428
+ }
1429
+ }
1430
+
1431
+
1432
+ /**
1433
+ * To provide the array of modules needed for maps rendering
1434
+ *
1435
+ * @returns {ModuleDeclaration[]} Returns the modules
1436
+ * @private
1437
+ */
1438
+ public requiredModules(): ModuleDeclaration[] {
1439
+ const modules: ModuleDeclaration[] = [];
1440
+ if (this.tooltipSettings.visible) {
1441
+ modules.push({
1442
+ member: 'treeMapTooltip',
1443
+ args: [this]
1444
+ });
1445
+ }
1446
+ if (this.highlightSettings.enable) {
1447
+ modules.push({
1448
+ member: 'treeMapHighlight',
1449
+ args: [this]
1450
+ });
1451
+ }
1452
+ if (this.selectionSettings.enable) {
1453
+ modules.push({
1454
+ member: 'treeMapSelection',
1455
+ args: [this]
1456
+ });
1457
+ }
1458
+ if (this.legendSettings.visible) {
1459
+ modules.push({
1460
+ member: 'treeMapLegend',
1461
+ args: [this]
1462
+ });
1463
+ }
1464
+ if (this.allowPrint) {
1465
+ modules.push({
1466
+ member: 'Print',
1467
+ args: [this, Print]
1468
+ });
1469
+ }
1470
+ if (this.allowImageExport) {
1471
+ modules.push({
1472
+ member: 'ImageExport',
1473
+ args: [this, ImageExport]
1474
+ });
1475
+ }
1476
+ if (this.allowPdfExport) {
1477
+ modules.push({
1478
+ member: 'PdfExport',
1479
+ args: [this, PdfExport]
1480
+ });
1481
+ }
1482
+ return modules;
1483
+ }
1484
+
1485
+ /**
1486
+ * Called internally if any of the property value changed.
1487
+ *
1488
+ * @param {TreeMapModel} newProp - Specifies the new property
1489
+ * @param {TreeMapModel} oldProp - Specifies the old property
1490
+ * @returns {void}
1491
+ * @private
1492
+ */
1493
+ public onPropertyChanged(newProp: TreeMapModel, oldProp: TreeMapModel): void {
1494
+ let render: boolean = false;
1495
+ for (const prop of Object.keys(newProp)) {
1496
+ switch (prop) {
1497
+ case 'background':
1498
+ this.renderBorder();
1499
+ break;
1500
+ case 'height':
1501
+ case 'width':
1502
+ case 'layoutType':
1503
+ case 'levels':
1504
+ case 'drillDownView':
1505
+ case 'renderDirection':
1506
+ case 'leafItemSettings':
1507
+ case 'legendSettings':
1508
+ case 'dataSource':
1509
+ render = true;
1510
+ break;
1511
+ }
1512
+ }
1513
+ if (render) {
1514
+ this.createSvg();
1515
+ this.renderElements();
1516
+ }
1517
+ }
1518
+
1519
+ /**
1520
+ * Gets component name.
1521
+ */
1522
+ public getModuleName(): string {
1523
+ return 'treemap';
1524
+ }
1525
+
1526
+ /**
1527
+ * This method is used to dispose the treemap component.
1528
+ */
1529
+ public destroy(): void {
1530
+ this.unWireEVents();
1531
+ this.drilledItems = [];
1532
+ this.levelSelection = [];
1533
+ this.legendId = [];
1534
+ this.removeSvg();
1535
+ super.destroy();
1536
+ }
1537
+
1538
+ private removeSvg(): void {
1539
+ removeElement(this.element.id + '_Secondary_Element');
1540
+ if (this.svgObject) {
1541
+ while (this.svgObject.childNodes.length > 0) {
1542
+ this.svgObject.removeChild(this.svgObject.firstChild);
1543
+ }
1544
+ if (!this.svgObject.hasChildNodes() && this.svgObject.parentNode) {
1545
+ remove(this.svgObject);
1546
+ }
1547
+ }
1548
+ }
1549
+
1550
+ /**
1551
+ * Get the properties to be maintained in the persisted state.
1552
+ *
1553
+ * @returns {string} - Returns the string value.
1554
+ * @private
1555
+ */
1556
+ public getPersistData(): string {
1557
+ return '';
1558
+ }
1559
+ }
1560
+
1561
+ /**
1562
+ * @private
1563
+ */
1564
+ export class LevelsData {
1565
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1566
+ public static levelsData : any[];
1567
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1568
+ public static defaultLevelsData : any[];
1569
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1570
+ public static hierarchyData : any[];
1571
+ }