@syncfusion/ej2-treemap 29.1.33 → 30.1.37

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/.eslintrc.json +2 -0
  2. package/dist/ej2-treemap.min.js +2 -2
  3. package/dist/ej2-treemap.umd.min.js +2 -2
  4. package/dist/ej2-treemap.umd.min.js.map +1 -1
  5. package/dist/es6/ej2-treemap.es2015.js +1 -1
  6. package/dist/es6/ej2-treemap.es2015.js.map +1 -1
  7. package/dist/es6/ej2-treemap.es5.js +1 -1
  8. package/dist/es6/ej2-treemap.es5.js.map +1 -1
  9. package/dist/global/ej2-treemap.min.js +2 -2
  10. package/dist/global/ej2-treemap.min.js.map +1 -1
  11. package/dist/global/index.d.ts +1 -1
  12. package/dist/ts/index.d.ts +4 -0
  13. package/dist/ts/index.ts +4 -0
  14. package/dist/ts/treemap/index.d.ts +19 -0
  15. package/dist/ts/treemap/index.ts +19 -0
  16. package/dist/ts/treemap/layout/legend.d.ts +137 -0
  17. package/dist/ts/treemap/layout/legend.ts +1095 -0
  18. package/dist/ts/treemap/layout/render-panel.d.ts +47 -0
  19. package/dist/ts/treemap/layout/render-panel.ts +758 -0
  20. package/dist/ts/treemap/model/base-model.d.ts +795 -0
  21. package/dist/ts/treemap/model/base.d.ts +671 -0
  22. package/dist/ts/treemap/model/base.ts +798 -0
  23. package/dist/ts/treemap/model/constants.d.ts +117 -0
  24. package/dist/ts/treemap/model/constants.ts +118 -0
  25. package/dist/ts/treemap/model/image-export.d.ts +34 -0
  26. package/dist/ts/treemap/model/image-export.ts +117 -0
  27. package/dist/ts/treemap/model/interface.d.ts +555 -0
  28. package/dist/ts/treemap/model/interface.ts +583 -0
  29. package/dist/ts/treemap/model/pdf-export.d.ts +36 -0
  30. package/dist/ts/treemap/model/pdf-export.ts +105 -0
  31. package/dist/ts/treemap/model/print.d.ts +45 -0
  32. package/dist/ts/treemap/model/print.ts +106 -0
  33. package/dist/ts/treemap/model/theme.d.ts +19 -0
  34. package/dist/ts/treemap/model/theme.ts +450 -0
  35. package/dist/ts/treemap/treemap-model.d.ts +374 -0
  36. package/dist/ts/treemap/treemap.d.ts +724 -0
  37. package/dist/ts/treemap/treemap.ts +1817 -0
  38. package/dist/ts/treemap/user-interaction/highlight-selection.d.ts +118 -0
  39. package/dist/ts/treemap/user-interaction/highlight-selection.ts +799 -0
  40. package/dist/ts/treemap/user-interaction/tooltip.d.ts +42 -0
  41. package/dist/ts/treemap/user-interaction/tooltip.ts +228 -0
  42. package/dist/ts/treemap/utils/enum.d.ts +256 -0
  43. package/dist/ts/treemap/utils/enum.ts +263 -0
  44. package/dist/ts/treemap/utils/helper.d.ts +543 -0
  45. package/dist/ts/treemap/utils/helper.ts +1453 -0
  46. package/package.json +12 -13
  47. package/src/treemap/utils/helper.js +1 -1
@@ -0,0 +1,1095 @@
1
+ import { TreeMap} from '../treemap';
2
+ import { LegendSettingsModel, ColorMappingModel, LevelSettingsModel } from '../model/base-model';
3
+ import { LeafItemSettingsModel, FontModel, BorderModel } from '../model/base-model';
4
+ import {
5
+ findChildren, Location, Rect, Size, measureText,
6
+ TextOption, PathOption, RectOption, drawSymbol, orderByArea, legendMaintain
7
+ } from '../utils/helper';
8
+ import { Browser, isNullOrUndefined, EventHandler, extend, SanitizeHtmlHelper } from '@syncfusion/ej2-base';
9
+ import { SvgRenderer, GradientColor, LinearGradient } from '@syncfusion/ej2-svg-base';
10
+ import { renderTextElement, textTrim } from '../utils/helper';
11
+ import { ILegendItemRenderingEventArgs, ILegendRenderingEventArgs } from '../model/interface';
12
+ import { LegendMode, LegendPosition, LegendOrientation, LabelPlacement, LabelIntersectAction } from '../utils/enum';
13
+ import { legendItemRendering, legendRendering } from '../model/constants';
14
+
15
+ /**
16
+ * Legend module class
17
+ */
18
+ export class TreeMapLegend {
19
+ private treemap: TreeMap;
20
+ /** collection of rendering legends */
21
+ /** @private */
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ public legendRenderingCollections: any[];
24
+ /** collection of legends */
25
+ /** @private */
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ public legendCollections: any[];
28
+ /** @private */
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ public outOfRangeLegend: any;
31
+ private legendHeight: number;
32
+ private legendWidth: number;
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ private totalPages: any[];
35
+ private page: number = 0;
36
+ private translate: Location;
37
+ /** @private */
38
+ public legendBorderRect: Rect = new Rect(0, 0, 0, 0);
39
+ private currentPage: number = 0;
40
+ /** @private */
41
+ public heightIncrement: number = 0;
42
+ /** @private */
43
+ public widthIncrement: number = 0;
44
+ private textMaxWidth: number = 0;
45
+ /** @private */
46
+ public legendGroup: Element;
47
+ private legendNames: string[];
48
+ private defsElement: Element;
49
+ private gradientCount: number;
50
+ private legendLinearGradient: Element;
51
+ private legendInteractiveGradient: Element[] = [];
52
+ private clearTimeout: number;
53
+ private legendItemRect: Rect = new Rect(0, 0, 0, 0);
54
+ constructor(treemap: TreeMap) {
55
+ this.treemap = treemap;
56
+ this.addEventListener();
57
+ }
58
+
59
+ /**
60
+ * method for legend
61
+ *
62
+ * @returns {void}
63
+ * @private
64
+ */
65
+ public renderLegend(): void {
66
+ this.page = 0;
67
+ this.legendRenderingCollections = [];
68
+ this.legendCollections = [];
69
+ this.legendNames = [];
70
+ this.totalPages = [];
71
+ this.gradientCount = 1;
72
+ this.widthIncrement = 0;
73
+ this.heightIncrement = 0;
74
+ this.defsElement = this.treemap.renderer.createDefs();
75
+ this.treemap.svgObject.appendChild(this.defsElement);
76
+ const eventArgs: ILegendRenderingEventArgs = {
77
+ cancel: false, name: legendRendering, treemap: this.treemap, _changePosition: this.treemap.legendSettings.position,
78
+ position: this.treemap.legendSettings.position
79
+ };
80
+ this.treemap.trigger(legendRendering, eventArgs, (observedArgs: ILegendRenderingEventArgs) => {
81
+ if (!observedArgs.cancel && observedArgs._changePosition !== this.treemap.legendSettings.position) {
82
+ this.treemap.legendSettings.position = observedArgs._changePosition;
83
+ }
84
+ this.calculateLegendBounds();
85
+ if (this.legendCollections.length > 0) {
86
+ this.drawLegend();
87
+ }
88
+ });
89
+
90
+ }
91
+ // eslint-disable-next-line valid-jsdoc
92
+ /** @private */
93
+ public calculateLegendBounds(): void {
94
+ const treemap: TreeMap = this.treemap;
95
+ const legend: LegendSettingsModel = treemap.legendSettings;
96
+ this.findColorMappingLegendItems(treemap.treemapLevelData.levelsData[0]);
97
+ if (((!isNullOrUndefined(this.treemap.palette) && this.treemap.palette.length > 0) || !isNullOrUndefined(treemap.colorValuePath))
98
+ && this.legendCollections.length === 0) {
99
+ this.findPaletteLegendItems(treemap.treemapLevelData.levelsData[0]);
100
+ }
101
+ if (this.legendCollections.length > 0) {
102
+ // eslint-disable-next-line @typescript-eslint/tslint/config
103
+ this.legendCollections.sort((firstItem, nextItem) => (firstItem.levelIndex > nextItem.levelIndex) ? 1 :
104
+ (firstItem.levelIndex < nextItem.levelIndex) ? -1 : 0);
105
+ // eslint-disable-next-line @typescript-eslint/tslint/config
106
+ this.legendCollections.sort((firstItem, nextItem) => (firstItem.groupIndex > nextItem.groupIndex) ? 1 :
107
+ (firstItem.groupIndex < nextItem.groupIndex) ? -1 : 0);
108
+ // eslint-disable-next-line @typescript-eslint/tslint/config
109
+ this.legendCollections.sort((firstItem, nextItem) => (firstItem.leafIndex > nextItem.leafIndex) ? 1 :
110
+ (firstItem.leafIndex < nextItem.leafIndex) ? -1 : 0);
111
+ const defaultSize: number = 25; const textPadding: number = 10; const position: LegendPosition = legend.position;
112
+ const legendTitle: string = treemap.enableHtmlSanitizer ? SanitizeHtmlHelper.sanitize(legend.title.text) : legend.title.text;
113
+ const titleTextStyle: FontModel = legend.titleStyle;
114
+ const legendMode: LegendMode = legend.mode; let shapeX: number = 0; let shapeY: number = 0;
115
+ let textX: number = 0; let textY: number = 0; const shapeHeight: number = legend.shapeHeight;
116
+ const shapeWidth: number = legend.shapeWidth; let shapeLocation: Location[] = []; let textLocation: Rect[] = [];
117
+ const orientation: LegendOrientation = (legend.orientation === 'None') ? ((position === 'Top' || position === 'Bottom'
118
+ || (position === 'Auto' && treemap.availableSize.width <= treemap.availableSize.height))
119
+ ? 'Horizontal' : 'Vertical') : legend.orientation;
120
+ const leftPadding: number = 10; const topPadding: number = 10; const spacing: number = 10;
121
+ let legendWidth: number = (legend.width.length > 1) ? (legend.width.indexOf('%') > -1) ? (treemap.availableSize.width / 100)
122
+ * parseFloat(legend.width) : parseFloat(legend.width) : null;
123
+ let legendHeight: number = (legend.height.length > 1) ? (legend.height.indexOf('%') > -1) ?
124
+ (treemap.availableSize.height / 100) * parseFloat(legend.height) : parseFloat(legend.height) : null;
125
+ titleTextStyle.fontFamily = titleTextStyle.fontFamily || treemap.themeStyle.fontFamily;
126
+ titleTextStyle.fontWeight = titleTextStyle.fontWeight || treemap.themeStyle.titleFontWeight;
127
+ titleTextStyle.size = titleTextStyle.size || treemap.themeStyle.subtitleFontSize;
128
+ const legendTitleSize: Size = measureText(legendTitle, titleTextStyle);
129
+ let startX: number = 0; let startY: number = 0; const shapePadding: number = legend.shapePadding;
130
+ const itemTextStyle: FontModel = legend.textStyle;
131
+ itemTextStyle.size = itemTextStyle.size || treemap.themeStyle.legendFontSize;
132
+ itemTextStyle.fontFamily = itemTextStyle.fontFamily || treemap.themeStyle.fontFamily;
133
+ itemTextStyle.fontWeight = itemTextStyle.fontWeight || treemap.themeStyle.fontWeight;
134
+ if (legendMode === 'Default') {
135
+ legendWidth = (isNullOrUndefined(legendWidth)) ? treemap.areaRect.width : legendWidth;
136
+ legendHeight = (isNullOrUndefined(legendHeight)) ? treemap.areaRect.height : legendHeight;
137
+ let j: number = 0;
138
+ for (let i: number = 0; i < this.legendCollections.length; i++) {
139
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
140
+ const legendItem: any = this.legendCollections[i as number];
141
+ if (isNullOrUndefined(this.totalPages[this.page])) {
142
+ this.totalPages[this.page] = { Page: (this.page + 1), Collection: [] };
143
+ }
144
+ const legendTextSize: Size = measureText(treemap.enableHtmlSanitizer ?
145
+ SanitizeHtmlHelper.sanitize(legendItem['legendName']) : legendItem['legendName'], itemTextStyle);
146
+ this.textMaxWidth = Math.max(this.textMaxWidth, legendTextSize.width);
147
+ if (i === 0) {
148
+ startX = shapeX = (leftPadding + (shapeWidth / 2));
149
+ startY = shapeY = topPadding + legendTitleSize.height + (shapeHeight > legendTextSize.height ? shapeHeight / 2
150
+ : (legendTextSize.height / 4));
151
+ } else {
152
+ const maxSize: number = (legendTextSize.height > shapeHeight) ? legendTextSize.height : shapeHeight;
153
+ if (orientation === 'Horizontal') {
154
+ const prvePositionX: number = (textLocation[j - 1].x + textLocation[j - 1].width) + textPadding + shapeWidth;
155
+ if ((prvePositionX + shapePadding + legendTextSize.width) > legendWidth) {
156
+ const nextPositionY: number = (textLocation[j - 1].y > (shapeLocation[j - 1].y + (shapeHeight / 2)) ?
157
+ textLocation[j - 1].y : (shapeLocation[j - 1].y + (shapeHeight / 2))) + topPadding;
158
+ if ((nextPositionY + maxSize) > legendHeight) {
159
+ this.getPageChanged();
160
+ j = 0;
161
+ shapeLocation = [];
162
+ textLocation = [];
163
+ shapeX = startX;
164
+ shapeY = startY;
165
+ } else {
166
+ shapeX = (shapeLocation[0].x);
167
+ shapeY = (nextPositionY + (maxSize / 2));
168
+ }
169
+ } else {
170
+ shapeX = (prvePositionX - (shapeWidth / 2));
171
+ shapeY = (shapeLocation[j - 1]).y;
172
+ }
173
+ } else {
174
+ const prevPositionY: number = textLocation[j - 1].y > shapeLocation[j - 1].y + (shapeHeight / 2) ?
175
+ textLocation[j - 1].y : shapeLocation[j - 1].y + (shapeHeight / 2);
176
+ if ((prevPositionY + topPadding + maxSize) > legendHeight) {
177
+ const nextPositionX: number = (textLocation[j - 1].x + this.textMaxWidth + textPadding);
178
+ if ((nextPositionX + shapePadding + legendTextSize.width) > legendWidth) {
179
+ shapeX = startX;
180
+ shapeY = startY;
181
+ textLocation = [];
182
+ shapeLocation = [];
183
+ this.getPageChanged();
184
+ j = 0;
185
+ } else {
186
+ shapeX = nextPositionX + (shapeWidth / 2);
187
+ shapeY = (shapeLocation[0].y);
188
+ }
189
+ } else {
190
+ shapeX = shapeLocation[j - 1].x;
191
+ shapeY = prevPositionY + topPadding + (shapeHeight / 2);
192
+ }
193
+ }
194
+ }
195
+ textX = shapeX + (shapeWidth / 2) + shapePadding;
196
+ textY = shapeY + (legendTextSize.height / 4);
197
+ shapeLocation.push({ x: shapeX, y: shapeY });
198
+ textLocation.push({ x: textX, y: textY, width: legendTextSize.width, height: (legendTextSize.height / 2) });
199
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
200
+ (<any[]>this.totalPages[this.page]['Collection']).push({
201
+ DisplayText: legendItem['legendName'], element: legendItem['gradientElement'],
202
+ Shape: { x: shapeX, y: shapeY },
203
+ Text: { x: textX, y: textY },
204
+ Fill: legendItem['legendFill'],
205
+ Data: legendItem['legendData'],
206
+ Rect: {
207
+ x: shapeLocation[j as number].x - (shapeWidth / 2),
208
+ y: (shapeLocation[j as number].y - (shapeHeight / 2)) < (textY - legendTextSize.height) ?
209
+ (shapeLocation[j as number].y - (shapeHeight / 2)) : (textY - legendTextSize.height),
210
+ width: Math.abs((shapeLocation[j as number].x - (shapeWidth / 2)) - (textX + legendTextSize.width)),
211
+ height: ((shapeHeight > legendTextSize.height) ? shapeHeight : legendTextSize.height)
212
+ }
213
+ });
214
+ j++;
215
+ }
216
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
217
+ const collection: any[] = (<any[]>this.totalPages[0]['Collection']);
218
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
219
+ collection.forEach((legendObj: any, index: number) => {
220
+ const legendRect: Rect = new Rect(
221
+ legendObj['Rect']['x'], legendObj['Rect']['y'],
222
+ legendObj['Rect']['width'], legendObj['Rect']['height']
223
+ );
224
+ if (index === 0) {
225
+ startX = legendRect.x;
226
+ startY = legendRect.y;
227
+ }
228
+ this.widthIncrement = Math.max(this.widthIncrement, Math.abs(startX - (legendRect.x + legendRect.width)));
229
+ this.heightIncrement = Math.max(this.heightIncrement, Math.abs(startY - (legendRect.y + legendRect.height)));
230
+ });
231
+ legendWidth = ((this.widthIncrement < legendWidth) ? this.widthIncrement : legendWidth);
232
+ legendHeight = ((this.heightIncrement < legendHeight) ? this.heightIncrement : legendHeight);
233
+ this.legendItemRect = {
234
+ x: collection[0]['Rect']['x'], y: collection[0]['Rect']['y'],
235
+ width: legendWidth, height: legendHeight
236
+ };
237
+ } else {
238
+ const legendLength: number = this.legendCollections.length;
239
+ const rectWidth: number = (orientation === 'Horizontal') ? (isNullOrUndefined(legendWidth)) ? (treemap.areaRect.width / legendLength) :
240
+ (legendWidth / legendLength) : (isNullOrUndefined(legendWidth)) ? defaultSize : legendWidth;
241
+ const rectHeight: number = (orientation === 'Horizontal') ? (isNullOrUndefined(legendHeight)) ? defaultSize : legendHeight :
242
+ (isNullOrUndefined(legendHeight)) ? (treemap.areaRect.height / legendLength) : (legendHeight / legendLength);
243
+ startX = 0; startY = legendTitleSize.height + spacing;
244
+ const textPadding: number = 10; const placement: LabelPlacement = legend.labelPosition;
245
+ let itemStartX: number = 0; let itemStartY: number = 0;
246
+ const labelAction: LabelIntersectAction = legend.labelDisplayMode;
247
+ let maxTextHeight: number = 0; let maxTextWidth: number = 0;
248
+ for (let i: number = 0; i < this.legendCollections.length; i++) {
249
+ startX = (orientation === 'Horizontal') ? (startX + rectWidth) : startX;
250
+ startY = (orientation === 'Horizontal') ? startY : (startY + rectHeight);
251
+ let legendText: string = this.legendCollections[i as number]['legendName'];
252
+ let itemTextSize: Size = new Size(0, 0);
253
+ if (labelAction === 'None') {
254
+ itemTextSize = measureText(legendText, itemTextStyle);
255
+ } else if (labelAction === 'Trim') {
256
+ legendText = textTrim((orientation === 'Horizontal' ? rectWidth : rectHeight), legendText, itemTextStyle);
257
+ itemTextSize = measureText(legendText, itemTextStyle);
258
+ } else {
259
+ legendText = '';
260
+ }
261
+ maxTextHeight = Math.max(maxTextHeight, itemTextSize.height);
262
+ maxTextWidth = Math.max(maxTextWidth, itemTextSize.width);
263
+ if (itemTextSize.width > 0 && itemTextSize.height > 0) {
264
+ if (orientation === 'Horizontal') {
265
+ textX = startX + (rectWidth / 2);
266
+ textY = (placement === 'After') ? (startY + rectHeight + (itemTextSize.height / 2)) + textPadding :
267
+ (startY - textPadding);
268
+ } else {
269
+ textX = (placement === 'After') ? startX - (itemTextSize.width / 2) - textPadding
270
+ : (startX + rectWidth + itemTextSize.width / 2) + textPadding;
271
+ textY = startY + (rectHeight / 2) + (itemTextSize.height / 4);
272
+ }
273
+ }
274
+ if (i === 0) {
275
+ itemStartX = (orientation === 'Horizontal') ? startX : (placement === 'After') ?
276
+ textX - (itemTextSize.width / 2) : startX;
277
+ itemStartY = (orientation === 'Horizontal') ? (placement === 'After') ? startY :
278
+ textY - (itemTextSize.height / 2) : startY;
279
+ }
280
+ if (i === legendLength - 1) {
281
+ legendWidth = (orientation === 'Horizontal') ? Math.abs((startX + rectWidth) - itemStartX) :
282
+ (rectWidth + maxTextWidth + textPadding);
283
+ legendHeight = (orientation === 'Horizontal') ? (rectHeight + (maxTextHeight / 2) + textPadding) :
284
+ Math.abs((startY + rectHeight) - itemStartY);
285
+ }
286
+ this.legendRenderingCollections.push({
287
+ fill: this.legendCollections[i as number]['legendFill'], x: startX, y: startY,
288
+ width: rectWidth, height: rectHeight, element: this.legendCollections[i as number]['gradientElement'],
289
+ text: legendText, textX: textX, textY: textY,
290
+ textWidth: itemTextSize.width, textHeight: itemTextSize.height,
291
+ data: this.legendCollections[i as number]['legendData']
292
+ });
293
+ }
294
+ this.legendItemRect = { x: itemStartX, y: itemStartY, width: legendWidth, height: legendHeight };
295
+ }
296
+ }
297
+ }
298
+
299
+ private getPageChanged(): void {
300
+ this.page++;
301
+ if (isNullOrUndefined(this.totalPages[this.page])) {
302
+ this.totalPages[this.page] = { Page: (this.page + 1), Collection: [] };
303
+ }
304
+ }
305
+
306
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
307
+ private findColorMappingLegendItems(data: any): void {
308
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
309
+ const child: any[] = findChildren(data)['values'];
310
+ if (child && child.length > 0) {
311
+ this.calculateLegendItems(child);
312
+ if (this.treemap.levels.length > 0) {
313
+ for (let i: number = 0; i < child.length; i++) {
314
+ this.findColorMappingLegendItems(child[i as number]);
315
+ }
316
+ }
317
+ }
318
+ }
319
+
320
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
321
+ private findPaletteLegendItems(data: any): void {
322
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
323
+ let child: any[]; let legendFillColor: string;
324
+ if (!isNullOrUndefined(this.treemap.drilledItems)) {
325
+ if (this.treemap.drilledItems.length === 0 && !isNullOrUndefined(this.treemap.initialDrillDown.groupName)
326
+ && isNullOrUndefined(this.treemap.drilledLegendItems)) {
327
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
328
+ const items: any[] = findChildren(data)['values'];
329
+ for (let k: number = 0; k < items.length; k++) {
330
+ if (items[k as number]['Name'] === this.treemap.initialDrillDown.groupName) {
331
+ items[k as number]['isDrilled'] = !items[k as number]['isDrilled'];
332
+ data = items[k as number];
333
+ this.treemap.currentLevel = this.treemap.initialDrillDown.groupIndex;
334
+ legendFillColor = this.treemap.palette.length > 0 ? this.treemap.palette[k % this.treemap.palette.length] :
335
+ items[k as number]['data'][this.treemap.colorValuePath];
336
+ break;
337
+ }
338
+ }
339
+ }
340
+ }
341
+ if (this.treemap.enableDrillDown && !isNullOrUndefined(this.treemap.drilledLegendItems)) {
342
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
343
+ const childElement: any = this.treemap.drilledLegendItems;
344
+ if (!isNullOrUndefined(childElement['data']['options'])) {
345
+ legendFillColor = childElement['data']['options']['fill'];
346
+ } else {
347
+ for (let k: number = 0; k < childElement.length; k++) {
348
+ legendFillColor = this.treemap.palette.length > 0 ? this.treemap.palette[k % this.treemap.palette.length] :
349
+ childElement[k as number]['data'][this.treemap.colorValuePath];
350
+ break;
351
+ }
352
+ }
353
+ if (childElement['data']['isDrilled']) {
354
+ child = findChildren(childElement['data'])['values'];
355
+ } else {
356
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
357
+ const parentElement: any = childElement['data']['parent'];
358
+ child = findChildren(parentElement)['values'];
359
+ }
360
+ } else {
361
+ child = findChildren(data)['values'];
362
+ }
363
+ let isDuplicate: boolean;
364
+ let legendName: string;
365
+ if (child && child.length > 0) {
366
+ for (let i: number = 0; i < child.length; i++) {
367
+ if (isNullOrUndefined(child[i as number]['data'][this.treemap.legendSettings.showLegendPath]) ||
368
+ child[i as number]['data'][this.treemap.legendSettings.showLegendPath]) {
369
+ legendName = child[i as number]['data'][this.treemap.legendSettings.valuePath] ?
370
+ child[i as number]['data'][this.treemap.legendSettings.valuePath] : child[i as number]['name'];
371
+ isDuplicate = this.treemap.legendSettings.removeDuplicateLegend ?
372
+ this.removeDuplicates(this.legendCollections, legendName) : false;
373
+ if (!isDuplicate) {
374
+ this.legendCollections.push({
375
+ legendName: legendName,
376
+ legendFill: this.treemap.palette.length > 0 ? !isNullOrUndefined(this.treemap.currentLevel)
377
+ ? legendFillColor : this.treemap.palette[i % this.treemap.palette.length] :
378
+ child[i as number]['data'][this.treemap.colorValuePath],
379
+ legendData: [],
380
+ itemArea: child[i as number]['weight'],
381
+ levelOrderName: child[i as number]['levelOrderName']
382
+ });
383
+ }
384
+ }
385
+ }
386
+ this.legendCollections.sort(orderByArea);
387
+ if (this.treemap.palette.length > 0) {
388
+ for (let j: number = 0; j < this.legendCollections.length; j++) {
389
+ this.legendCollections[j as number]['legendFill'] = !isNullOrUndefined(this.treemap.currentLevel)
390
+ ? legendFillColor : this.treemap.palette[j % this.treemap.palette.length];
391
+ }
392
+ }
393
+ }
394
+ }
395
+
396
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
397
+ private calculateLegendItems(data: any[]): void {
398
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
399
+ let isAddData: any; let fill: string; let rangeValue: number;
400
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
401
+ let currentData: any; let legendText: string;
402
+ let isLeafItem: boolean; let colorMapProcess: boolean = false;
403
+ let colorMapping: ColorMappingModel[]; let groupIndex: number;
404
+ const leaf: LeafItemSettingsModel = this.treemap.leafItemSettings;
405
+ const levels: LevelSettingsModel[] = this.treemap.levels; let equalValue: string;
406
+ const position: LegendPosition = this.treemap.legendSettings.position;
407
+ let gradientElement: Element; let x2: string; let y2: string; let actualValue: string;
408
+ let isDuplicate: boolean; let isEqualColor: boolean; let isRange: boolean; let isDesaturation: boolean = false;
409
+ let legendIndex: number = 0; let outfill: string; let labelLegend: string; let otherIndex: number;
410
+ this.outOfRangeLegend = null;
411
+ for (let i: number = 0; i < data.length; i++) {
412
+ fill = ''; isEqualColor = false; isRange = false; isDesaturation = false;
413
+ currentData = data[i as number]['data'];
414
+ groupIndex = data[i as number]['groupIndex'];
415
+ isLeafItem = (this.treemap.levels.length === 0 || groupIndex === this.treemap.levels.length);
416
+ colorMapping = isLeafItem ? leaf.colorMapping : levels[groupIndex as number].colorMapping;
417
+ for (let j: number = 0; j < colorMapping.length; j ++) {
418
+ const colorMap: ColorMappingModel = colorMapping[j as number];
419
+ gradientElement = null;
420
+ rangeValue = Number(currentData[this.treemap.rangeColorValuePath]);
421
+ equalValue = currentData[this.treemap.equalColorValuePath];
422
+ colorMap.value = !isNullOrUndefined(colorMap.value) ? colorMap.value.toString() : colorMap.value;
423
+ if (!isNullOrUndefined(colorMap.from) && !isNullOrUndefined(colorMap.to) &&
424
+ rangeValue >= colorMap.from && rangeValue <= colorMap.to && colorMap.showLegend) {
425
+ colorMapProcess = true; isRange = true;
426
+ actualValue = colorMap.from + ' - ' + colorMap.to;
427
+ legendText = !isNullOrUndefined(colorMap.label) ? colorMap.label : colorMap.from + ' - ' + colorMap.to;
428
+ fill = isNullOrUndefined(colorMap.color) ? fill : <string>colorMap.color;
429
+ isAddData = this.isAddNewLegendData(actualValue);
430
+ } else if (!isNullOrUndefined(colorMap.value) && equalValue === colorMap.value && colorMap.showLegend) {
431
+ colorMapProcess = true; isEqualColor = true;
432
+ actualValue = colorMap.value.toString();
433
+ legendText = !isNullOrUndefined(colorMap.label) ? colorMap.label : colorMap.value.toString();
434
+ fill = isNullOrUndefined(colorMap.color) ? fill :
435
+ Object.prototype.toString.call(colorMap.color) === '[object Array]' ? colorMap.color[0] : <string>colorMap.color;
436
+ isAddData = this.isAddNewLegendData(actualValue);
437
+ }
438
+ if (colorMapProcess && isNullOrUndefined(colorMap.value) && colorMap.maxOpacity && colorMap.minOpacity
439
+ && this.treemap.legendSettings.mode === 'Interactive') {
440
+ const colors: GradientColor[] = []; isDesaturation = true;
441
+ if (Object.prototype.toString.call(colorMap.color) === '[object Array]') {
442
+ for (let q: number = 0; q < colorMap.color.length; q++) {
443
+ const offsetColor: number = 100 / (colorMap.color.length - 1);
444
+ const offsetValue: string = q * offsetColor + '%';
445
+ const stop1Color: GradientColor = { colorStop: offsetValue.toString(), color: colorMap.color[q as number] };
446
+ colors.push(stop1Color);
447
+ }
448
+ } else {
449
+ const stop1Color: GradientColor = { colorStop: '0%', color: fill };
450
+ const stop2Color: GradientColor = { colorStop: '100%', color: fill };
451
+ colors.push(stop1Color);
452
+ colors.push(stop2Color);
453
+ }
454
+ x2 = position === 'Top' || position === 'Bottom' ? '100%' : '0%';
455
+ y2 = position === 'Top' || position === 'Bottom' ? '0%' : '100%';
456
+ const gradient: LinearGradient = {
457
+ id: 'groupIndex_' + groupIndex + '_colorIndex_' + this.gradientCount, x1: '0%', y1: '0%', x2: x2, y2: y2
458
+ };
459
+ gradientElement = this.treemap.renderer.drawGradient('linearGradient', gradient, colors).childNodes[0] as Element;
460
+ if (Object.prototype.toString.call(colorMap.color) !== '[object Array]') {
461
+ (gradientElement.childNodes[0] as Element).setAttribute('stop-opacity', colorMap.minOpacity.toString());
462
+ (gradientElement.childNodes[1] as Element).setAttribute('stop-opacity', colorMap.maxOpacity.toString());
463
+ }
464
+ this.defsElement.appendChild(gradientElement);
465
+ this.gradientCount++;
466
+ }
467
+ isDuplicate = this.treemap.legendSettings.removeDuplicateLegend ?
468
+ this.removeDuplicates(this.legendCollections, legendText) : false;
469
+ if (isAddData && isAddData['process'] && colorMapProcess && !isDuplicate) {
470
+ colorMapProcess = false;
471
+ fill = ((Object.prototype.toString.call(colorMap.color) === '[object Array]')) && isNullOrUndefined(gradientElement)
472
+ && isNullOrUndefined(colorMap.value) ? this.legendGradientColor(colorMap, legendIndex) : fill;
473
+ this.legendCollections.push({
474
+ actualValue: actualValue, levelIndex: !isLeafItem ? j : -1, leafIndex: isLeafItem ? j : -1,
475
+ legendName: legendText, legendFill: fill, legendData: [], groupIndex: !isLeafItem ? groupIndex : -1,
476
+ gradientElement: !isNullOrUndefined(gradientElement) ? gradientElement : isNullOrUndefined(colorMap.value)
477
+ ? this.legendLinearGradient : null, name: data[i as number]['name'],
478
+ opacity: this.treemap.legendSettings.opacity, borderColor: this.treemap.legendSettings.border.color,
479
+ borderWidth: this.treemap.legendSettings.border.width
480
+ });
481
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
482
+ (<any[]>this.legendCollections[this.legendCollections.length - 1]['legendData']).push(data[i as number]);
483
+ legendIndex++;
484
+ } else if (colorMapProcess) {
485
+ colorMapProcess = false;
486
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
487
+ (<any[]>this.legendCollections[isAddData['value']]['legendData']).push(data[i as number]);
488
+ }
489
+ if (!isRange && !isDesaturation && !isEqualColor) {
490
+ if (isNullOrUndefined(colorMap.from) && isNullOrUndefined(colorMap.to)
491
+ && isNullOrUndefined(colorMap.minOpacity) &&
492
+ isNullOrUndefined(colorMap.maxOpacity) && isNullOrUndefined(colorMap.value) &&
493
+ !isNullOrUndefined(colorMap.color)) {
494
+ outfill = ((Object.prototype.toString.call(colorMap.color) === '[object Array]'))
495
+ ? colorMap.color[0] : <string>colorMap.color;
496
+ labelLegend = !isNullOrUndefined(colorMap.label) ? colorMap.label : 'Others';
497
+ isDuplicate = this.treemap.legendSettings.removeDuplicateLegend ?
498
+ this.removeDuplicates(this.legendCollections, labelLegend) : false;
499
+ if (isNullOrUndefined(this.outOfRangeLegend) && !isDuplicate) {
500
+ this.legendCollections.push({
501
+ actualValue: labelLegend, legendData: [],
502
+ legendName: labelLegend, legendFill: outfill, groupIndex: (!isLeafItem || groupIndex > -1) ? groupIndex : -1
503
+ });
504
+ otherIndex = this.legendCollections.length;
505
+ this.outOfRangeLegend = this.legendCollections[otherIndex - 1];
506
+ legendIndex++;
507
+ }
508
+ for (let k: number = this.legendCollections.length - 1; k >= 0; k--) {
509
+ if (this.legendCollections[k as number]['actualValue'] === (colorMap.label || 'Others')) {
510
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
511
+ (<any[]>this.legendCollections[k as number]['legendData']).push(data[i as number]);
512
+ break;
513
+ }
514
+ }
515
+
516
+ }
517
+ }
518
+ }
519
+ }
520
+ }
521
+
522
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
523
+ private removeDuplicates(legendCollection: any[], text: string): boolean {
524
+ let isDuplicate: boolean = false;
525
+ for (let i: number = 0; i < legendCollection.length; i++) {
526
+ if (legendCollection[i as number]['legendName'] === text) {
527
+ isDuplicate = true;
528
+ break;
529
+ } else {
530
+ continue;
531
+ }
532
+ }
533
+ return isDuplicate;
534
+ }
535
+
536
+
537
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
538
+ private isAddNewLegendData(legendText: string): any {
539
+ let newDataProcess: boolean; let itemValue: number;
540
+ if (this.legendCollections.length === 0) {
541
+ newDataProcess = true;
542
+ } else {
543
+ for (let j: number = 0; j < this.legendCollections.length; j++) {
544
+ if (legendText === this.legendCollections[j as number]['actualValue']) {
545
+ newDataProcess = false;
546
+ itemValue = j;
547
+ break;
548
+ } else if (j === this.legendCollections.length - 1) {
549
+ newDataProcess = true;
550
+ }
551
+ }
552
+ }
553
+ return { process: newDataProcess, value: itemValue };
554
+ }
555
+ // eslint-disable-next-line valid-jsdoc
556
+ /**
557
+ * To draw the legend
558
+ *
559
+ * @private
560
+ */
561
+ public drawLegend(): void {
562
+ const legend: LegendSettingsModel = <LegendSettingsModel>this.treemap.legendSettings;
563
+ const render: SvgRenderer = this.treemap.renderer; let fill: string;
564
+ let textOptions: TextOption; let gradientElement: Element;
565
+ const textFont: FontModel = legend.textStyle;
566
+ this.legendGroup = render.createGroup({ id: this.treemap.element.id + '_Legend_Group' });
567
+ this.renderLegendBorder();
568
+ this.renderLegendTitle();
569
+ if (legend.mode === 'Default') {
570
+ this.drawLegendItem(this.currentPage);
571
+ } else {
572
+ for (let i: number = 0; i < this.legendRenderingCollections.length; i++) {
573
+ const itemId: string = this.treemap.element.id + '_Legend_Index_' + i;
574
+ const textId: string = this.treemap.element.id + '_Legend_Index_' + i + '_Text';
575
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
576
+ const item: any = this.legendRenderingCollections[i as number];
577
+ gradientElement = item['element'];
578
+ fill = gradientElement ? 'url(#' + gradientElement.id + ')' : item['fill'];
579
+ const bounds: Rect = new Rect(item['x'], item['y'], item['width'], item['height']);
580
+ const textLocation: Location = new Location(item['textX'], item['textY']);
581
+
582
+ const rectOptions: RectOption = new RectOption(itemId, fill, legend.shapeBorder, legend.opacity, bounds);
583
+ if (this.treemap.enableRtl) {
584
+ if (this.treemap.legendSettings.position === 'Left' || this.treemap.legendSettings.position === 'Right'
585
+ || (this.treemap.legendSettings.position === 'Auto'
586
+ && this.treemap.availableSize.width >= this.treemap.availableSize.height)) {
587
+ rectOptions.y = (this.translate.y + this.legendBorderRect.y + this.legendBorderRect.height)
588
+ - (this.translate.y + rectOptions.height) - Math.abs(this.legendBorderRect.y - rectOptions.y);
589
+ textLocation.y = (this.translate.y + this.legendBorderRect.y + this.legendBorderRect.height)
590
+ - (this.translate.y) + (item['textHeight'] / 2)
591
+ - Math.abs(this.legendBorderRect.y - textLocation.y);
592
+ } else {
593
+ rectOptions.x = (this.translate.x + this.legendBorderRect.x + this.legendBorderRect.width)
594
+ - (this.translate.x + rectOptions.width)
595
+ - Math.abs(this.legendBorderRect.x - rectOptions.x);
596
+ textLocation.x = (this.translate.x + this.legendBorderRect.x + this.legendBorderRect.width)
597
+ - this.translate.x - Math.abs(this.legendBorderRect.x - textLocation.x);
598
+ }
599
+ }
600
+ const text: string = this.treemap.enableHtmlSanitizer ? (SanitizeHtmlHelper.sanitize(item['text'])) : item['text'];
601
+ textOptions = new TextOption(textId, textLocation.x, textLocation.y, 'middle', text, '', '');
602
+ renderTextElement(textOptions, textFont, textFont.color || this.treemap.themeStyle.legendTextColor, this.legendGroup);
603
+ const legendElement: Element = render.drawRectangle(rectOptions);
604
+ legendElement.setAttribute('tabindex', this.treemap.tabIndex.toString());
605
+ (legendElement as HTMLElement).style.outline = '';
606
+ this.legendGroup.appendChild(legendElement);
607
+ }
608
+ }
609
+ legendMaintain(this.treemap, this.legendGroup);
610
+ }
611
+
612
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
613
+ private defaultLegendRtlLocation(collection: any, spacing: number, treemap: TreeMap, legend: LegendSettingsModel): any {
614
+ const shapeLocation: Location = collection['Shape'];
615
+ const textLocation: Location = collection['Text'];
616
+ const legendText: string = collection['DisplayText'];
617
+ const textSize: Size = measureText(legendText, legend.textStyle);
618
+ shapeLocation.x = (this.translate.x + this.legendBorderRect.x + this.legendBorderRect.width)
619
+ - (this.translate.x + spacing) - Math.abs(this.legendBorderRect.x - shapeLocation.x);
620
+ textLocation.x = (this.translate.x + this.legendBorderRect.x + this.legendBorderRect.width)
621
+ - (this.translate.x + textSize.width + spacing) - Math.abs(this.legendBorderRect.x - textLocation.x);
622
+ if (treemap.legendSettings.position === 'Left' || treemap.legendSettings.position === 'Right'
623
+ || (treemap.legendSettings.position === 'Auto'
624
+ && this.treemap.availableSize.width >= this.treemap.availableSize.height)) {
625
+ shapeLocation.y = (this.translate.y + this.legendBorderRect.y + this.legendBorderRect.height)
626
+ - this.translate.y - Math.abs(Math.abs(this.legendBorderRect.y) - shapeLocation.y) - (legend.shapeHeight / 2);
627
+ textLocation.y = (this.translate.y + this.legendBorderRect.y + this.legendBorderRect.height)
628
+ - this.translate.y - Math.abs(Math.abs(this.legendBorderRect.y) - textLocation.y);
629
+ }
630
+ return { shapeLocation: shapeLocation, textLocation: textLocation };
631
+ }
632
+
633
+
634
+ private drawLegendItem(page: number): void {
635
+ const treemap: TreeMap = this.treemap; const spacing: number = 10;
636
+ const legend: LegendSettingsModel = <LegendSettingsModel>treemap.legendSettings;
637
+ const shapeSize: Size = new Size(legend.shapeWidth, legend.shapeHeight);
638
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
639
+ let textOptions: TextOption; let legendRtlLocation: any;
640
+ const render: SvgRenderer = treemap.renderer;
641
+ const shapeBorder: BorderModel = legend.shapeBorder; let eventArgs: ILegendItemRenderingEventArgs;
642
+ if (page >= 0 && page < this.totalPages.length) {
643
+ if (document.getElementById(this.legendGroup.id)) {
644
+ document.getElementById(this.legendGroup.id).remove();
645
+ }
646
+ const isLineShape: boolean = (legend.shape === 'HorizontalLine' || legend.shape === 'VerticalLine' || legend.shape === 'Cross');
647
+ const strokeColor: string = isLineShape ? isNullOrUndefined(legend.fill) ? '#000000' : legend.fill : shapeBorder.color;
648
+ const strokeWidth: number = isLineShape ? (shapeBorder.width === 0) ? 1 : shapeBorder.width : shapeBorder.width;
649
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
650
+ for (let i: number = 0; i < (<any[]>this.totalPages[page as number]['Collection']).length; i++) {
651
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
652
+ const collection: any = <any[]>this.totalPages[page as number]['Collection'][i as number];
653
+ const legendText: string = this.treemap.enableHtmlSanitizer ? SanitizeHtmlHelper.sanitize(collection['DisplayText']) : collection['DisplayText'];
654
+ const legendElement: Element = render.createGroup({ id: treemap.element.id + '_Legend_Index_' + i });
655
+ legendElement.setAttribute('aria-label', legendText + ' Legend');
656
+ legendElement.setAttribute('role', 'region');
657
+ legendElement.setAttribute('tabindex', this.treemap.tabIndex.toString());
658
+ (legendElement as HTMLElement).style.outline = 'none';
659
+ const shapeId: string = treemap.element.id + '_Legend_Shape_Index_' + i;
660
+ const textId: string = treemap.element.id + '_Legend_Text_Index_' + i;
661
+ let shapeLocation: Location = collection['Shape'];
662
+ let textLocation: Location = collection['Text'];
663
+ if (treemap.enableRtl) {
664
+ legendRtlLocation = this.defaultLegendRtlLocation(collection, spacing, treemap, legend);
665
+ shapeLocation = legendRtlLocation['shapeLocation'];
666
+ textLocation = legendRtlLocation['textLocation'];
667
+ }
668
+ eventArgs = {
669
+ cancel: false, name: legendItemRendering, treemap: treemap, fill: collection['Fill'],
670
+ shape: legend.shape, imageUrl: legend.imageUrl
671
+ };
672
+ treemap.trigger(legendItemRendering, eventArgs, (observedArgs: ILegendItemRenderingEventArgs) => {
673
+ const renderOptions: PathOption = new PathOption(
674
+ shapeId, observedArgs.fill, strokeWidth, isLineShape ? collection['Fill'] : strokeColor, legend.opacity, ''
675
+ );
676
+ legendElement.appendChild(
677
+ drawSymbol(shapeLocation, observedArgs.shape, shapeSize, observedArgs.imageUrl, renderOptions));
678
+ textOptions = new TextOption(textId, textLocation.x, textLocation.y, 'start', legendText, '', '');
679
+ renderTextElement(
680
+ textOptions, legend.textStyle, legend.textStyle.color || treemap.themeStyle.legendTextColor, legendElement
681
+ );
682
+ this.legendGroup.appendChild(legendElement);
683
+ });
684
+ }
685
+ let pagingGroup: Element; const width: number = spacing; const height: number = (spacing / 2);
686
+ if (this.page !== 0) {
687
+ const pagingText: string = (page + 1) + '/' + this.totalPages.length;
688
+ const pagingFont: FontModel = legend.textStyle; const pagingTextSize: Size = measureText(pagingText, pagingFont);
689
+ const leftPageX: number = (this.legendItemRect.x + this.legendItemRect.width) - pagingTextSize.width -
690
+ (width * 2) - spacing;
691
+ const rightPageX: number = (this.legendItemRect.x + this.legendItemRect.width);
692
+ const locY: number = (this.legendItemRect.y + this.legendItemRect.height) + (height / 2) + spacing;
693
+ const pageTextX: number = rightPageX - width - (pagingTextSize.width / 2) - (spacing / 2);
694
+ pagingGroup = render.createGroup({ id: treemap.element.id + '_Legend_Paging_Group' });
695
+ const leftPageElement: Element = render.createGroup({ id: treemap.element.id + '_Legend_Left_Paging_Group' });
696
+ const rightPageElement: Element = render.createGroup({ id: treemap.element.id + '_Legend_Right_Paging_Group' });
697
+ const rightPath: string = ' M ' + rightPageX + ' ' + locY + ' L ' + (rightPageX - width) + ' ' + (locY - height) +
698
+ ' L ' + (rightPageX - width) + ' ' + (locY + height) + ' z ';
699
+ const leftPath: string = ' M ' + leftPageX + ' ' + locY + ' L ' + (leftPageX + width) + ' ' + (locY - height) +
700
+ ' L ' + (leftPageX + width) + ' ' + (locY + height) + ' z ';
701
+ const leftPageOptions: PathOption = new PathOption(
702
+ treemap.element.id + '_Left_Page', '#a6a6a6', 0, '#a6a6a6', 1, '', leftPath
703
+ );
704
+ leftPageElement.appendChild(render.drawPath(leftPageOptions));
705
+ const leftRectPageOptions: RectOption = new RectOption(
706
+ treemap.element.id + '_Left_Page_Rect', 'transparent', {}, 1,
707
+ new Rect(leftPageX - (width / 2), (locY - (height * 2)), width * 2, spacing * 2), ''
708
+ );
709
+ leftPageElement.appendChild(render.drawRectangle(leftRectPageOptions));
710
+ this.wireEvents(leftPageElement);
711
+ const rightPageOptions: PathOption = new PathOption(
712
+ treemap.element.id + '_Right_Page', '#a6a6a6', 0, '#a6a6a6', 1, '', rightPath
713
+ );
714
+ rightPageElement.appendChild(render.drawPath(rightPageOptions));
715
+ const rightRectPageOptions: RectOption = new RectOption(
716
+ treemap.element.id + '_Right_Page_Rect', 'transparent', {}, 1,
717
+ new Rect((rightPageX - width), (locY - height), width, spacing), ''
718
+ );
719
+ rightPageElement.appendChild(render.drawRectangle(rightRectPageOptions));
720
+ this.wireEvents(rightPageElement);
721
+ pagingGroup.appendChild(leftPageElement);
722
+ pagingGroup.appendChild(rightPageElement);
723
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
724
+ const pageTextOptions: any = {
725
+ 'id': treemap.element.id + '_Paging_Text',
726
+ 'x': pageTextX,
727
+ 'y': locY + (pagingTextSize.height / 4),
728
+ 'fill': '#a6a6a6',
729
+ 'font-size': '14px',
730
+ 'font-style': pagingFont.fontStyle,
731
+ 'font-family': pagingFont.fontFamily,
732
+ 'font-weight': pagingFont.fontWeight,
733
+ 'text-anchor': 'middle',
734
+ 'transform': '',
735
+ 'opacity': 1,
736
+ 'dominant-baseline': '',
737
+ 'role': 'region',
738
+ 'aria-label': pagingText
739
+ };
740
+ pagingGroup.appendChild(render.createText(pageTextOptions, pagingText));
741
+ this.legendGroup.appendChild(pagingGroup);
742
+ }
743
+ }
744
+ }
745
+ private renderLegendBorder(): void {
746
+ const treemap: TreeMap = this.treemap;
747
+ const legend: LegendSettingsModel = <LegendSettingsModel>treemap.legendSettings;
748
+ const legendTitle: string = legend.title.text;
749
+ const spacing: number = 10;
750
+ const textStyle: FontModel = legend.titleStyle;
751
+ const title: string = textTrim((this.legendItemRect.width + (spacing * 2)), legendTitle, textStyle);
752
+ const textSize: Size = measureText(title, textStyle);
753
+ this.legendBorderRect = new Rect(
754
+ (this.legendItemRect.x - spacing),
755
+ (this.legendItemRect.y - spacing - textSize.height),
756
+ (this.legendItemRect.width) + (spacing * 2),
757
+ (this.legendItemRect.height) + (spacing * 2) + textSize.height +
758
+ (legend.mode === 'Interactive' ? 0 : (this.page !== 0) ? spacing : 0)
759
+ );
760
+ const borderStyle: BorderModel = {
761
+ color: legend.border.color || this.treemap.themeStyle.legendBorderColor,
762
+ width: legend.border.width || this.treemap.themeStyle.legendBorderWidth
763
+ };
764
+ const renderOptions: RectOption = new RectOption(
765
+ treemap.element.id + '_Legend_Border', legend.background, borderStyle, 1, this.legendBorderRect, ''
766
+ );
767
+ const legendBorder: Element = treemap.renderer.drawRectangle(renderOptions);
768
+ (legendBorder as HTMLElement).style.pointerEvents = 'none';
769
+ this.legendGroup.appendChild(legendBorder);
770
+ this.getLegendAlignment(treemap, this.legendBorderRect.width, this.legendBorderRect.height, legend);
771
+ this.legendGroup.setAttribute('transform', 'translate( ' + (this.translate.x + (-(this.legendBorderRect.x))) + ' ' +
772
+ (this.translate.y + (-(this.legendBorderRect.y))) + ' )');
773
+ treemap.svgObject.appendChild(this.legendGroup);
774
+ }
775
+
776
+ private renderLegendTitle(): void {
777
+ const legend: LegendSettingsModel = <LegendSettingsModel>this.treemap.legendSettings;
778
+ const textStyle: FontModel = legend.titleStyle;
779
+ const legendTitle: string = this.treemap.enableHtmlSanitizer ? (SanitizeHtmlHelper.sanitize(legend.title.text)) : legend.title.text;
780
+ let textOptions: TextOption; const spacing: number = 10;
781
+ const trimTitle: string = textTrim((this.legendItemRect.width + (spacing * 2)), legendTitle, textStyle);
782
+ const textSize: Size = measureText(trimTitle, textStyle);
783
+ if (legendTitle) {
784
+ textOptions = new TextOption(
785
+ this.treemap.element.id + '_LegendTitle',
786
+ (this.legendItemRect.x) + (this.legendItemRect.width / 2),
787
+ this.legendItemRect.y - (textSize.height / 2) - (spacing / 2),
788
+ 'middle', trimTitle, '');
789
+ const textElement: Element = renderTextElement(textOptions, textStyle, textStyle.color ||
790
+ this.treemap.themeStyle.legendTitleColor, this.legendGroup);
791
+ textElement.setAttribute('role', 'region');
792
+ textElement.setAttribute('aria-label', legendTitle);
793
+ }
794
+ }
795
+ /**
796
+ * To rendered the interactive pointer
797
+ *
798
+ * @param {PointerEvent | TouchEvent} e - Specifies the pointer argument.
799
+ * @returns {void}
800
+ * @private
801
+ */
802
+ public renderInteractivePointer(e: PointerEvent | TouchEvent): void {
803
+ const treemap: TreeMap = this.treemap; let target: Element = <Element>e.target;
804
+ const interactiveId: string = treemap.element.id + '_Interactive_Legend';
805
+ let pointerDrawn: boolean = false;
806
+ target = !(e.type.indexOf('touch') > -1) ? target :
807
+ document.elementFromPoint((<TouchEvent>e).changedTouches[0].clientX, (<TouchEvent>e).changedTouches[0].clientY);
808
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
809
+ let targetItem: any; const legend: LegendSettingsModel = <LegendSettingsModel>treemap.legendSettings;
810
+ if (target.id.indexOf('_Item_Index') > -1 && legend.visible && this.legendRenderingCollections.length > 0) {
811
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
812
+ let currentData: any; let legendRect: ClientRect;
813
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
814
+ let data: any[]; let fill: string; let stroke: string; let strokeWidth: number; let legendElement: Element;
815
+ targetItem = treemap.layout.renderItems[parseFloat(target.id.split('_Item_Index_')[1])];
816
+ const svgRect: ClientRect = treemap.svgObject.getBoundingClientRect();
817
+ for (let i: number = 0; i < this.legendCollections.length && !pointerDrawn; i++) {
818
+ currentData = this.legendCollections[i as number];
819
+ legendElement = document.getElementById(treemap.element.id + '_Legend_Index_' + i);
820
+ legendRect = <ClientRect>legendElement.getBoundingClientRect();
821
+ const rect: Rect = new Rect(
822
+ Math.abs(legendRect.left - svgRect.left), Math.abs(legendRect.top - svgRect.top),
823
+ legendRect.width, legendRect.height
824
+ );
825
+ fill = legendElement.getAttribute('fill');
826
+ stroke = legend.shapeBorder.color;
827
+ strokeWidth = legend.shapeBorder.width;
828
+ if (!isNullOrUndefined(currentData['legendData']) && currentData['legendData'].length > 0) {
829
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
830
+ data = <any[]>currentData['legendData'];
831
+ const valuePath: string = treemap.rangeColorValuePath;
832
+ if (targetItem['levelOrderName'].indexOf(this.legendCollections[i as number]['legendName']) > -1) {
833
+ this.drawInteractivePointer(legend, fill, stroke, interactiveId, strokeWidth, rect);
834
+ pointerDrawn = true;
835
+ } else {
836
+ for (let j: number = 0; j < data.length; j++) {
837
+ if ((treemap.rangeColorValuePath && treemap.leafItemSettings.colorMapping.length > 0)
838
+ ? data[j as number]['data'][valuePath as string] === targetItem['data'][valuePath as string]
839
+ : (data[j as number]['levelOrderName'] === targetItem['levelOrderName'] ||
840
+ data[j as number]['levelOrderName'].indexOf(targetItem['levelOrderName']) > -1)) {
841
+ this.drawInteractivePointer(legend, fill, stroke, interactiveId, strokeWidth, rect);
842
+ pointerDrawn = true;
843
+ break;
844
+ }
845
+ }
846
+ }
847
+ } else if (this.treemap.leafItemSettings.colorMapping.length === 0 && this.treemap.palette) {
848
+ if (targetItem['levelOrderName'].indexOf(currentData['levelOrderName']) > -1 ) {
849
+ this.drawInteractivePointer(legend, fill, stroke, interactiveId, strokeWidth, rect);
850
+ pointerDrawn = true;
851
+ }
852
+ }
853
+ }
854
+ } else {
855
+ this.removeInteractivePointer();
856
+ }
857
+ }
858
+
859
+ private drawInteractivePointer(
860
+ legend: LegendSettingsModel, fill: string, stroke: string, id: string, strokeWidth: number, rect: Rect
861
+ ): void {
862
+ let path: string;
863
+ let locX: number; let locY: number;
864
+ const height: number = 10; const width: number = 10;
865
+ const direction: LegendOrientation = (legend.orientation === 'None') ? (legend.position === 'Top' || legend.position === 'Bottom')
866
+ ? 'Horizontal' : 'Vertical' : legend.orientation;
867
+ if (direction === 'Horizontal') {
868
+ if (!legend.invertedPointer) {
869
+ locX = rect.x + (rect.width / 2);
870
+ locY = rect.y;
871
+ path = ' M ' + locX + ' ' + locY + ' L ' + (locX - width) + ' ' + (locY - height) +
872
+ ' L ' + (locX + width) + ' ' + (locY - height) + ' Z ';
873
+ } else {
874
+ locX = rect.x + (rect.width / 2);
875
+ locY = rect.y + (rect.height);
876
+ path = ' M ' + locX + ' ' + locY + ' L ' + (locX - width) + ' ' + (locY + height) +
877
+ ' L ' + (locX + width) + ' ' + (locY + height) + ' Z ';
878
+ }
879
+ } else {
880
+ if (!legend.invertedPointer) {
881
+ locX = rect.x + (rect.width);
882
+ locY = rect.y + (rect.height / 2);
883
+ path = ' M ' + locX + ' ' + locY + ' L ' + (locX + width) + ' ' + (locY - height) +
884
+ ' L ' + (locX + width) + ' ' + (locY + height) + ' z ';
885
+ } else {
886
+ locX = rect.x;
887
+ locY = rect.y + (rect.height / 2);
888
+ path = ' M ' + locX + ' ' + locY + ' L ' + (locX - width) + ' ' + (locY - height) +
889
+ ' L ' + (locX - width) + ' ' + (locY + height) + ' z ';
890
+ }
891
+ }
892
+ const pathOptions: PathOption = new PathOption(id, fill, strokeWidth, stroke, 1, '', path);
893
+ this.treemap.svgObject.appendChild(this.treemap.renderer.drawPath(pathOptions) as SVGPathElement);
894
+ }
895
+
896
+
897
+ private getLegendAlignment(treemap: TreeMap, width: number, height: number, legend: LegendSettingsModel): void {
898
+ let x: number; let y: number;
899
+ const spacing: number = 10; let totalRect: Rect;
900
+ // eslint-disable-next-line prefer-const
901
+ totalRect = extend({}, treemap.areaRect, totalRect, true) as Rect;
902
+ const areaX: number = totalRect.x;
903
+ const areaY: number = totalRect.y;
904
+ const areaHeight: number = totalRect.height;
905
+ const areaWidth: number = totalRect.width;
906
+ const totalWidth: number = treemap.availableSize.width;
907
+ const totalHeight: number = treemap.availableSize.height;
908
+ const position: string = legend.position === 'Auto' ? (totalWidth > totalHeight) ? 'Right' : 'Bottom' : legend.position;
909
+ if (legend.position === 'Float') {
910
+ this.translate = legend.location;
911
+ } else {
912
+ switch (position) {
913
+ case 'Top':
914
+ case 'Bottom':
915
+ totalRect.height = (areaHeight - height);
916
+ x = (totalWidth / 2) - (width / 2);
917
+ y = (position === 'Top') ? areaY : (areaY + totalRect.height) + spacing;
918
+ totalRect.y = (position === 'Top') ? areaY + height + spacing : areaY;
919
+ break;
920
+ case 'Left':
921
+ case 'Right':
922
+ totalRect.width = (areaWidth - width);
923
+ x = (position === 'Left') ? areaX : areaX + totalRect.width;
924
+ y = (totalHeight / 2) - (height / 2);
925
+ totalRect.x = (position === 'Left') ? areaX + width : areaX;
926
+ break;
927
+ }
928
+ switch (legend.alignment) {
929
+ case 'Near':
930
+ if (position === 'Top' || position === 'Bottom') {
931
+ x = totalRect.x;
932
+ } else {
933
+ y = totalRect.y;
934
+ }
935
+ break;
936
+ case 'Far':
937
+ if (position === 'Top' || position === 'Bottom') {
938
+ x = totalWidth - width;
939
+ } else {
940
+ y = totalHeight - height;
941
+ }
942
+ break;
943
+ }
944
+ this.treemap.totalRect = totalRect;
945
+ this.translate = new Location(x, y);
946
+ }
947
+ }
948
+ /**
949
+ * @param {PointerEvent} e - Specifies the event.
950
+ * @returns {void}
951
+ * @private
952
+ */
953
+ public mouseUpHandler(e: PointerEvent): void {
954
+ this.renderInteractivePointer(e);
955
+ clearTimeout(this.clearTimeout);
956
+ this.clearTimeout = setTimeout(this.removeInteractivePointer.bind(this), 3000);
957
+ }
958
+ // eslint-disable-next-line valid-jsdoc
959
+ /**
960
+ * To remove the interactive pointer
961
+ *
962
+ * @private
963
+ */
964
+ public removeInteractivePointer(): void {
965
+ if (document.getElementById(this.treemap.element.id + '_Interactive_Legend')) {
966
+ const legendElementId: HTMLElement = document.getElementById(this.treemap.element.id + '_Interactive_Legend');
967
+ legendElementId.parentNode.removeChild(legendElementId);
968
+ }
969
+ }
970
+ /**
971
+ * To change the next page
972
+ *
973
+ * @param {PointerEvent} e - Specifies the pointer event argument.
974
+ * @returns {void}
975
+ * @private
976
+ */
977
+ public changeNextPage(e: PointerEvent): void {
978
+ this.currentPage = ((<Element>e.target).id.indexOf('_Left_Page_') > -1) ? (this.currentPage - 1) :
979
+ (this.currentPage + 1);
980
+ if (this.currentPage >= 0 && this.currentPage < this.totalPages.length) {
981
+ this.drawLegend();
982
+ } else {
983
+ this.currentPage = ((<Element>e.target).id.indexOf('_Left_Page_') > -1) ? 0 : this.totalPages.length - 1;
984
+ }
985
+ }
986
+ /**
987
+ * Wire events for event handler
988
+ *
989
+ * @param {Element} element - Specifies the element.
990
+ * @returns {void}
991
+ * @private
992
+ */
993
+ public wireEvents(element: Element): void {
994
+ EventHandler.add(element, Browser.touchStartEvent, this.changeNextPage, this);
995
+ }
996
+ // eslint-disable-next-line valid-jsdoc
997
+ /**
998
+ * To add the event listener
999
+ *
1000
+ * @private
1001
+ */
1002
+ public addEventListener(): void {
1003
+ if (this.treemap.isDestroyed) {
1004
+ return;
1005
+ }
1006
+ this.treemap.on(Browser.touchMoveEvent, this.renderInteractivePointer, this);
1007
+ this.treemap.on(Browser.touchEndEvent, this.mouseUpHandler, this);
1008
+ }
1009
+ // eslint-disable-next-line valid-jsdoc
1010
+ /**
1011
+ * To remove the event listener
1012
+ *
1013
+ * @private
1014
+ */
1015
+ public removeEventListener(): void {
1016
+ if (this.treemap.isDestroyed) {
1017
+ return;
1018
+ }
1019
+ this.treemap.off(Browser.touchMoveEvent, this.renderInteractivePointer);
1020
+ this.treemap.off(Browser.touchEndEvent, this.mouseUpHandler);
1021
+ }
1022
+
1023
+ /**
1024
+ * Get module name.
1025
+ *
1026
+ * @returns {string} Returns the legend module name.
1027
+ */
1028
+ protected getModuleName(): string {
1029
+ return 'treeMapLegend';
1030
+ }
1031
+
1032
+ /**
1033
+ * To destroy the legend.
1034
+ *
1035
+ * @returns {void}
1036
+ * @private
1037
+ */
1038
+ public destroy(): void {
1039
+ clearTimeout(this.clearTimeout);
1040
+ this.clearTimeout = null;
1041
+ this.legendRenderingCollections = [];
1042
+ this.legendCollections = [];
1043
+ this.outOfRangeLegend = null;
1044
+ this.totalPages = [];
1045
+ this.translate = null;
1046
+ this.legendBorderRect = null;
1047
+ this.legendGroup = null;
1048
+ this.legendNames = [];
1049
+ this.defsElement = null;
1050
+ this.legendLinearGradient = null;
1051
+ this.legendInteractiveGradient = [];
1052
+ this.legendItemRect = null;
1053
+ this.removeEventListener();
1054
+ this.treemap = null;
1055
+ }
1056
+ /**
1057
+ * Get the gradient color for interactive legend.
1058
+ *
1059
+ * @param {ColorMappingModel} colorMap - Specifies the color mapping instance.
1060
+ * @param {number} legendIndex - Specifies the index of legend.
1061
+ * @returns {string} - Returns the legend color.
1062
+ * @private
1063
+ */
1064
+ public legendGradientColor(colorMap: ColorMappingModel, legendIndex: number): string {
1065
+ let legendFillColor: string;
1066
+ const xmlns: string = 'http://www.w3.org/2000/svg';
1067
+ if (!isNullOrUndefined(colorMap.color) && Object.prototype.toString.call(colorMap.color) === '[object Array]') {
1068
+ const defElement: Element = this.treemap.renderer.createDefs();
1069
+ const linerGradientEle: Element = document.createElementNS(xmlns, 'linearGradient');
1070
+ const opacity: number = 1; const position: LegendPosition = this.treemap.legendSettings.position;
1071
+ const x2: string = position === 'Top' || position === 'Bottom' ? '100' : '0';
1072
+ const y2: string = position === 'Top' || position === 'Bottom' ? '0' : '100';
1073
+ linerGradientEle.setAttribute('id', 'linear_' + legendIndex);
1074
+ linerGradientEle.setAttribute('x1', 0 + '%');
1075
+ linerGradientEle.setAttribute('y1', 0 + '%');
1076
+ linerGradientEle.setAttribute('x2', x2 + '%');
1077
+ linerGradientEle.setAttribute('y2', y2 + '%');
1078
+ for (let b: number = 0; b < colorMap.color.length; b++) {
1079
+ const offsetColor: number = 100 / (colorMap.color.length - 1);
1080
+ const stopEle: Element = document.createElementNS(xmlns, 'stop');
1081
+ stopEle.setAttribute('offset', b * offsetColor + '%');
1082
+ stopEle.setAttribute('stop-color', colorMap.color[b as number]);
1083
+ stopEle.setAttribute('stop-opacity', opacity.toString());
1084
+ linerGradientEle.appendChild(stopEle);
1085
+ }
1086
+ defElement.appendChild(linerGradientEle);
1087
+ this.legendLinearGradient = linerGradientEle;
1088
+ const color: string = 'url(' + '#linear_' + legendIndex + ')';
1089
+ this.defsElement.appendChild(linerGradientEle);
1090
+ legendFillColor = color;
1091
+ }
1092
+
1093
+ return legendFillColor;
1094
+ }
1095
+ }