@syncfusion/ej2-maps
Version:
The Maps component is used to visualize the geographical data and represent the statistical data of a particular geographical area on earth with user interactivity, and provides various customizing options
793 lines (787 loc) • 169 kB
text/typescript
import { Maps } from '../../index';
import {
LayerSettings, ColorMappingSettings, BorderModel, LegendPosition, FontModel, LegendSettingsModel,
click, ILegendRenderingEventArgs, legendRendering,
MarkerSettingsModel, MarkerSettings, LegendShape, LabelPosition, LabelIntersectAction
} from '../index';
import { LegendArrangement, LegendMode } from '../index';
import {
Rect, measureText, PathOption, textTrim, drawBalloon,
removeClass, querySelector, maintainStyleClass, getValueFromObject, getTemplateFunction
} from '../utils/helper';
import { RectOption, Size, TextOption, Point, renderTextElement, drawSymbol, checkPropertyPath, getElement } from '../utils/helper';
import { isNullOrUndefined, Browser, EventHandler, remove, extend } from '@syncfusion/ej2-base';
import { SvgRenderer } from '@syncfusion/ej2-svg-base';
import { LayerSettingsModel, HighlightSettingsModel, SelectionSettingsModel } from '../model/base-model';
import { ShapeSettings } from '../model/base';
import { Theme } from '../model/theme';
/**
* Legend module is used to render legend for the maps
*/
export class Legend {
/**
* @private
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public legendCollection: any[];
/**
* @private
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public legendRenderingCollections: any[];
private translate: Point;
/**
* @private
*/
public legendBorderRect: Rect = new Rect(0, 0, 0, 0);
/**
* @private
*/
public initialMapAreaRect: Rect = new Rect(0, 0, 0, 0);
/**
* @private
*/
public legendTotalRect: Rect = new Rect(0, 0, 0, 0);
private maps: Maps;
/**
* @private
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public totalPages: any[] = [];
private page: number = 0;
/**
* @private
*/
public currentPage: number = 0;
private legendItemRect: Rect = new Rect(0, 0, 0, 0);
private heightIncrement: number = 0;
private widthIncrement: number = 0;
private textMaxWidth: number = 0;
private arrowTimer: number;
/**
* @private
*/
public legendGroup: Element;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private shapeHighlightCollection: any[] = [];
/**
* @private
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public legendHighlightCollection: any[] = [];
/**
* @private
*/
public shapePreviousColor: string[] = [];
/**
* @private
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public selectedNonLegendShapes: any[] = [];
/**
* @private
*/
public shapeToggled: boolean = true;
private legendLinearGradient: Element;
private currentLayer: LayerSettings;
private defsElement: Element;
/**
* @private
*/
public legendElement: Element[] = null;
/**
* @private
*/
public oldShapeElement: Element;
constructor(maps: Maps) {
this.maps = maps;
this.addEventListener();
}
/**
* To calculate legend bounds and draw the legend shape and text.
*
* @returns {void}
* @private
*/
public renderLegend(): void {
this.legendRenderingCollections = [];
this.legendCollection = [];
this.totalPages = [];
this.widthIncrement = 0;
this.heightIncrement = 0;
this.defsElement = this.maps.renderer.createDefs();
this.maps.svgObject.appendChild(this.defsElement);
this.initialMapAreaRect = this.maps.mapAreaRect;
this.calculateLegendBounds();
this.drawLegend();
}
public calculateLegendBounds(): void {
const map: Maps = this.maps;
const legend: LegendSettingsModel = <LegendSettingsModel>map.legendSettings;
this.legendCollection = [];
const spacing: number = 10;
const leftPadding: number = 10; const topPadding: number = map.mapAreaRect.y;
this.legendRenderingCollections = [];
Array.prototype.forEach.call(map.layersCollection, (layer: LayerSettings, layerIndex: number) => {
if (!isNullOrUndefined(layer.shapeData)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const layerData: any[] = layer.shapeData['features'];
const dataPath: string = layer.shapeDataPath;
const propertyPath: string | string[] = layer.shapePropertyPath;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let dataSource: any[] = layer.dataSource as any[];
let colorValuePath: string;
let colorMapping: ColorMappingSettings[];
if (legend.type === 'Layers' && layer.visible) {
colorValuePath = layer.shapeSettings.colorValuePath;
colorMapping = <ColorMappingSettings[]>layer.shapeSettings.colorMapping;
this.getLegends(layerIndex, layerData, colorMapping, dataSource, dataPath, colorValuePath, propertyPath);
} else if (legend.type === 'Bubbles') {
for (const bubble of layer.bubbleSettings) {
if (bubble.visible) {
colorValuePath = bubble.colorValuePath;
colorMapping = <ColorMappingSettings[]>bubble.colorMapping;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
dataSource = bubble.dataSource as any[];
this.getLegends(layerIndex, layerData, colorMapping, dataSource, dataPath, colorValuePath, propertyPath);
}
}
}
}
if (legend.type === 'Markers') {
this.getMarkersLegendCollections(layerIndex, layer.markerSettings);
}
});
if (this.legendCollection.length > 0) {
for (let i: number = 0; i < this.legendCollection.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const legendItem: any = this.legendCollection[i as number];
const eventArgs: ILegendRenderingEventArgs = {
name: legendRendering, cancel: false, fill: legendItem['fill'], shape: legend.shape,
shapeBorder: legend.shapeBorder,
text: typeof legendItem['text'] === 'number' ? legendItem['text'].toString() : legendItem['text']
};
map.trigger('legendRendering', eventArgs);
legendItem['fill'] = eventArgs.fill;
legendItem['shape'] = eventArgs.shape;
legendItem['shapeBorder'] = eventArgs.shapeBorder;
legendItem['text'] = eventArgs.text;
if (eventArgs.cancel) {
this.legendCollection.splice(i, 1);
i--;
}
}
}
const defaultSize: number = 25;
const legendTitle: string = map.legendSettings.title.text;
const titleTextStyle: FontModel = map.legendSettings.titleStyle;
if (this.legendCollection.length > 0) {
const legendMode: LegendMode = legend.mode;
let shapeX: number = 0; let shapeY: number = 0;
let textX: number = 0; let textY: number = 0;
const shapePadding: number = legend.shapePadding;
const textPadding: number = 10;
const shapeHeight: number = legend.shapeHeight; const shapeWidth: number = legend.shapeWidth;
let shapeLocation: Point[] = []; let textLocation: Rect[] = [];
const position: LegendPosition = legend.position;
const labelAction: LabelIntersectAction = legend.labelDisplayMode;
const arrangement: LegendArrangement = (legend.orientation === 'None') ? ((position === 'Top' || position === 'Bottom')
? 'Horizontal' : 'Vertical') : legend.orientation;
let legendWidth: number = (legend.width.length > 1) ? (legend.width.indexOf('%') > -1) ? (map.availableSize.width / 100)
* parseInt(legend.width, 10) : parseInt(legend.width, 10) : null;
let legendHeight: number = (legend.height.length > 1) ? (legend.height.indexOf('%') > -1) ? (map.availableSize.height / 100) *
parseInt(legend.height, 10) : parseInt(legend.height, 10) : null;
let legendItemStartX: number; let legendItemStartY: number;
let startX: number = 0; let startY: number = 0;
const legendtitleSize: Size = measureText(legendTitle, titleTextStyle);
if (legendMode === 'Interactive') {
const itemTextStyle: FontModel = legend.textStyle;
const legendLength: number = this.legendCollection.length;
const rectWidth: number = (arrangement === 'Horizontal') ? (isNullOrUndefined(legendWidth)) ? (map.mapAreaRect.width / legendLength) :
(legendWidth / legendLength) : (isNullOrUndefined(legendWidth)) ? defaultSize : legendWidth;
const rectHeight: number = (arrangement === 'Horizontal') ? (isNullOrUndefined(legendHeight)) ? defaultSize : legendHeight :
(isNullOrUndefined(legendHeight)) ? (map.mapAreaRect.height / legendLength) : (legendHeight / legendLength);
startX = 0; startY = legendtitleSize.height + spacing;
const position: LabelPosition = legend.labelPosition;
let textX: number = 0; let textY: number = 0; const textPadding: number = 10;
let itemStartX: number = 0; let itemStartY: number = 0;
let maxTextHeight: number = 0; let maxTextWidth: number = 0;
for (let i: number = 0; i < this.legendCollection.length; i++) {
startX = (arrangement === 'Horizontal') ? (startX + rectWidth) : startX;
startY = (arrangement === 'Horizontal') ? startY : (startY + rectHeight);
let legendText: string = this.legendCollection[i as number]['text'];
let itemTextSize: Size = new Size(0, 0);
if (labelAction === 'None') {
itemTextSize = measureText(legendText, itemTextStyle);
} else if (labelAction === 'Trim') {
legendText = textTrim((arrangement === 'Horizontal' ? rectWidth : rectHeight), legendText, itemTextStyle);
itemTextSize = measureText(legendText, itemTextStyle);
} else {
legendText = '';
}
if (legend.position === 'Left' || legend.position === 'Right' || legend.position === 'Float') {
for (let i: number = 0; i < this.legendCollection.length; i++) {
const legendItem: object = this.legendCollection[i as number];
const legendTextSize: Size = measureText(legendItem['text'], legend.textStyle);
this.textMaxWidth = Math.max(this.textMaxWidth, legendTextSize.width);
}
}
maxTextHeight = Math.max(maxTextHeight, itemTextSize.height);
maxTextWidth = Math.max(maxTextWidth, itemTextSize.width);
if (itemTextSize.width > 0 && itemTextSize.height > 0) {
if (arrangement === 'Horizontal') {
textX = startX + (rectWidth / 2);
textY = (position === 'After') ? (startY + rectHeight + (itemTextSize.height / 2)) + textPadding :
(startY - textPadding);
} else {
textX = (position === 'After') ? startX - (this.textMaxWidth / 2) - textPadding
: (startX + rectWidth + this.textMaxWidth / 2) + textPadding;
textY = startY + (rectHeight / 2) + (itemTextSize.height / 4);
}
}
if (i === 0) {
itemStartX = (arrangement === 'Horizontal') ? startX : (position === 'After') ?
textX - (this.textMaxWidth / 2) : startX;
itemStartY = (arrangement === 'Horizontal') ? (position === 'After') ? startY :
textY - (itemTextSize.height / 2) : startY;
if (this.legendCollection.length === 1) {
legendWidth = (arrangement === 'Horizontal') ? Math.abs((startX + rectWidth) - itemStartX) :
(rectWidth + this.textMaxWidth + textPadding);
legendHeight = (arrangement === 'Horizontal') ? (rectHeight + (maxTextHeight / 2) + textPadding) :
Math.abs((startY + rectHeight) - itemStartY);
}
} else if (i === this.legendCollection.length - 1) {
legendWidth = (arrangement === 'Horizontal') ? Math.abs((startX + rectWidth) - itemStartX) :
(rectWidth + this.textMaxWidth + textPadding);
legendHeight = (arrangement === 'Horizontal') ? (rectHeight + (maxTextHeight / 2) + textPadding) :
Math.abs((startY + rectHeight) - itemStartY);
}
this.legendRenderingCollections.push({
fill: this.legendCollection[i as number]['fill'], x: startX, y: startY,
width: rectWidth, height: rectHeight,
text: legendText, textX: textX, textY: textY,
textWidth: itemTextSize.width, textHeight: itemTextSize.height,
shapeBorder: this.legendCollection[i as number]['shapeBorder']
});
}
if (this.legendCollection.length === 1 ) {
legendHeight = maxTextHeight + textPadding;
legendWidth = rectWidth;
}
this.legendItemRect = { x: itemStartX, y: itemStartY, width: legendWidth, height: legendHeight };
} else {
legendWidth = (isNullOrUndefined(legendWidth)) ? map.mapAreaRect.width : legendWidth;
legendHeight = (isNullOrUndefined(legendHeight)) ? map.mapAreaRect.height : legendHeight;
let j: number = 0;
this.page = 0;
for (let i: number = 0; i < this.legendCollection.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const legendItem: any = this.legendCollection[i as number];
if (isNullOrUndefined(this.totalPages[this.page])) {
this.totalPages[this.page] = { Page: (this.page + 1), Collection: [] };
}
const legendTextSize: Size = measureText(legendItem['text'], legend.textStyle);
this.textMaxWidth = Math.max(this.textMaxWidth, legendTextSize.width);
if (i === 0) {
startX = shapeX = (leftPadding + (shapeWidth / 2));
startY = shapeY = topPadding + legendtitleSize.height + (shapeHeight > legendTextSize.height ? shapeHeight / 2
: (legendTextSize.height / 4));
} else {
const maxSize: number = (legendTextSize.height > shapeHeight) ? legendTextSize.height : shapeHeight;
if (arrangement === 'Horizontal') {
const prvePositionX: number = (textLocation[j - 1].x + textLocation[j - 1].width) + textPadding + shapeWidth;
if ((prvePositionX + shapePadding + legendTextSize.width) > legendWidth) {
const nextPositionY: number = (textLocation[j - 1].y > (shapeLocation[j - 1].y + (shapeHeight / 2)) ?
textLocation[j - 1].y : (shapeLocation[j - 1].y + (shapeHeight / 2))) + topPadding;
if ((nextPositionY + maxSize) > legendHeight) {
this.getPageChanged();
j = 0;
shapeLocation = [];
textLocation = [];
shapeX = startX;
shapeY = startY;
} else {
shapeX = (shapeLocation[0].x);
shapeY = (nextPositionY + (maxSize / 2));
}
} else {
shapeX = (prvePositionX - (shapeWidth / 2));
shapeY = (shapeLocation[j - 1]).y;
}
} else {
const prevPositionY: number = textLocation[j - 1].y > shapeLocation[j - 1].y + (shapeHeight / 2) ?
textLocation[j - 1].y : shapeLocation[j - 1].y + (shapeHeight / 2);
if ((prevPositionY + topPadding + maxSize) > legendHeight) {
const nextPositionX: number = (textLocation[j - 1].x + this.textMaxWidth + textPadding);
if ((nextPositionX + shapePadding + legendTextSize.width) > legendWidth) {
shapeX = startX;
shapeY = startY;
textLocation = [];
shapeLocation = [];
this.getPageChanged();
j = 0;
} else {
shapeX = nextPositionX + (shapeWidth / 2);
shapeY = (shapeLocation[0].y);
}
} else {
const padding: number = 10;
shapeX = shapeLocation[j - 1].x;
shapeY = prevPositionY + padding + (shapeHeight / 2);
}
}
}
textX = shapeX + (shapeWidth / 2) + shapePadding;
textY = shapeY + (legendTextSize.height / 4);
shapeLocation.push({ x: shapeX, y: shapeY });
textLocation.push({ x: textX, y: textY, width: legendTextSize.width, height: (legendTextSize.height / 2) });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(<any[]>this.totalPages[this.page]['Collection']).push({
DisplayText: legendItem['text'],
ImageSrc: legendItem['imageSrc'],
Shape: { x: shapeX, y: shapeY },
Text: { x: textX, y: textY },
Fill: legendItem['fill'],
legendShape: legendItem['shape'],
shapeBorder: legendItem['shapeBorder'],
idIndex: i,
Rect: {
x: shapeLocation[j as number].x - (shapeWidth / 2),
y: (shapeLocation[j as number].y - (shapeHeight / 2)) < (textY - legendTextSize.height) ?
(shapeLocation[j as number].y - (shapeHeight / 2)) : (textY - legendTextSize.height),
width: Math.abs((shapeLocation[j as number].x - (shapeWidth / 2)) - (textX + legendTextSize.width)),
height: ((shapeHeight > legendTextSize.height) ? shapeHeight : legendTextSize.height)
}
});
j++;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const collection: any[] = (<any[]>this.totalPages[0]['Collection']);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Array.prototype.forEach.call(collection, (legendObj: any, index: number) => {
const legendRect: Rect = new Rect(
legendObj['Rect']['x'], legendObj['Rect']['y'],
legendObj['Rect']['width'], legendObj['Rect']['height']
);
if (index === 0) {
legendItemStartX = legendRect.x;
legendItemStartY = legendRect.y;
}
this.widthIncrement = Math.max(this.widthIncrement, Math.abs(legendItemStartX - (legendRect.x + legendRect.width)));
this.heightIncrement = Math.max(this.heightIncrement, Math.abs(legendItemStartY - (legendRect.y + legendRect.height)));
});
legendWidth = ((this.widthIncrement < legendWidth) ? this.widthIncrement : legendWidth);
legendHeight = ((this.heightIncrement < legendHeight) ? this.heightIncrement : legendHeight);
this.legendItemRect = {
x: collection[0]['Rect']['x'], y: collection[0]['Rect']['y'],
width: legendWidth, height: legendHeight
};
}
}
}
/**
* Get the legend collections
*
* @param {number} layerIndex - Specifies the layer index
* @param {any[]} layerData - Specifies the layer data
* @param {ColorMappingSettings[]} colorMapping - Specifies the color mapping
* @param {any[]} dataSource - Specifies the data source
* @param {string} dataPath - Specifies the data path
* @param {string} colorValuePath - Specifies the color value path
* @param {string | string[]} propertyPath - Specifies the property path
* @returns {void}
*/
private getLegends(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
layerIndex: number, layerData: any[], colorMapping: ColorMappingSettings[], dataSource: any[],
dataPath: string, colorValuePath: string, propertyPath: string | string[]
): void {
this.getRangeLegendCollection(layerIndex, layerData, colorMapping, dataSource, dataPath, colorValuePath, propertyPath);
this.getEqualLegendCollection(layerIndex, layerData, colorMapping, dataSource, dataPath, colorValuePath, propertyPath);
this.getDataLegendCollection(layerIndex, layerData, colorMapping, dataSource, dataPath, colorValuePath, propertyPath);
}
private getPageChanged(): void {
this.page++;
if (isNullOrUndefined(this.totalPages[this.page])) {
this.totalPages[this.page] = { Page: (this.page + 1), Collection: [] };
}
}
private legendTextTrim(maxWidth: number, text: string, font: FontModel, legendRectSize: number): string {
let label: string = text;
let size: number = measureText(text, font).width;
const legendWithoutTextSize : number = legendRectSize - size;
if (legendRectSize > maxWidth) {
const textLength: number = text.length;
for (let i: number = textLength - 1; i >= 0; --i) {
label = text.substring(0, i) + '...';
size = measureText(label, font).width;
const totalSize : number = legendWithoutTextSize + size;
if (totalSize <= maxWidth || label.length < 4) {
if (label.length < 4) {
label = ' ';
}
return label;
}
}
}
return label;
}
// eslint-disable-next-line valid-jsdoc
/**
* To draw the legend shape and text.
*
* @private
*/
public drawLegend(): void {
const map: Maps = this.maps;
const legend: LegendSettingsModel = <LegendSettingsModel>map.legendSettings;
const render: SvgRenderer = map.renderer;
let textOptions: TextOption;
const textFont: FontModel = {
size: legend.textStyle.size,
color: legend.textStyle.color,
fontFamily: legend.textStyle.fontFamily,
fontWeight: legend.textStyle.fontWeight,
fontStyle: legend.textStyle.fontStyle,
opacity: legend.textStyle.opacity
};
this.legendGroup = render.createGroup({ id: map.element.id + '_Legend_Group' });
if (legend.mode === 'Interactive') {
for (let i: number = 0; i < this.legendRenderingCollections.length; i++) {
const itemId: string = map.element.id + '_Legend_Index_' + i;
const textId: string = map.element.id + '_Legend_Index_' + i + '_Text';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const item: any = this.legendRenderingCollections[i as number];
const bounds: Rect = new Rect(item['x'], item['y'], item['width'], item['height']);
if (i === 0) {
this.renderLegendBorder();
}
const textLocation: Point = new Point(item['textX'], item['textY']);
textFont.color = (textFont.color !== null) ? textFont.color : this.maps.themeStyle.legendTextColor;
const rectOptions: RectOption = new RectOption(itemId, item['fill'], item['shapeBorder'], legend.opacity, bounds);
textOptions = new TextOption(textId, textLocation.x, textLocation.y, 'middle', item['text'], '', '');
textFont.fontFamily = !isNullOrUndefined(textFont.fontFamily) ? textFont.fontFamily : this.maps.themeStyle.fontFamily;
textFont.size = textFont.size || map.themeStyle.legendFontSize;
const textElement : Element = renderTextElement(textOptions, textFont, textFont.color, this.legendGroup);
textElement.setAttribute('aria-label', item['text']);
textElement.setAttribute('role', 'region');
const rectElement: Element = render.drawRectangle(rectOptions);
this.legendGroup.appendChild(rectElement);
if (map.legendSettings.toggleLegendSettings.enable && (legend.type === 'Layers' || legend.type === 'Markers')) {
this.maintainLegendToggle(i, rectElement, textElement);
}
this.legendToggle();
}
} else {
this.drawLegendItem(this.currentPage);
}
}
/**
* @param {number} page - Specifies the legend page.
* @returns {void}
* @private
*/
public drawLegendItem(page: number): void {
const map: Maps = this.maps;
const legend: LegendSettingsModel = <LegendSettingsModel>map.legendSettings; const spacing: number = 10;
const shapeSize: Size = new Size(legend.shapeWidth, legend.shapeHeight);
let textOptions: TextOption;
const render: SvgRenderer = map.renderer;
let legendShape: LegendShape = legend.shape;
if (page >= 0 && page < this.totalPages.length) {
if (querySelector(this.legendGroup.id, this.maps.element.id)) {
remove(querySelector(this.legendGroup.id, this.maps.element.id));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (let i: number = 0; i < (<any[]>this.totalPages[page as number]['Collection']).length; i++) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const collection: any = <any[]>this.totalPages[page as number]['Collection'][i as number];
const shapeBorder: BorderModel = collection['shapeBorder'];
const legendElement: Element = render.createGroup({ id: map.element.id + '_Legend_Index_' + collection['idIndex'] });
let legendText: string = collection['DisplayText'];
const pagingArrowPadding: number = 4;
const strokeColor: string = (legend.shape === 'HorizontalLine' || legend.shape === 'VerticalLine'
|| legend.shape === 'Cross') ? isNullOrUndefined(legend.fill) ? '#000000' : legend.fill : shapeBorder.color;
const strokeWidth: number = (legend.shape === 'HorizontalLine' || legend.shape === 'VerticalLine'
|| legend.shape === 'Cross') ? (shapeBorder.width === 0) ?
1 : shapeBorder.width : shapeBorder.width;
const shapeId: string = map.element.id + '_Legend_Shape_Index_' + collection['idIndex'];
const textId: string = map.element.id + '_Legend_Text_Index_' + collection['idIndex'];
const shapeLocation: Point = new Point(collection['Shape']['x'], (collection['Shape']['y'] - pagingArrowPadding));
const textLocation: Point = new Point(collection['Text']['x'], (collection['Text']['y'] - pagingArrowPadding));
const renderOptions: PathOption = new PathOption(
shapeId, collection['Fill'], strokeWidth, strokeColor, legend.opacity,
isNullOrUndefined(shapeBorder.opacity) ? legend.opacity : shapeBorder.opacity, ''
);
const legendTextStyle: FontModel = {
fontFamily: legend.textStyle.fontFamily, fontStyle: legend.textStyle.fontStyle,
fontWeight: legend.textStyle.fontWeight, size: legend.textStyle.size, color: legend.textStyle.color,
opacity: legend.textStyle.opacity
};
legendTextStyle.color = (legendTextStyle.color !== null) ? legendTextStyle.color :
this.maps.themeStyle.legendTextColor;
legendTextStyle.fontFamily = !isNullOrUndefined(legendTextStyle.fontFamily) ? legendTextStyle.fontFamily :
this.maps.themeStyle.fontFamily;
legendTextStyle.size = legendTextStyle.size || map.themeStyle.legendFontSize;
legendTextStyle.fontWeight = legendTextStyle.fontWeight || map.themeStyle.fontWeight;
if (i === 0) {
this.renderLegendBorder();
}
if (legend.type === 'Markers' && legend.useMarkerShape) {
const legendShapeData: object = this.legendCollection[collection['idIndex']].data[0];
const marker: MarkerSettingsModel = map.layers[legendShapeData['layerIndex']].markerSettings[legendShapeData['markerIndex']];
legendShape = !isNullOrUndefined(marker.dataSource[legendShapeData['dataIndex']][marker['shapeValuePath']]) && marker.dataSource[legendShapeData['dataIndex']][marker['shapeValuePath']] !== '' ? marker.dataSource[legendShapeData['dataIndex']][marker['shapeValuePath']] : marker.shape;
}
if (legendShape === 'Balloon') {
legendElement.appendChild(drawBalloon(map, renderOptions, shapeSize, { x: shapeLocation.x, y: (shapeLocation.y + 5)}, 'Legend'));
}
else {
legendElement.appendChild(drawSymbol(shapeLocation, legendShape, shapeSize, collection['ImageSrc'], renderOptions));
}
const legendRectSize : number = collection['Rect']['x'] + collection['Rect']['width'];
if (legendRectSize > this.legendBorderRect.width) {
const trimmedText: string = this.legendTextTrim(this.legendBorderRect.width, legendText,
legendTextStyle, legendRectSize);
legendText = trimmedText;
}
textOptions = new TextOption(textId, textLocation.x, textLocation.y, 'start', legendText, '', '');
const textElement : Element = renderTextElement(textOptions, legendTextStyle, legendTextStyle.color, legendElement);
textElement.setAttribute('aria-label', legendText);
textElement.setAttribute('role', 'region');
this.legendGroup.appendChild(legendElement);
if (map.legendSettings.toggleLegendSettings.enable && (legend.type === 'Layers' || legend.type === 'Markers')) {
const legendShapeElement: Element = legendElement.childNodes[0] as Element;
this.maintainLegendToggle(collection['idIndex'], legendShapeElement, textElement);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (i === ((<any[]>this.totalPages[page as number]['Collection']).length - 1)) {
let pagingGroup: Element; const width: number = spacing; const height: number = (spacing / 2);
if (this.page !== 0) {
const pagingText: string = (page + 1) + '/' + this.totalPages.length;
const pagingFont: FontModel = legend.textStyle;
const pagingTextSize: Size = measureText(pagingText, pagingFont);
const leftPageX: number = (this.legendItemRect.x + this.legendItemRect.width) - pagingTextSize.width -
(width * 2) - (spacing * 2) + (pagingArrowPadding / 2);
const rightPageX: number = (this.legendItemRect.x + this.legendItemRect.width);
const pageTextX: number = rightPageX - width - (pagingTextSize.width / 2) - (spacing / 2) - pagingArrowPadding;
const locY: number = (this.legendItemRect.y + this.legendItemRect.height) + (height / 2) + spacing;
pagingGroup = render.createGroup({ id: map.element.id + '_Legend_Paging_Group' });
const leftPageElement: Element = render.createGroup({ id: map.element.id + '_Legend_Left_Paging_Group' });
const rightPageElement: Element = render.createGroup({ id: map.element.id + '_Legend_Right_Paging_Group' });
const rightPath: string = ' M ' + rightPageX + ' ' + locY + ' L ' + (rightPageX - width) + ' ' + (locY - height) +
' L ' + (rightPageX - width) + ' ' + (locY + height) + ' z ';
const leftPath: string = ' M ' + leftPageX + ' ' + locY + ' L ' + (leftPageX + width) + ' ' + (locY - height) +
' L ' + (leftPageX + width) + ' ' + (locY + height) + ' z ';
const leftPageOptions: PathOption = new PathOption(
map.element.id + '_Left_Page', this.maps.themeStyle.legendTextColor, 0, this.maps.themeStyle.legendTextColor, ((page + 1) === 1 ? 0.5 : 1), 1, '', leftPath
);
leftPageElement.appendChild(render.drawPath(leftPageOptions));
const leftRectPageOptions: RectOption = new RectOption(
map.element.id + '_Left_Page_Rect', 'transparent', {}, 1,
new Rect(leftPageX - (width / 2), (locY - (height * 2)), width * 2, spacing * 2), null, null, '', ''
);
let pathEle: Element = render.drawRectangle(leftRectPageOptions);
pathEle.setAttribute('aria-label', 'Navigate to the previous legend items');
pathEle.setAttribute('role', 'button');
(pathEle as HTMLElement).tabIndex = (page + 1) === 1 ? -1 : map.tabIndex;
if ((page + 1) === 1) {
(pathEle as HTMLElement).style.cursor = 'default';
(pathEle as HTMLElement).style.setProperty('outline', 'none');
} else {
(pathEle as HTMLElement).style.cursor = 'pointer';
(pathEle as HTMLElement).style.removeProperty('outline');
}
leftPageElement.appendChild(pathEle);
this.wireEvents(leftPageElement);
const rightPageOptions: PathOption = new PathOption(
map.element.id + '_Right_Page', this.maps.themeStyle.legendTextColor, 0, this.maps.themeStyle.legendTextColor, ((page + 1) === this.totalPages.length ? 0.5 : 1), 1, '', rightPath
);
rightPageElement.appendChild(render.drawPath(rightPageOptions));
const rightRectPageOptions: RectOption = new RectOption(
map.element.id + '_Right_Page_Rect', 'transparent', {}, 1,
new Rect(rightPageX - spacing - (width / 2), (locY - (height * 2)), width * 2, spacing * 2), null, null, '', ''
);
pathEle = render.drawRectangle(rightRectPageOptions);
pathEle.setAttribute('aria-label', 'Navigate to the next legend items');
pathEle.setAttribute('role', 'button');
(pathEle as HTMLElement).tabIndex = (page + 1) === this.totalPages.length ? -1 : map.tabIndex;
if ((page + 1) === this.totalPages.length) {
(pathEle as HTMLElement).style.cursor = 'default';
(pathEle as HTMLElement).style.setProperty('outline', 'none');
} else {
(pathEle as HTMLElement).style.cursor = 'pointer';
(pathEle as HTMLElement).style.removeProperty('outline');
}
rightPageElement.appendChild(pathEle);
this.wireEvents(rightPageElement);
pagingGroup.appendChild(leftPageElement);
pagingGroup.appendChild(rightPageElement);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const pageTextOptions: any = {
'id': map.element.id + '_Paging_Text',
'x': pageTextX,
'y': locY + (pagingTextSize.height / 4),
'fill': this.maps.themeStyle.legendTextColor,
'font-size': '14px',
'font-style': pagingFont.fontStyle,
'font-family': pagingFont.fontFamily,
'font-weight': pagingFont.fontWeight,
'text-anchor': 'middle',
'transform': '',
'opacity': 1,
'dominant-baseline': ''
};
const pagingTextElement: HTMLElement = <HTMLElement>render.createText(pageTextOptions, pagingText);
pagingTextElement.style.cssText = 'user-select: none;';
pagingTextElement.setAttribute('aria-label', pagingText);
pagingTextElement.setAttribute('role', 'region');
pagingGroup.appendChild(pagingTextElement);
this.legendGroup.appendChild(pagingGroup);
}
this.legendToggle();
}
}
}
}
/**
* @param {number} legendIndex - Specifies the legend index.
* @param {Element} legendShapeElement - Specifies the legend shape element.
* @param {Element} legendTextElement - Specifies the legend text element.
* @returns {void}
* @private
*/
public maintainLegendToggle(legendIndex: number, legendShapeElement: Element, legendTextElement: Element): void {
if (this.maps.legendSettings.toggleLegendSettings.enable &&
!isNullOrUndefined(this.maps.toggledLegendId) && this.maps.toggledLegendId.indexOf(legendIndex) > -1 &&
!isNullOrUndefined(this.maps.toggledElementId) && this.maps.toggledElementId.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const currentItem: any[] = this.legendCollection[legendIndex as number]['data'];
if (!this.maps.legendSettings.toggleLegendSettings.applyShapeSettings) {
this.setToggleAttributes(legendTextElement, legendShapeElement, this.maps.legendSettings.toggleLegendSettings.fill,
this.maps.legendSettings.toggleLegendSettings.opacity,
this.maps.legendSettings.toggleLegendSettings.border.color,
this.maps.legendSettings.toggleLegendSettings.border.width,
isNullOrUndefined(this.maps.legendSettings.toggleLegendSettings.border.opacity) ?
this.maps.legendSettings.toggleLegendSettings.opacity :
this.maps.legendSettings.toggleLegendSettings.border.opacity,
this.maps.legendSettings.toggleLegendSettings.fill);
} else if (currentItem[currentItem.length - 1].length > 0) {
const layerIndex: number = currentItem[currentItem.length - 1].layerIndex;
this.setToggleAttributes(legendTextElement, legendShapeElement,
this.maps.layers[layerIndex as number].shapeSettings.fill,
this.maps.layers[layerIndex as number].shapeSettings.opacity,
/* eslint-disable-next-line max-len */
this.maps.layers[layerIndex as number].shapeSettings.border.color || this.maps.themeStyle.shapeBorderColor,
isNullOrUndefined(this.maps.layers[layerIndex as number].shapeSettings.border.width)
? 0 : this.maps.layers[layerIndex as number].shapeSettings.border.width,
isNullOrUndefined(this.maps.layers[layerIndex as number].shapeSettings.border.opacity)
? this.maps.layers[layerIndex as number].shapeSettings.opacity
: this.maps.layers[layerIndex as number].shapeSettings.border.opacity,
this.maps.layers[layerIndex as number].shapeSettings.fill);
}
currentItem['_isVisible'] = false;
}
}
public legendHighLightAndSelection(targetElement: Element, value: string): void {
let shapeIndex: number;
let layerIndex: number;
let dataIndex: number;
let pointIndex: number;
const legend: LegendSettingsModel = this.maps.legendSettings;
const textEle: Element = legend.mode === 'Default' ? document.getElementById(targetElement.id.replace('Shape', 'Text')) :
document.getElementById(targetElement.id + '_Text');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const collection: any[] = this.maps.legendModule.legendCollection;
let length: number;
const multiSelectEnable: boolean = !isNullOrUndefined(collection[0]['data'][0]['layerIndex']) ? this.maps.layers[collection[0]['data'][0]['layerIndex']].selectionSettings.enableMultiSelect : false;
let selectLength: number = 0;
let interactProcess: boolean = true;
const idIndex: number = parseFloat(targetElement.id.charAt(targetElement.id.length - 1));
this.updateLegendElement();
const toggleLegendCheck: number = this.maps.toggledLegendId.indexOf(idIndex);
if (this.maps.legendSettings.toggleLegendSettings.enable && value === 'highlight' && toggleLegendCheck !== -1) {
const collectionIndex: number = this.getIndexofLegend(this.legendHighlightCollection, targetElement);
if (collectionIndex !== -1) {
this.legendHighlightCollection.splice(collectionIndex, 1);
}
this.removeLegendHighlightCollection();
return null;
}
if (value === 'selection') {
this.shapeHighlightCollection = [];
if (!this.maps.shapeSelections && !multiSelectEnable) {
this.removeAllSelections();
this.maps.shapeSelections = true;
}
if (this.maps.legendSelectionCollection.length > 0 && (!multiSelectEnable ? this.maps.shapeSelections : true)) {
for (let k: number = 0; k < this.maps.legendSelectionCollection.length; k++) {
if (targetElement === this.maps.legendSelectionCollection[k as number]['legendElement']) {
this.maps.legendSelectionCollection[k as number]['legendElement'] = targetElement;
interactProcess = false;
this.removeLegendSelectionCollection(this.maps.legendSelectionCollection[k as number]['legendElement']);
this.maps.selectedLegendElementId.splice(this.maps.selectedLegendElementId.indexOf(idIndex), 1);
this.maps.legendSelectionCollection.splice(k, 1);
this.maps.legendSelection = this.maps.legendSelectionCollection.length > 0 ? false : true;
break;
} else if (!multiSelectEnable) {
if (this.maps.legendSelectionCollection.length > 1) {
for (let z : number = 0; z < this.maps.legendSelectionCollection.length; z++) {
this.removeLegendSelectionCollection(this.maps.legendSelectionCollection[z as number]['legendElement']);
}
this.maps.legendSelectionCollection = [];
} else {
this.removeLegendSelectionCollection(this.maps.legendSelectionCollection[k as number]['legendElement']);
this.maps.legendSelectionCollection.splice(k, 1);
}
}
}
}
} else {
if (this.maps.legendSelectionCollection.length > 0) {
for (let k: number = 0; k < this.maps.legendSelectionCollection.length; k++) {
if ((targetElement.id.indexOf('_Legend_Shape') > -1 || targetElement.id.indexOf('_Legend_Index')) &&
targetElement === this.maps.legendSelectionCollection[k as number]['legendElement']) {
interactProcess = false;
break;
} else {
this.removeLegendHighlightCollection();
}
}
}
this.removeLegendHighlightCollection();
}
if (interactProcess) {
for (let i: number = 0; i < collection.length; i++) {
const idIndex: number = this.maps.legendSettings.mode === 'Interactive' ?
parseFloat(targetElement.id.split('_Legend_Index_')[1]) :
parseFloat(targetElement.id.split('_Legend_Shape_Index_')[1]);
if (textEle.textContent === collection[i as number]['text'] && collection[i as number]['data'].length > 0
&& idIndex === i) {
const layer: LayerSettingsModel = this.maps.layers[collection[i as number]['data'][0]['layerIndex']];
let enable: boolean; let legendModule: HighlightSettingsModel | SelectionSettingsModel;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let data: any[];
if (!isNullOrUndefined(layer)) {
enable = (value === 'selection') ? layer.selectionSettings.enable : layer.highlightSettings.enable;
legendModule = void 0;
legendModule = (value === 'selection') ? layer.selectionSettings : layer.highlightSettings;
data = collection[i as number]['data'];
}
if (enable) {
for (let j: number = 0; j < data.length; j++) {
let shapeElement: Element;
shapeIndex = data[j as number]['shapeIndex'];
layerIndex = data[j as number]['layerIndex'];
dataIndex = data[j as number]['dataIndex'];
pointIndex = data[j as number]['pointIndex'];
if (pointIndex === -1) {
shapeElement = document.getElementById(this.maps.element.id + '_LayerIndex_' +
layerIndex + '_shapeIndex_' + shapeIndex + '_dataIndex_' + dataIndex);
} else {
shapeElement = document.getElementById(this.maps.element.id + '_LayerIndex_' +
layerIndex + '_shapeIndex_' + shapeIndex + '_dataIndex_' + dataIndex + '_multiLine_' + pointIndex);
}
if (shapeElement !== null) {
let shapeMatch: boolean = true;
if (this.maps.legendSelectionCollection !== null) {
for (let i: number = 0; i < this.maps.legendSelectionCollection.length; i++) {