UNPKG

@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
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++) {