@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.
- package/.eslintrc.json +2 -0
- package/dist/ej2-treemap.min.js +2 -2
- package/dist/ej2-treemap.umd.min.js +2 -2
- package/dist/ej2-treemap.umd.min.js.map +1 -1
- package/dist/es6/ej2-treemap.es2015.js +1 -1
- package/dist/es6/ej2-treemap.es2015.js.map +1 -1
- package/dist/es6/ej2-treemap.es5.js +1 -1
- package/dist/es6/ej2-treemap.es5.js.map +1 -1
- package/dist/global/ej2-treemap.min.js +2 -2
- package/dist/global/ej2-treemap.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/dist/ts/index.d.ts +4 -0
- package/dist/ts/index.ts +4 -0
- package/dist/ts/treemap/index.d.ts +19 -0
- package/dist/ts/treemap/index.ts +19 -0
- package/dist/ts/treemap/layout/legend.d.ts +137 -0
- package/dist/ts/treemap/layout/legend.ts +1095 -0
- package/dist/ts/treemap/layout/render-panel.d.ts +47 -0
- package/dist/ts/treemap/layout/render-panel.ts +758 -0
- package/dist/ts/treemap/model/base-model.d.ts +795 -0
- package/dist/ts/treemap/model/base.d.ts +671 -0
- package/dist/ts/treemap/model/base.ts +798 -0
- package/dist/ts/treemap/model/constants.d.ts +117 -0
- package/dist/ts/treemap/model/constants.ts +118 -0
- package/dist/ts/treemap/model/image-export.d.ts +34 -0
- package/dist/ts/treemap/model/image-export.ts +117 -0
- package/dist/ts/treemap/model/interface.d.ts +555 -0
- package/dist/ts/treemap/model/interface.ts +583 -0
- package/dist/ts/treemap/model/pdf-export.d.ts +36 -0
- package/dist/ts/treemap/model/pdf-export.ts +105 -0
- package/dist/ts/treemap/model/print.d.ts +45 -0
- package/dist/ts/treemap/model/print.ts +106 -0
- package/dist/ts/treemap/model/theme.d.ts +19 -0
- package/dist/ts/treemap/model/theme.ts +450 -0
- package/dist/ts/treemap/treemap-model.d.ts +374 -0
- package/dist/ts/treemap/treemap.d.ts +724 -0
- package/dist/ts/treemap/treemap.ts +1817 -0
- package/dist/ts/treemap/user-interaction/highlight-selection.d.ts +118 -0
- package/dist/ts/treemap/user-interaction/highlight-selection.ts +799 -0
- package/dist/ts/treemap/user-interaction/tooltip.d.ts +42 -0
- package/dist/ts/treemap/user-interaction/tooltip.ts +228 -0
- package/dist/ts/treemap/utils/enum.d.ts +256 -0
- package/dist/ts/treemap/utils/enum.ts +263 -0
- package/dist/ts/treemap/utils/helper.d.ts +543 -0
- package/dist/ts/treemap/utils/helper.ts +1453 -0
- package/package.json +12 -13
- package/src/treemap/utils/helper.js +1 -1
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
import { TreeMap } from '../treemap';
|
|
2
|
+
import {
|
|
3
|
+
Rect, itemsToOrder, TextOption, Size, measureText, textTrim, hide, wordWrap, textWrap,
|
|
4
|
+
getTemplateFunction, convertElement, findLabelLocation, PathOption, textFormatter, ColorValue, colorNameToHex, convertHexToColor,
|
|
5
|
+
colorMap, measureElement, convertToContainer, convertToRect, getShortestEdge, getArea, orderByArea, isParentItem, maintainSelection
|
|
6
|
+
} from '../utils/helper';
|
|
7
|
+
import { isNullOrUndefined, createElement, extend, SanitizeHtmlHelper } from '@syncfusion/ej2-base';
|
|
8
|
+
import { SvgRenderer } from '@syncfusion/ej2-svg-base';
|
|
9
|
+
import { Location, findChildren, renderTextElement } from '../utils/helper';
|
|
10
|
+
import { LevelSettings, LeafItemSettings } from '../model/base';
|
|
11
|
+
import { LabelPosition, LabelAlignment } from '../utils/enum';
|
|
12
|
+
import { BorderModel, FontModel, ColorMappingModel, LevelSettingsModel, LeafItemSettingsModel } from '../model/base-model';
|
|
13
|
+
import { IItemRenderingEventArgs } from '../model/interface';
|
|
14
|
+
import { itemRendering } from '../model/constants';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* To calculate and render the shape layer
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export class LayoutPanel {
|
|
21
|
+
private treemap: TreeMap;
|
|
22
|
+
private currentRect: Rect;
|
|
23
|
+
public layoutGroup: Element;
|
|
24
|
+
private renderer: SvgRenderer;
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
public renderItems: any[];
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
private parentData: any[];
|
|
29
|
+
constructor(treemap: TreeMap) {
|
|
30
|
+
this.treemap = treemap;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public processLayoutPanel(): void {
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
+
let data: any[] | any; let totalRect: Rect;
|
|
36
|
+
if (this.treemap.treemapLevelData.levelsData && this.treemap.treemapLevelData.levelsData.length > 0) {
|
|
37
|
+
data = (!isNullOrUndefined(this.treemap.initialDrillDown.groupIndex) &&
|
|
38
|
+
!isNullOrUndefined(this.treemap.initialDrillDown.groupName)) &&
|
|
39
|
+
(isNullOrUndefined(this.treemap.drilledItems) ? isNullOrUndefined(this.treemap.drilledItems)
|
|
40
|
+
: this.treemap.drilledItems.length === 0) ?
|
|
41
|
+
this.getDrilldownData(this.treemap.treemapLevelData.levelsData[0], [])[0] : this.treemap.treemapLevelData.levelsData[0];
|
|
42
|
+
totalRect = extend({}, this.treemap.areaRect, totalRect, false) as Rect;
|
|
43
|
+
if (!isNullOrUndefined(this.treemap.treeMapLegendModule) && !isNullOrUndefined(this.treemap.totalRect)) {
|
|
44
|
+
if (this.treemap.legendSettings.position !== 'Float') {
|
|
45
|
+
totalRect = this.treemap.totalRect;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (!isNullOrUndefined(this.treemap.currentLevel) &&
|
|
49
|
+
(isNullOrUndefined(this.treemap.drilledItems) ? !isNullOrUndefined(this.treemap.drilledItems)
|
|
50
|
+
: this.treemap.drilledItems.length !== 0)) {
|
|
51
|
+
const count: number = this.treemap.drilledItems.length - 1;
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
const x: any = this.treemap.drilledItems[count as number]['data'];
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
const y: any = {};
|
|
56
|
+
y[this.treemap.drilledItems[count as number]['data']['groupName']] = [x];
|
|
57
|
+
if (!isNullOrUndefined(this.treemap.initialDrillDown.groupIndex) && !this.treemap.enableBreadcrumb) {
|
|
58
|
+
this.treemap.currentLevel = this.treemap.drilledItems[count as number]['data']['groupIndex'];
|
|
59
|
+
}
|
|
60
|
+
this.calculateLayoutItems(y || this.treemap.treemapLevelData.levelsData[0], totalRect);
|
|
61
|
+
this.renderLayoutItems();
|
|
62
|
+
} else {
|
|
63
|
+
if (!isNullOrUndefined(this.treemap.initialDrillDown.groupIndex) &&
|
|
64
|
+
(isNullOrUndefined(this.treemap.drilledItems) ? isNullOrUndefined(this.treemap.drilledItems)
|
|
65
|
+
: this.treemap.drilledItems.length === 0)) {
|
|
66
|
+
this.treemap.currentLevel = this.treemap.initialDrillDown.groupIndex;
|
|
67
|
+
}
|
|
68
|
+
this.calculateLayoutItems(data || this.treemap.treemapLevelData.levelsData[0], totalRect);
|
|
69
|
+
this.renderLayoutItems();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
+
private getDrilldownData(data: any, drillData: any[]): any {
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
|
+
const treemap: TreeMap = this.treemap; const newData: any = {};
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
|
+
const child: any[] = findChildren(data)['values'];
|
|
80
|
+
if (child && child.length > 0 && drillData.length === 0) {
|
|
81
|
+
for (let i: number = 0; i < child.length; i++) {
|
|
82
|
+
if (child[i as number]['groupIndex'] === treemap.initialDrillDown.groupIndex &&
|
|
83
|
+
child[i as number]['name'] === treemap.initialDrillDown.groupName) {
|
|
84
|
+
child[i as number]['isDrilled'] = true;
|
|
85
|
+
newData[child[i as number]['groupName']] = [child[i as number]];
|
|
86
|
+
drillData.push(newData);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (let j: number = 0; j < child.length; j++) {
|
|
90
|
+
this.getDrilldownData(child[j as number], drillData);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return drillData;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
+
public calculateLayoutItems(data: any, rect: Rect): void {
|
|
98
|
+
this.renderItems = [];
|
|
99
|
+
this.parentData = [];
|
|
100
|
+
if (!isNullOrUndefined(this.treemap.weightValuePath)) {
|
|
101
|
+
if (this.treemap.layoutType.indexOf('SliceAndDice') > -1) {
|
|
102
|
+
this.computeSliceAndDiceDimensional(data, rect);
|
|
103
|
+
} else {
|
|
104
|
+
rect.height = rect.height + rect.y;
|
|
105
|
+
rect.width = rect.width + rect.x;
|
|
106
|
+
this.computeSquarifyDimensional(data, rect);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
112
|
+
private computeSliceAndDiceDimensional(data: any, coords: Rect): any {
|
|
113
|
+
const leafItem: LeafItemSettings = this.treemap.leafItemSettings as LeafItemSettings;
|
|
114
|
+
let rect: Rect; const groups: LevelSettings[] = this.treemap.levels as LevelSettings[];
|
|
115
|
+
let groupIndex: number; let isLeafItem: boolean = false;
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
|
+
const children: any[] = findChildren(data)['values'];
|
|
118
|
+
let gap: number; let headerHeight: number;
|
|
119
|
+
if (children && children.length > 0) {
|
|
120
|
+
this.sliceAndDiceProcess(children, coords);
|
|
121
|
+
if (this.treemap.levels.length > 0) {
|
|
122
|
+
for (let i: number = 0; i < children.length; i++) {
|
|
123
|
+
groupIndex = children[i as number]['groupIndex'];
|
|
124
|
+
isLeafItem = (groups.length === 0 || groupIndex === groups.length);
|
|
125
|
+
gap = isLeafItem ? leafItem.gap : groups[groupIndex as number].groupGap;
|
|
126
|
+
headerHeight = groups.length === 0 ? 0 : groups[groupIndex as number] ? groups[groupIndex as number].showHeader ?
|
|
127
|
+
groups[groupIndex as number].headerHeight : 0 : groups[groupIndex - 1].showHeader ?
|
|
128
|
+
groups[groupIndex - 1].headerHeight : 0;
|
|
129
|
+
rect = children[i as number]['rect'];
|
|
130
|
+
rect = new Rect(
|
|
131
|
+
rect.x + (gap / 2), rect.y + (headerHeight + (gap / 2)), rect.width - gap,
|
|
132
|
+
Math.abs(rect.height - (gap + headerHeight)));
|
|
133
|
+
this.computeSliceAndDiceDimensional(children[i as number], rect);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return data;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
141
|
+
private sliceAndDiceProcess(processData: any[], rect: Rect): void {
|
|
142
|
+
const parentArea: number = rect.height * rect.width;
|
|
143
|
+
const levels: LevelSettingsModel[] = this.treemap.levels;
|
|
144
|
+
let childValue: number; let alottedValue: number = 0; let totalWeight: number = 0;
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
processData.forEach((data: any) => { totalWeight += data['weight']; });
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
148
|
+
processData.forEach((child: any) => {
|
|
149
|
+
child['weightArea'] = parentArea * (child['weight'] as number) / totalWeight;
|
|
150
|
+
});
|
|
151
|
+
const isHorizontal: boolean = (this.treemap.layoutType === 'SliceAndDiceAuto') ? (rect.width > rect.height) :
|
|
152
|
+
(this.treemap.layoutType === 'SliceAndDiceHorizontal');
|
|
153
|
+
processData.sort(itemsToOrder);
|
|
154
|
+
for (let i: number = 0; i < processData.length; i++) {
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
156
|
+
const item: any = processData[i as number];
|
|
157
|
+
item['isLeafItem'] = (levels.length === 0) || ((this.treemap.isHierarchicalData ||
|
|
158
|
+
isNullOrUndefined(this.treemap.leafItemSettings.labelPath)) ?
|
|
159
|
+
item['groupIndex'] === levels.length - 1 : item['groupIndex'] === this.treemap.levels.length);
|
|
160
|
+
if (isHorizontal) {
|
|
161
|
+
childValue = ((parentArea / totalWeight) * processData[i as number]['weight']) / rect.height;
|
|
162
|
+
if (alottedValue <= rect.width) {
|
|
163
|
+
processData[i as number]['rect'] = new Rect(alottedValue + rect.x, rect.y, childValue, rect.height);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
childValue = ((parentArea / totalWeight) * processData[i as number]['weight']) / rect.width;
|
|
167
|
+
if (alottedValue <= rect.height) {
|
|
168
|
+
processData[i as number]['rect'] = new Rect(rect.x, alottedValue + rect.y, rect.width, childValue);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
alottedValue += childValue;
|
|
172
|
+
this.renderItems.push(processData[i as number]);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
177
|
+
private computeSquarifyDimensional(data: any, coords: Rect): void {
|
|
178
|
+
const leaf: LeafItemSettings = this.treemap.leafItemSettings as LeafItemSettings;
|
|
179
|
+
let rect: Rect; const levels: LevelSettings[] = this.treemap.levels as LevelSettings[];
|
|
180
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
|
+
let item: any;
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
183
|
+
const child: any[] = findChildren(data)['values']; let index: number;
|
|
184
|
+
let padding: number; let headerHeight: number;
|
|
185
|
+
if (child && child.length > 0) {
|
|
186
|
+
if (this.parentData.length === 0) {
|
|
187
|
+
this.parentData = [];
|
|
188
|
+
this.parentData.push(child);
|
|
189
|
+
}
|
|
190
|
+
this.calculateChildrenLayout(data, child, coords);
|
|
191
|
+
if (this.treemap.levels.length > 0) {
|
|
192
|
+
for (let i: number = 0; i < child.length; i++) {
|
|
193
|
+
item = child[i as number];
|
|
194
|
+
index = item['groupIndex'];
|
|
195
|
+
rect = item['rect'];
|
|
196
|
+
padding = (item['isLeafItem'] ? leaf.padding : levels[index as number].groupPadding) / 2;
|
|
197
|
+
headerHeight = this.treemap.isHierarchicalData ? index === 0 && item['isLeafItem'] ? 0 : levels[index as number] ?
|
|
198
|
+
levels[index as number].showHeader ? levels[index as number].headerHeight : 0 : 0 :
|
|
199
|
+
(levels.length === 0) ? 0 : levels[index as number] ?
|
|
200
|
+
levels[index as number].showHeader ? levels[index as number].headerHeight : 0 : 0;
|
|
201
|
+
rect = new Rect(
|
|
202
|
+
rect.x + padding, rect.y + (headerHeight + padding),
|
|
203
|
+
rect.width - padding, rect.height - padding
|
|
204
|
+
);
|
|
205
|
+
if (!item['isLeafItem'] && item['weight'] > 0) {
|
|
206
|
+
this.computeSquarifyDimensional(child[i as number], rect);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
214
|
+
private calculateChildrenLayout(parent: any, children: any[], coords: Rect): void {
|
|
215
|
+
this.computeTotalArea(children, getArea(coords));
|
|
216
|
+
children.sort(orderByArea);
|
|
217
|
+
this.performRowsLayout(children, [], coords, []);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
221
|
+
private performRowsLayout(data: any[], currentRow: any[], rect: Rect, stack: any[]): any[] {
|
|
222
|
+
const dataLength: number = data.length;
|
|
223
|
+
if (dataLength === 0) {
|
|
224
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
225
|
+
const newCoordinates: any[] = this.getCoordinates(currentRow, rect);
|
|
226
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
+
const newStack: any[] = stack.concat(newCoordinates);
|
|
228
|
+
return newStack;
|
|
229
|
+
}
|
|
230
|
+
const width: number = getShortestEdge(rect);
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
232
|
+
const nextDatum: any = data[0];
|
|
233
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
234
|
+
const restData: any[] = data.slice(1, dataLength);
|
|
235
|
+
if (this.aspectRatio(currentRow, nextDatum, width)) {
|
|
236
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
237
|
+
const newRow: any[] = currentRow.concat(nextDatum);
|
|
238
|
+
return this.performRowsLayout(restData, newRow, rect, stack);
|
|
239
|
+
} else {
|
|
240
|
+
const currentRowLength: number = currentRow.length;
|
|
241
|
+
let valueSum: number = 0;
|
|
242
|
+
for (let i: number = 0; i < currentRowLength; i += 1) {
|
|
243
|
+
valueSum += currentRow[i as number]['itemArea'];
|
|
244
|
+
}
|
|
245
|
+
const newContainer: Rect = this.cutArea(rect, valueSum);
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
247
|
+
const newCoordinates: any[] = this.getCoordinates(currentRow, rect);
|
|
248
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
249
|
+
const newStack: any[] = stack.concat(newCoordinates);
|
|
250
|
+
return this.performRowsLayout(data, [], newContainer, newStack);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
255
|
+
private aspectRatio(currentRow: any[], nextDatum: any, length: number): boolean {
|
|
256
|
+
if (currentRow.length === 0) {
|
|
257
|
+
return true;
|
|
258
|
+
} else {
|
|
259
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
260
|
+
const newRow: any[] = currentRow.concat(nextDatum);
|
|
261
|
+
const currentMaxAspectRatio: number = this.findMaxAspectRatio(currentRow, length);
|
|
262
|
+
const newMaxAspectRatio: number = this.findMaxAspectRatio(newRow, length);
|
|
263
|
+
return (currentMaxAspectRatio >= newMaxAspectRatio);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
268
|
+
private findMaxAspectRatio(row: any[], length: number): number {
|
|
269
|
+
const rowLength: number = row.length;
|
|
270
|
+
let minArea: number = Infinity;
|
|
271
|
+
let maxArea: number = -Infinity;
|
|
272
|
+
let sumArea: number = 0;
|
|
273
|
+
for (let i: number = 0; i < rowLength; i += 1) {
|
|
274
|
+
const area: number = row[i as number]['itemArea'];
|
|
275
|
+
if (area < minArea) {
|
|
276
|
+
minArea = area;
|
|
277
|
+
}
|
|
278
|
+
if (area > maxArea) {
|
|
279
|
+
maxArea = area;
|
|
280
|
+
}
|
|
281
|
+
sumArea += area;
|
|
282
|
+
}
|
|
283
|
+
const result: number = Math.max((Math.pow(length, 2)) * maxArea / (Math.pow(sumArea, 2)), (Math.pow(sumArea, 2)) /
|
|
284
|
+
((Math.pow(length, 2)) * minArea));
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
private cutArea(rect: Rect, area: number): Rect {
|
|
290
|
+
const newContainer: Rect = convertToContainer(rect);
|
|
291
|
+
const width: number = newContainer.width;
|
|
292
|
+
const height: number = newContainer.height;
|
|
293
|
+
const xOffset: number = newContainer.x;
|
|
294
|
+
const yOffset: number = newContainer.y;
|
|
295
|
+
if (width >= height) {
|
|
296
|
+
const areaWidth: number = area / height;
|
|
297
|
+
const newWidth: number = width - areaWidth;
|
|
298
|
+
const container: Rect = {
|
|
299
|
+
x: xOffset + areaWidth,
|
|
300
|
+
y: yOffset,
|
|
301
|
+
width: newWidth,
|
|
302
|
+
height: height
|
|
303
|
+
};
|
|
304
|
+
return convertToRect(container);
|
|
305
|
+
} else {
|
|
306
|
+
const areaHeight: number = area / width;
|
|
307
|
+
const newHeight: number = height - areaHeight;
|
|
308
|
+
const container: Rect = {
|
|
309
|
+
x: xOffset,
|
|
310
|
+
y: yOffset + areaHeight,
|
|
311
|
+
width: width,
|
|
312
|
+
height: newHeight
|
|
313
|
+
};
|
|
314
|
+
return convertToRect(container);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
319
|
+
private getCoordinates(row: any[], rect: Rect): any[] {
|
|
320
|
+
const container: Rect = convertToContainer(rect);
|
|
321
|
+
const width: number = container.width; const height: number = container.height;
|
|
322
|
+
const xOffset: number = container.x; const yOffset: number = container.y;
|
|
323
|
+
const rowLength: number = row.length; const levels: LevelSettingsModel[] = this.treemap.levels;
|
|
324
|
+
const leaf: LeafItemSettingsModel = this.treemap.leafItemSettings; let index: number;
|
|
325
|
+
let valueSum: number = 0;
|
|
326
|
+
for (let i: number = 0; i < rowLength; i += 1) {
|
|
327
|
+
valueSum += row[i as number]['itemArea'];
|
|
328
|
+
}
|
|
329
|
+
const areaWidth: number = valueSum / height; const areaHeight: number = valueSum / width;
|
|
330
|
+
let subXOffset: number = xOffset; let subYOffset: number = yOffset; let padding: number;
|
|
331
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
332
|
+
const coordinates: any[] = []; let isParent: boolean; let parentRect: Rect;
|
|
333
|
+
for (let i: number = 0; i < rowLength; i += 1) {
|
|
334
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
335
|
+
const item: any = row[i as number];
|
|
336
|
+
index = item['groupIndex'];
|
|
337
|
+
item['isLeafItem'] = (levels.length === 0) || (this.treemap.isHierarchicalData ? index === levels.length :
|
|
338
|
+
isNullOrUndefined(leaf.labelPath) ? false : index === levels.length);
|
|
339
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
340
|
+
isParent = isParentItem(this.parentData[0] as any[], item);
|
|
341
|
+
parentRect = isParent ? this.treemap.areaRect : item['parent'].rect;
|
|
342
|
+
padding = item['isLeafItem'] ? leaf.padding : levels[index as number].groupPadding;
|
|
343
|
+
if (width >= height) {
|
|
344
|
+
const y1: number = subYOffset + item['itemArea'] / areaWidth;
|
|
345
|
+
item['rect'] = {
|
|
346
|
+
x: subXOffset,
|
|
347
|
+
y: subYOffset,
|
|
348
|
+
width: subXOffset + areaWidth,
|
|
349
|
+
height: y1
|
|
350
|
+
};
|
|
351
|
+
subYOffset = y1;
|
|
352
|
+
} else {
|
|
353
|
+
const x1: number = subXOffset + item['itemArea'] / areaHeight;
|
|
354
|
+
item['rect'] = {
|
|
355
|
+
x: subXOffset,
|
|
356
|
+
y: subYOffset,
|
|
357
|
+
width: x1,
|
|
358
|
+
height: subYOffset + areaHeight
|
|
359
|
+
};
|
|
360
|
+
subXOffset = x1;
|
|
361
|
+
}
|
|
362
|
+
if (item['weight'] > 0 && (isParent || (Math.round(rect.y + (padding / 2)) <=
|
|
363
|
+
Math.round(parentRect.y + (parentRect.height - parentRect.y)) && Math.round(rect.x + (padding / 2)) <=
|
|
364
|
+
Math.round(parentRect.x + (parentRect.width - parentRect.x))))) {
|
|
365
|
+
this.renderItems.push(item);
|
|
366
|
+
coordinates.push(item);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return coordinates;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
373
|
+
private computeTotalArea(data: any[], area: number): any[] {
|
|
374
|
+
const dataLength: number = data.length;
|
|
375
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
376
|
+
const result: any[] = [];
|
|
377
|
+
for (let i: number = 0; i < dataLength; i += 1) {
|
|
378
|
+
const dataLength: number = data.length;
|
|
379
|
+
let dataSum: number = 0;
|
|
380
|
+
for (let i: number = 0; i < dataLength; i += 1) {
|
|
381
|
+
dataSum += data[i as number]['weight'];
|
|
382
|
+
}
|
|
383
|
+
const multiplier: number = area / dataSum;
|
|
384
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
385
|
+
let datum: any;
|
|
386
|
+
for (let j: number = 0; j < dataLength; j++) {
|
|
387
|
+
datum = data[j as number];
|
|
388
|
+
datum['itemArea'] = datum['weight'] * multiplier;
|
|
389
|
+
result.push(datum);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return result;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
396
|
+
public onDemandProcess(childItems: any): void {
|
|
397
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
398
|
+
let parentItem: any = {}; let totalRect: Rect;
|
|
399
|
+
parentItem = childItems[0]['parent'];
|
|
400
|
+
this.treemap.currentLevel = parentItem['isDrilled'] ? parentItem['groupIndex'] : null;
|
|
401
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
402
|
+
let parentItemGroupname: any = {};
|
|
403
|
+
if (isNullOrUndefined(parentItem['groupName'])) {
|
|
404
|
+
parentItemGroupname = parentItem;
|
|
405
|
+
} else {
|
|
406
|
+
parentItemGroupname[parentItem['groupName']] = [parentItem];
|
|
407
|
+
}
|
|
408
|
+
totalRect = extend({}, this.treemap.areaRect, totalRect, false) as Rect;
|
|
409
|
+
if (!isNullOrUndefined(this.treemap.treeMapLegendModule) && !isNullOrUndefined(this.treemap.totalRect)) {
|
|
410
|
+
totalRect = this.treemap.totalRect;
|
|
411
|
+
}
|
|
412
|
+
const count: number = this.treemap.levels.length;
|
|
413
|
+
for (let i: number = 0; i < count; i++) {
|
|
414
|
+
const levelCount: number = childItems[0]['groupIndex'];
|
|
415
|
+
if (count === levelCount) {
|
|
416
|
+
this.treemap.levels[count as number] = this.treemap.levels[i as number];
|
|
417
|
+
} else {
|
|
418
|
+
this.treemap.levels.splice(count - 1, 1);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
this.calculateLayoutItems(parentItemGroupname, totalRect);
|
|
422
|
+
this.renderLayoutItems();
|
|
423
|
+
}
|
|
424
|
+
// eslint-disable-next-line valid-jsdoc
|
|
425
|
+
/** @private */
|
|
426
|
+
public renderLayoutItems(): void {
|
|
427
|
+
let position: string;
|
|
428
|
+
const treeMap: TreeMap = this.treemap;
|
|
429
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
430
|
+
let txtVisible: boolean; let getItemColor: any; let eventArgs: IItemRenderingEventArgs;
|
|
431
|
+
this.renderer = treeMap.renderer;
|
|
432
|
+
let pathOptions: PathOption;
|
|
433
|
+
const elementID: string = treeMap.element.id; let index: number; let templatePosition: LabelPosition;
|
|
434
|
+
const mode: string = treeMap.layoutType; let rect: Rect; let format: string;
|
|
435
|
+
const interSectAction: LabelAlignment = this.treemap.leafItemSettings.interSectAction;
|
|
436
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
437
|
+
let fill: string; let item: any; let renderText: string;
|
|
438
|
+
let opacity: number; let rectPath: string = '';
|
|
439
|
+
const secondaryEle: HTMLElement = document.getElementById(treeMap.element.id + '_Secondary_Element');
|
|
440
|
+
let groupId: string; let templateEle: HTMLElement; let gap: number;
|
|
441
|
+
let textStyle: FontModel; const levels: LevelSettings[] = treeMap.levels as LevelSettings[];
|
|
442
|
+
this.layoutGroup = this.renderer.createGroup({ id: elementID + '_TreeMap_' + mode + '_Layout' });
|
|
443
|
+
let itemGroup: Element; let template: string | Function; let border: BorderModel;
|
|
444
|
+
const templateGroup: HTMLElement = createElement('div', {
|
|
445
|
+
id: treeMap.element.id + '_Label_Template_Group',
|
|
446
|
+
className: 'template'
|
|
447
|
+
});
|
|
448
|
+
templateGroup.style.cssText = 'overflow: hidden; position: absolute;pointer-events: none;' +
|
|
449
|
+
'top:' + treeMap.areaRect.y + 'px;' +
|
|
450
|
+
'left:' + treeMap.areaRect.x + 'px;' +
|
|
451
|
+
'height:' + treeMap.areaRect.height + 'px;' +
|
|
452
|
+
'width:' + treeMap.areaRect.width + 'px;';
|
|
453
|
+
let isLeafItem: boolean = false; const leaf: LeafItemSettings = treeMap.leafItemSettings as LeafItemSettings;
|
|
454
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
455
|
+
let childItems: any[]; let connectorText: string;
|
|
456
|
+
for (let i: number = 0; i < this.renderItems.length; i++) {
|
|
457
|
+
item = this.renderItems[i as number];
|
|
458
|
+
index = item['groupIndex'];
|
|
459
|
+
if (this.treemap.drillDownView && isNullOrUndefined(this.treemap.currentLevel)
|
|
460
|
+
&& index > 0 || this.treemap.drillDownView
|
|
461
|
+
&& index > (this.treemap.currentLevel + 1)) {
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
rect = item['rect'];
|
|
465
|
+
isLeafItem = item['isLeafItem'];
|
|
466
|
+
groupId = elementID + '_Level_Index_' + index + '_Item_Index_' + i;
|
|
467
|
+
itemGroup = this.renderer.createGroup({ id: groupId + '_Group' });
|
|
468
|
+
gap = (isLeafItem ? leaf.gap : levels[index as number].groupGap) / 2;
|
|
469
|
+
const treemapItemRect: Rect = this.treemap.totalRect ? (treeMap.legendSettings.visible ? this.treemap.totalRect
|
|
470
|
+
: convertToContainer(this.treemap.totalRect)) : this.treemap.areaRect;
|
|
471
|
+
if (treeMap.layoutType === 'Squarified') {
|
|
472
|
+
rect.width = Math.abs(rect.x - rect.width) - gap;
|
|
473
|
+
rect.height = Math.abs(rect.y - rect.height) - gap;
|
|
474
|
+
}
|
|
475
|
+
if (treeMap.renderDirection === 'TopRightBottomLeft') {
|
|
476
|
+
rect.x = (treemapItemRect.x + treemapItemRect.width) - rect.width - Math.abs(treemapItemRect.x - rect.x);
|
|
477
|
+
} else if (treeMap.renderDirection === 'BottomLeftTopRight') {
|
|
478
|
+
rect.y = (treemapItemRect.y + treemapItemRect.height) - rect.height - Math.abs(treemapItemRect.y - rect.y);
|
|
479
|
+
} else if (treeMap.renderDirection === 'BottomRightTopLeft') {
|
|
480
|
+
rect.x = (treemapItemRect.x + treemapItemRect.width) - rect.width - Math.abs(treemapItemRect.x - rect.x);
|
|
481
|
+
rect.y = (treemapItemRect.y + treemapItemRect.height) - rect.height - Math.abs(treemapItemRect.y - rect.y);
|
|
482
|
+
}
|
|
483
|
+
getItemColor = this.getItemColor(isLeafItem, item);
|
|
484
|
+
fill = getItemColor['fill'];
|
|
485
|
+
opacity = getItemColor['opacity'];
|
|
486
|
+
format = isLeafItem ? leaf.labelFormat : (levels[index as number]).headerFormat;
|
|
487
|
+
let levelName: string;
|
|
488
|
+
txtVisible = isLeafItem ? leaf.showLabels : (levels[index as number]).showHeader;
|
|
489
|
+
if (index === this.treemap.currentLevel) {
|
|
490
|
+
if (this.treemap.enableBreadcrumb) {
|
|
491
|
+
const re: RegExp = /#/gi;
|
|
492
|
+
connectorText = '#' + this.treemap.breadcrumbConnector + '#';
|
|
493
|
+
levelName = item['levelOrderName'].replace(re, connectorText);
|
|
494
|
+
levelName = index !== 0 ? '#' + levelName : levelName;
|
|
495
|
+
} else {
|
|
496
|
+
levelName = item['name'];
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
if (this.treemap.enableBreadcrumb) {
|
|
500
|
+
item['isDrilled'] = false;
|
|
501
|
+
}
|
|
502
|
+
levelName = item['name'];
|
|
503
|
+
}
|
|
504
|
+
renderText = textFormatter(format, item['data'], this.treemap) || levelName || 'undefined';
|
|
505
|
+
childItems = findChildren(item)['values'];
|
|
506
|
+
renderText = !isLeafItem && childItems && childItems.length > 0 && this.treemap.enableDrillDown ?
|
|
507
|
+
!item['isDrilled'] ? treeMap.enableRtl ? renderText + ' [+]' : '[+] ' + renderText :
|
|
508
|
+
treeMap.enableRtl ? renderText + ' [-]' : '[-] ' + renderText : renderText;
|
|
509
|
+
if (treeMap.enableHtmlSanitizer) {
|
|
510
|
+
renderText = SanitizeHtmlHelper.sanitize(renderText);
|
|
511
|
+
}
|
|
512
|
+
let fontFamily: string = (isLeafItem ? leaf.labelStyle.fontFamily : levels[index as number].headerStyle.fontFamily);
|
|
513
|
+
fontFamily = fontFamily || this.treemap.themeStyle.labelFontFamily;
|
|
514
|
+
let size: string = (isLeafItem ? leaf.labelStyle.size : levels[index as number].headerStyle.size);
|
|
515
|
+
size = size || this.treemap.themeStyle.labelFontSize;
|
|
516
|
+
let fontWeight: string = (isLeafItem ? leaf.labelStyle.fontWeight : levels[index as number].headerStyle.fontWeight);
|
|
517
|
+
fontWeight = fontWeight || this.treemap.themeStyle.fontWeight;
|
|
518
|
+
const color: string = (isLeafItem ? leaf.labelStyle.color : levels[index as number].headerStyle.color);
|
|
519
|
+
const fontStyle: string = (isLeafItem ? leaf.labelStyle.fontStyle : levels[index as number].headerStyle.fontStyle);
|
|
520
|
+
const textStyleOpacity: number = (isLeafItem ? leaf.labelStyle.opacity : levels[index as number].headerStyle.opacity);
|
|
521
|
+
textStyle = {
|
|
522
|
+
fontFamily: fontFamily, size: size, fontWeight: fontWeight, color: color, fontStyle: fontStyle, opacity: textStyleOpacity
|
|
523
|
+
};
|
|
524
|
+
border = isLeafItem ? leaf.border : levels[index as number].border;
|
|
525
|
+
position = !isLeafItem ? (levels[index as number].headerAlignment) === 'Near' ? 'TopLeft' : (levels[index as number].headerAlignment) === 'Center' ?
|
|
526
|
+
'TopCenter' : 'TopRight' : leaf.labelPosition;
|
|
527
|
+
templatePosition = isLeafItem ? leaf.templatePosition : levels[index as number].templatePosition;
|
|
528
|
+
template = isLeafItem ? leaf.labelTemplate : levels[index as number].headerTemplate;
|
|
529
|
+
item['options'] = { border: border, opacity: opacity, fill: fill };
|
|
530
|
+
eventArgs = {
|
|
531
|
+
cancel: false, name: itemRendering, treemap: this.treemap, text: renderText,
|
|
532
|
+
currentItem: item, RenderItems: this.renderItems, options: item['options'], textColor: textStyle.color
|
|
533
|
+
};
|
|
534
|
+
this.treemap.trigger(itemRendering, eventArgs, (observedArgs: IItemRenderingEventArgs) => {
|
|
535
|
+
if (!observedArgs.cancel) {
|
|
536
|
+
rectPath = ' M ' + rect.x + ' ' + rect.y + ' L ' + (rect.x + rect.width) + ' ' + rect.y +
|
|
537
|
+
' L ' + (rect.x + rect.width) + ' ' + (rect.y + rect.height) + ' L ' + rect.x + ' ' + (rect.y + rect.height) + 'z';
|
|
538
|
+
pathOptions = new PathOption(groupId + '_RectPath', fill, border.width, border.color, opacity, null, rectPath);
|
|
539
|
+
const path: Element = this.renderer.drawPath(pathOptions);
|
|
540
|
+
itemGroup.appendChild(path);
|
|
541
|
+
if (txtVisible) {
|
|
542
|
+
if (eventArgs.text !== renderText) {
|
|
543
|
+
eventArgs.text = textFormatter(eventArgs.text, item['data'], this.treemap) || levelName;
|
|
544
|
+
}
|
|
545
|
+
textStyle.color = eventArgs.textColor ? eventArgs.textColor : textStyle.color;
|
|
546
|
+
this.renderItemText(
|
|
547
|
+
eventArgs.text.toString(), itemGroup, textStyle, rect, interSectAction, groupId, fill,
|
|
548
|
+
position as LabelPosition, connectorText
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
if (template) {
|
|
552
|
+
templateEle = this.renderTemplate(secondaryEle, groupId, rect, templatePosition, template, item, isLeafItem);
|
|
553
|
+
if (!isNullOrUndefined(templateEle)) {
|
|
554
|
+
templateGroup.appendChild(templateEle);
|
|
555
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
556
|
+
(this.treemap as any).renderReactTemplates();
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
itemGroup.setAttribute('aria-label', item['name']);
|
|
560
|
+
if ((this.treemap.enableDrillDown && !isLeafItem) || (this.treemap.selectionSettings.enable ||
|
|
561
|
+
this.treemap.highlightSettings.enable)) {
|
|
562
|
+
itemGroup.setAttribute('role', 'button');
|
|
563
|
+
itemGroup.setAttribute('tabindex', this.treemap.tabIndex.toString());
|
|
564
|
+
(itemGroup as HTMLElement).style.outline = 'none';
|
|
565
|
+
(itemGroup as HTMLElement).style.cursor = this.treemap.highlightSettings.enable && !this.treemap.selectionSettings.enable && (this.treemap.enableDrillDown && item['groupIndex'] === (this.treemap.levels.length - 1)) ? 'default' :
|
|
566
|
+
this.treemap.highlightSettings.enable && !this.treemap.selectionSettings.enable && !this.treemap.enableDrillDown ? 'default' : 'pointer';
|
|
567
|
+
} else {
|
|
568
|
+
itemGroup.setAttribute('role', 'region');
|
|
569
|
+
}
|
|
570
|
+
maintainSelection(this.treemap, itemGroup, 'treeMapSelection');
|
|
571
|
+
this.layoutGroup.appendChild(itemGroup);
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
if (templateGroup.childNodes.length > 0) {
|
|
576
|
+
secondaryEle.appendChild(templateGroup);
|
|
577
|
+
}
|
|
578
|
+
this.treemap.svgObject.appendChild(this.layoutGroup);
|
|
579
|
+
maintainSelection(this.treemap, this.layoutGroup, 'treeMapSelection');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private renderItemText(
|
|
583
|
+
text: string, parentElement: Element, textStyle: FontModel, rect: Rect, interSectAction: LabelAlignment,
|
|
584
|
+
groupId: string, fill: string, position: LabelPosition, connectorText: string
|
|
585
|
+
): void {
|
|
586
|
+
const padding: number = 5; let textSize: Size;
|
|
587
|
+
let textCollection: string[] = []; let customText: string | string[];
|
|
588
|
+
const tspanText: string[] = []; let height: number = 0; let textName: string;
|
|
589
|
+
textCollection = ((text.indexOf('<br>')) !== -1) ? text.split('<br>') : null;
|
|
590
|
+
customText = this.labelInterSectAction(rect, text, textStyle, interSectAction);
|
|
591
|
+
textSize = measureText(textCollection && textCollection[0] || customText[0], textStyle);
|
|
592
|
+
if (this.treemap.enableRtl) {
|
|
593
|
+
const labelSize: Size = measureText(text, textStyle);
|
|
594
|
+
const drillSymbolCount: number = text.search('[+]') || text.search('[-]');
|
|
595
|
+
if (rect.width < labelSize.width && drillSymbolCount > 0) {
|
|
596
|
+
const label: string = text.substring(drillSymbolCount - 1, text.length);
|
|
597
|
+
const drillSymbol: string = '[+]';
|
|
598
|
+
const drillSymbolSize: Size = measureText(drillSymbol, textStyle);
|
|
599
|
+
customText['0'] = textTrim(rect.width - drillSymbolSize.width - padding, customText[0], textStyle) + label;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
}
|
|
603
|
+
const textLocation: Location = findLabelLocation(rect, position, textSize, 'Text', this.treemap);
|
|
604
|
+
if (!isNullOrUndefined(textCollection)) {
|
|
605
|
+
const collection: string[] = [];
|
|
606
|
+
let texts: string = null;
|
|
607
|
+
const maxNumber: number[] = [];
|
|
608
|
+
for (let i: number = 0; i < textCollection.length; i++) {
|
|
609
|
+
texts = textTrim((rect.width - 5), textCollection[i as number], textStyle);
|
|
610
|
+
textSize = measureText(texts, textStyle);
|
|
611
|
+
height += textSize.height;
|
|
612
|
+
maxNumber.push(textSize.width);
|
|
613
|
+
collection.push(texts);
|
|
614
|
+
}
|
|
615
|
+
customText = collection;
|
|
616
|
+
textSize.width = Math.max.apply(null, maxNumber);
|
|
617
|
+
textSize.height = height;
|
|
618
|
+
}
|
|
619
|
+
if (interSectAction === 'WrapByWord' || interSectAction === 'Wrap' || interSectAction === 'Trim') {
|
|
620
|
+
for (let j: number = 0; j < customText.length; j++) {
|
|
621
|
+
textSize = measureText(customText[j as number], textStyle);
|
|
622
|
+
height += textSize.height;
|
|
623
|
+
if ((rect.height - padding) > height) {
|
|
624
|
+
tspanText.push(customText[j as number]);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (interSectAction === 'Wrap' && customText.length !== tspanText.length && tspanText.length) {
|
|
628
|
+
const collectionLength: number = tspanText.length - 1;
|
|
629
|
+
let stringText: string = tspanText[collectionLength as number];
|
|
630
|
+
stringText = stringText.substring(0, (stringText.length - 1)) + '...';
|
|
631
|
+
tspanText.splice(collectionLength);
|
|
632
|
+
if (stringText !== '...') {
|
|
633
|
+
tspanText.push(stringText);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
} else {
|
|
637
|
+
textName = customText as string;
|
|
638
|
+
tspanText.push(textName);
|
|
639
|
+
}
|
|
640
|
+
const textOptions: TextOption = new TextOption(
|
|
641
|
+
groupId + '_Text', textLocation.x, textLocation.y, 'start', tspanText, '', '', connectorText
|
|
642
|
+
);
|
|
643
|
+
renderTextElement(textOptions, textStyle, textStyle.color || this.getSaturatedColor(fill), parentElement);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
647
|
+
private getItemColor(isLeafItem: boolean, item: any): any {
|
|
648
|
+
const treemap: TreeMap = this.treemap;
|
|
649
|
+
let itemFill: string = isLeafItem ? treemap.leafItemSettings.fill : treemap.levels[item['groupIndex']].fill;
|
|
650
|
+
let itemOpacity: number = isLeafItem ? treemap.leafItemSettings.opacity : treemap.levels[item['groupIndex']].opacity;
|
|
651
|
+
if (!isNullOrUndefined(treemap.treemapLevelData.defaultLevelsData)) {
|
|
652
|
+
if (treemap.treemapLevelData.defaultLevelsData.length > 0) {
|
|
653
|
+
treemap.treemapLevelData.levelsData = treemap.treemapLevelData.defaultLevelsData;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
657
|
+
const parentData: any[] = findChildren(treemap.treemapLevelData.levelsData[0])['values'];
|
|
658
|
+
const colorMapping: ColorMappingModel[] = isLeafItem ? treemap.leafItemSettings.colorMapping :
|
|
659
|
+
treemap.levels[item['groupIndex']].colorMapping;
|
|
660
|
+
if (colorMapping.length > 0) {
|
|
661
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
662
|
+
const option: any = colorMap(
|
|
663
|
+
colorMapping, item['data'][treemap.equalColorValuePath],
|
|
664
|
+
item['data'][treemap.rangeColorValuePath]);
|
|
665
|
+
if (!isNullOrUndefined(option)) {
|
|
666
|
+
itemFill = !isNullOrUndefined(option['fill']) ? option['fill'] : treemap.leafItemSettings.fill;
|
|
667
|
+
itemOpacity = option['opacity'];
|
|
668
|
+
}
|
|
669
|
+
} else {
|
|
670
|
+
for (let i: number = 0; i < parentData.length; i++) {
|
|
671
|
+
if ((parentData[i as number]['levelOrderName'] as string) === (item['levelOrderName'] as string).split('#')[0]) {
|
|
672
|
+
itemFill = !isNullOrUndefined(itemFill) ? itemFill : !isNullOrUndefined(treemap.colorValuePath) ?
|
|
673
|
+
parentData[i as number]['data'][treemap.colorValuePath] : !isNullOrUndefined(item['options']) ?
|
|
674
|
+
item['options'].fill : (!isNullOrUndefined(treemap.palette) && treemap.palette.length > 0) ?
|
|
675
|
+
treemap.palette[i % treemap.palette.length] : '#808080';
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
return { fill: itemFill, opacity: itemOpacity };
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* To find saturated color for datalabel
|
|
684
|
+
*
|
|
685
|
+
* @param {string} color - Specifies the color
|
|
686
|
+
* @returns {string} - Returns the color
|
|
687
|
+
*/
|
|
688
|
+
private getSaturatedColor(color: string): string {
|
|
689
|
+
let saturatedColor: string = color;
|
|
690
|
+
saturatedColor = (saturatedColor === 'transparent') ? window.getComputedStyle(document.body, null).backgroundColor : saturatedColor;
|
|
691
|
+
const rgbValue: ColorValue = convertHexToColor(colorNameToHex(saturatedColor));
|
|
692
|
+
const contrast: number = Math.round((rgbValue.r * 299 + rgbValue.g * 587 + rgbValue.b * 114) / 1000);
|
|
693
|
+
return contrast >= 128 ? 'black' : 'white';
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
private renderTemplate(
|
|
697
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, max-len
|
|
698
|
+
secondaryEle: HTMLElement, groupId: string, rect: Rect, position: LabelPosition, template: string | Function, item: any, isLeafItem: boolean
|
|
699
|
+
): HTMLElement {
|
|
700
|
+
const templateId: string = isLeafItem ? groupId + '_LabelTemplate' : groupId + '_HeaderTemplate';
|
|
701
|
+
const baseTemplateId: string = isLeafItem ? '_LabelTemplate' : '_HeaderTemplate';
|
|
702
|
+
if (isNullOrUndefined(template['prototype']) && typeof template === 'string') {
|
|
703
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
704
|
+
const keys: any[] = Object.keys(item['data']);
|
|
705
|
+
for (let i: number = 0; i < keys.length; i++) {
|
|
706
|
+
const regExp: RegExpConstructor = RegExp;
|
|
707
|
+
template = template.replace(new regExp('{{:' + <string>keys[i as number] + '}}', 'g'), item['data'][keys[i as number].toString()]);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
if (this.treemap.enableHtmlSanitizer && typeof template === 'string') {
|
|
711
|
+
template = SanitizeHtmlHelper.sanitize(template);
|
|
712
|
+
}
|
|
713
|
+
let labelElement: HTMLElement;
|
|
714
|
+
if (!isNullOrUndefined(document.getElementById(this.treemap.element.id + '_Secondary_Element'))) {
|
|
715
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
716
|
+
const templateFn: any = getTemplateFunction(template);
|
|
717
|
+
const templateElement: HTMLCollection = templateFn(item['data'], this.treemap, template, this.treemap.element.id + baseTemplateId, false);
|
|
718
|
+
labelElement = convertElement(templateElement, templateId, item['data']);
|
|
719
|
+
const templateSize: Size = measureElement(labelElement, secondaryEle);
|
|
720
|
+
const templateLocation: Location = findLabelLocation(rect, position, templateSize, 'Template', this.treemap);
|
|
721
|
+
labelElement.style.left = templateLocation.x + 'px';
|
|
722
|
+
labelElement.style.top = templateLocation.y + 'px';
|
|
723
|
+
}
|
|
724
|
+
return labelElement;
|
|
725
|
+
}
|
|
726
|
+
private labelInterSectAction(rect: Rect, text: string, textStyle: FontModel, alignment: LabelAlignment): string | string[] {
|
|
727
|
+
let textValue: string | string[]; const maxWidth: number = rect.width - 10;
|
|
728
|
+
switch (alignment) {
|
|
729
|
+
case 'Hide':
|
|
730
|
+
textValue = [hide(maxWidth, rect.height, text, textStyle)];
|
|
731
|
+
break;
|
|
732
|
+
case 'Trim':
|
|
733
|
+
textValue = [textTrim((maxWidth + 3), text, textStyle)];
|
|
734
|
+
break;
|
|
735
|
+
case 'WrapByWord':
|
|
736
|
+
textValue = wordWrap(maxWidth, text, textStyle);
|
|
737
|
+
break;
|
|
738
|
+
case 'Wrap':
|
|
739
|
+
textValue = textWrap(maxWidth, text, textStyle);
|
|
740
|
+
break;
|
|
741
|
+
}
|
|
742
|
+
return textValue;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
*
|
|
747
|
+
* @returns {void}
|
|
748
|
+
* @private
|
|
749
|
+
*/
|
|
750
|
+
public destroy(): void {
|
|
751
|
+
this.treemap = null;
|
|
752
|
+
this.currentRect = null;
|
|
753
|
+
this.layoutGroup = null;
|
|
754
|
+
this.renderer = null;
|
|
755
|
+
this.renderItems = [];
|
|
756
|
+
this.parentData = [];
|
|
757
|
+
}
|
|
758
|
+
}
|