import { CommonModule } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; // modules import { AngularSvgIconModule } from 'angular-svg-icon'; import { NgbModule, NgbPopover, NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; // Components import { CaMapComponent } from '../ca-map/ca-map.component'; import { CaAppTooltipV2Component } from '../ca-app-tooltip-v2/ca-app-tooltip-v2.component'; // Constants import { ProgressBarConstants } from './utils/constants'; import { MapOptionsConstants } from '../ca-map/utils/constants'; // models import { IGpsProgress, IProgressBarData } from './interfaces'; import { ICaMapProps, IMapMarkers, IMapRoutePath } from '../ca-map/models'; // svg-routes import { ProgressBarSvgRoutes } from './utils/svg-routes'; import { SharedSvgRoutes } from '../../utils/svg-routes'; // pipes import { ConvertMinutesToHoursPipe } from './pipes'; import { SafeHtmlPipe } from '../../pipes'; // Enums import { eProgressBarString } from './enums'; import { eColor, ePosition, eSharedString, eStringPlaceholder, eUnit, eThousandSeparatorFormat, eDateTimeFormats, } from '../../enums'; // Services import { MapMarkerIconService } from '../ca-map/utils/services'; @Component({ selector: 'app-ca-progress-bar', templateUrl: './ca-progress-bar.component.html', styleUrls: ['./ca-progress-bar.component.scss'], imports: [ // Modules CommonModule, AngularSvgIconModule, NgbModule, NgbTooltip, // Components CaMapComponent, CaAppTooltipV2Component, // Pipes ConvertMinutesToHoursPipe, SafeHtmlPipe, ], }) export class ProgressBarComponent { @Input() set progressBarData(values: IProgressBarData) { if (values) { this._progressBarData = values; this.setProgressData(); } } @Input() dropdownWidth: number | null = null; @Input() mapWidth: number | null = null; @Input() isDisabled: boolean = false; @Output() onOpenMap = new EventEmitter(); public _progressBarData: IProgressBarData | null = null; public _gpsProgress: IGpsProgress[] = []; public currentPosition: number = 0; public gpsIconTopPosition: number = 0; public hoveredGpsTitle: string | null = null; public hoveredMileageInfo: string | null = null; public hoveredGpsIcon: boolean = false; public staticConstant = ProgressBarConstants; public progressBarSvgRoutes = ProgressBarSvgRoutes; public sharedSvgRoutes = SharedSvgRoutes; public mapData: ICaMapProps = { markers: [], clusterMarkers: [], routingMarkers: [], routePaths: [], darkMode: true, }; public eUnit = eUnit; public ePosition = ePosition; public eColor = eColor; public eThousandSeparatorFormat = eThousandSeparatorFormat; public eDateTimeFormats = eDateTimeFormats; get gpsStopsWithoutCurrentLocation(): IGpsProgress[] { return this._gpsProgress.filter( (stop) => stop.type !== eSharedString.CURRENT_LOCATION ); } constructor(private markerIconService: MapMarkerIconService) {} public hoverStop(stop: IGpsProgress): void { this.hoveredGpsTitle = stop?.isAtStop ? eProgressBarString.CURRENT_LOCATION : stop?.heading || null; this.hoveredMileageInfo = !stop?.isAtStop ? stop?.mileage : eStringPlaceholder.EMPTY; } public hoverCurrentLocation(): void { this.hoveredGpsTitle = eProgressBarString.CURRENT_LOCATION; this.hoveredMileageInfo = eStringPlaceholder.EMPTY; } public leaveStop(): void { this.hoveredGpsTitle = null; this.hoveredMileageInfo = null; } public showDropdownMap(t2: NgbPopover): void { if (this.isDisabled) return; t2.open(); this.onOpenMap.emit(); } private setGpsProgress(gpsProgressData: IGpsProgress[]): void { this._gpsProgress = gpsProgressData; this.setMapMarkers(); this.calculateGpsIconPosition(); } private setMapMarkers(): void { let routeMarkers: IMapMarkers[] = []; let routePaths: IMapRoutePath[] = []; const currentLocationIndex = this._gpsProgress.findIndex( (stop) => stop.type === eSharedString.CURRENT_LOCATION ); this._gpsProgress.forEach((loadStop, index) => { const markerData = { position: { lat: loadStop.latitude, lng: loadStop.longitude }, }; const markerIcon = !!loadStop.motionStatus ? this.markerIconService.getCurrentLocationMarkerIcon( markerData, loadStop.motionStatus ) : this.markerIconService.getRoutingMarkerIcon( markerData, loadStop.stopNumber ?? 0, loadStop.type, this.currentPosition >= loadStop.position ); const routeMarker: IMapMarkers = { ...markerData, content: markerIcon, }; routeMarkers = [...routeMarkers, routeMarker]; if (loadStop.routeShape) { const strokeColor = index <= currentLocationIndex ? MapOptionsConstants.ROUTING_PATH_DARK_COLORS[ 'complete' ] : MapOptionsConstants.ROUTING_PATH_DARK_COLORS[ 'incomplete' ]; const isDashed = this._gpsProgress?.[index - 1]?.type === eProgressBarString.DEADHEAD; const routePath: IMapRoutePath = { path: [], decodedShape: loadStop.routeShape, strokeColor, strokeOpacity: 1, strokeWeight: 4, isDashed, }; routePaths = [...routePaths, routePath]; } }); this.mapData = { ...this.mapData, isZoomShown: true, routingMarkers: routeMarkers, routePaths: routePaths, }; } private calculateGpsIconPosition(): void { let topPosition = 0; let currentStopPercentage = null; const stopPercentage = 100 / (this.gpsStopsWithoutCurrentLocation.length - 1); this.gpsStopsWithoutCurrentLocation.forEach((stop, index) => { const isAtDeadhead = stop.isAtStop && !index; if (stop.isVisited && !isAtDeadhead) topPosition += index ? stopPercentage : stopPercentage / 2; if (stop.isAtStop) currentStopPercentage = stopPercentage * index; }); this.gpsIconTopPosition = currentStopPercentage ?? topPosition; } private setProgressData(): void { if (this._progressBarData) { this.currentPosition = this._progressBarData.currentPosition > 100 ? 100 : (this._progressBarData.currentPosition ?? 0); if (this._progressBarData.gpsProgress) this.setGpsProgress(this._progressBarData.gpsProgress); } } }