hi all i have an angular component that creates Geofencing and it is stored n the database . and my challenge is now when the page loads is to bind it to the map back again . here is the data that is returned by the api
{
"GeofencingID": 1,
"Lat": 0,
"Lng": 0,
"Radius": 0,
"path": [
{
"Lat": -28.968001800551786,
"Lng": 27.063988775857908
},
{
"Lat": -29.862781146283663,
"Lng": 27.036522955545408
},
{
"Lat": -29.94849239274194,
"Lng": 27.975854010232908
},
{
"Lat": -29.208018172701806,
"Lng": 28.074730963357908
}
],
"Type": "polygon",
"user_id": 1,
"StartTime": "11:08",
"EndTime": "11:08"
}
and here is the html
<div id="map" style="height: 600px; width: 100%;"></div>
and here is my ts code
import { Component, AfterViewInit, ChangeDetectorRef, NgZone } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { NotificationService } from '@progress/kendo-angular-notification';
import { Generics } from './../../generics';
interface Marker {
lat: number;
lng: number;
label?: string;
infoWindowContent?: string;
}
interface Geofence {
lat?: number;
lng?: number;
radius?: number;
path?: { lat: number; lng: number }[];
type: 'circle' | 'polygon';
center?: { lat: number, lng: number };
startTime?: string;
endTime?: string;
}
declare var google: any;
@Component({
selector: 'app-geo-fencing',
templateUrl: './geo-fencing.component.html',
styleUrls: ['./geo-fencing.component.css']
})
export class GeoFencingComponent implements AfterViewInit {
isDialogVisible = false;
openDialog() {
this.isDialogVisible = true;
}
closeDialog() {
this.isDialogVisible = false;
}
public saveGeofences(): void {
this.closeDialog();
console.warn("Now Saving");
this.SaveGeoFencing();
}
public generics: Generics;
constructor(
private http: HttpClient,
private notificationService: NotificationService,
private cd: ChangeDetectorRef,
private ngZone: NgZone,private cdr: ChangeDetectorRef
) {
this.generics = new Generics(notificationService);
}
lat = -30.5595;
lng = 22.9375;
zoom = 6;
public lstResults!: any;
public loader: boolean = false;
public markers: Marker[] = [];
private mapMarkers: google.maps.Marker[] = [];
private geofenceCircles: google.maps.Circle[] = [];
private geofencePolygons: google.maps.Polygon[] = [];
private map!: google.maps.Map;
private mapInitialized = false;
private geofences: Geofence[] = [];
private drawingManager!: google.maps.drawing.DrawingManager;
private selectedShape: google.maps.Circle | google.maps.Polygon | null = null;
private shapeHistory: any[] = [];
startTime: string = '';
endTime: string = '';
noTimeLimit: boolean = false;
ngAfterViewInit(): void {
this.cdr.detectChanges();
this.ngZone.runOutsideAngular(() => {
this.initMap();
});
this.GetGeofencing();
this.generics.CheckUserProfilePermission();
setInterval(() => {
}, 3000);
}
private deserializePositions(data: any): Marker {
return {
lat: Number(data.LATITUDE),
lng: Number(data.LONGITUDE),
label: data.DEVICE_DESCRIPTION ? String(data.DEVICE_DESCRIPTION) : undefined,
infoWindowContent: data.DEVICE_DESCRIPTION ? String(data.DEVICE_DESCRIPTION) : undefined
};
}
private mapApiDataToGeofences(apiData: any[]): Geofence[] {
return apiData.map(item => ({
type: item.Type.toLowerCase(),
lat: item.Lat,
lng: item.Lng,
radius: item.Radius,
path: item.path.map((point: { Lat: number; Lng: number }) => ({
lat: point.Lat,
lng: point.Lng
}))
}));
}
public GetDevicePositions(): void {
console.log('GetDevicePositions method called');
const user_id_str = localStorage.getItem("KLS_USER_ID");
if (!user_id_str) {
console.error('No user_id found in localStorage');
return;
}
this.loader = true;
const apiurl: string = Generics.API_ENDPOINT + `DevicePositions?user_id=${encodeURIComponent(user_id_str?.toString() || '')}`;
console.log('API URL for DevicePositions:', apiurl);
this.http.get<any>(apiurl).subscribe(
(data: any) => {
console.log('Device Positions Data:', data);
this.lstResults = data;
this.markers = [];
this.lstResults.forEach((item: any) => {
console.log('Processing item:', item);
this.markers.push(this.deserializePositions(item));
});
this.ngZone.run(() => {
this.updateMap();
this.loader = false;
this.cd.detectChanges();
});
console.log('Device Positions processing complete');
},
(error: any) => {
console.error('Error fetching device positions:', error);
this.ngZone.run(() => {
this.loader = false;
this.cd.detectChanges();
});
}
);
}
private loadGeofences(): void {
console.log('loadGeofences method called');
const apiurl: string = Generics.API_ENDPOINT + 'Geofencing?user_id=1';
console.log('API URL for Geofences:', apiurl);
this.http.get<Geofence[]>(apiurl).subscribe(
data => {
console.log('Geofences Data:', data);
this.geofences = data;
console.warn("Geofence that retrived");
console.warn(this.geofences );
this.displayGeofences();
},
error => {
console.error('Error fetching geofences:', error);
}
);
}
private displayGeofences(): void {
console.warn("Inside displayGeofences");
if (!this.map) return;
this.geofenceCircles.forEach(circle => circle.setMap(null));
this.geofenceCircles = [];
this.geofencePolygons.forEach(polygon => polygon.setMap(null));
this.geofencePolygons = [];
console.warn('Displaying Geofences:', this.geofences);
this.geofences.forEach(geofence => {
if (geofence.type === 'circle' && geofence.radius != null && geofence.lat != null && geofence.lng != null) {
console.warn("Drawing Circle");
this.drawGeofence(geofence.lat, geofence.lng, geofence.radius);
} else if (geofence.type === 'polygon' && geofence.path) {
console.warn("Drawing Polygon");
const path = geofence.path.map(point => ({
lat: point.lat,
lng: point.lng
}));
this.drawPolygon(path);
} else {
console.warn("Unknown geofence type or missing path/radius:", geofence);
}
});
}
private drawGeofence(lat: number, lng: number, radius: number): void {
if (!this.map) return;
const circle = new google.maps.Circle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: this.map,
center: { lat, lng },
radius,
clickable: true,
editable: true,
zIndex: 1
});
this.geofenceCircles.push(circle);
}
private drawPolygon(path: google.maps.LatLngLiteral[]): void {
if (!this.map) return;
console.log('Drawing polygon with path:', path);
const polygon = new google.maps.Polygon({
paths: path.map(point => new google.maps.LatLng(point.lat, point.lng)),
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: this.map,
clickable: true,
editable: true,
zIndex: 1
});
this.geofencePolygons.push(polygon);
}
private updateMap(): void {
if (!this.map) {
console.error('Map is not initialized.');
return;
}
const customMarkerImage = 'assets/media/site_logo/imgs/Logo_resizeone.png';
this.mapMarkers.forEach(marker => marker.setMap(null));
this.mapMarkers = [];
this.markers.forEach(markerData => {
const marker = new google.maps.Marker({
position: { lat: markerData.lat, lng: markerData.lng },
map: this.map,
title: markerData.label,
icon: {
url: customMarkerImage,
scaledSize: new google.maps.Size(50, 50)
}
});
const infowindow = new google.maps.InfoWindow({
content: markerData.infoWindowContent || ''
});
marker.addListener('click', () => {
infowindow.open(this.map, marker);
});
this.mapMarkers.push(marker);
});
if (this.mapMarkers.length > 0 && !this.mapInitialized) {
this.lat = this.markers[0].lat;
this.lng = this.markers[0].lng;
this.map.setCenter({ lat: this.lat, lng: this.lng });
this.mapInitialized = true;
}
}
private initMap(): void {
const mapOptions: google.maps.MapOptions = {
center: { lat: this.lat, lng: this.lng },
zoom: this.zoom
};
this.map = new google.maps.Map(document.getElementById('map') as HTMLElement, mapOptions);
google.maps.event.addListenerOnce(this.map, 'idle', () => {
console.log('Map initialized');
this.initDrawingManager();
this.loadGeofences();
});
}
private initDrawingManager(): void {
if (!this.map) return;
this.drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.CIRCLE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.CIRCLE,
google.maps.drawing.OverlayType.POLYGON
]
},
circleOptions: {
fillColor: '#FF0000',
fillOpacity: 0.35,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
clickable: true,
editable: true,
zIndex: 1
},
polygonOptions: {
fillColor: '#FF0000',
fillOpacity: 0.35,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
clickable: true,
editable: true,
zIndex: 1
}
});
this.drawingManager.setMap(this.map);
google.maps.event.addListener(this.drawingManager, 'overlaycomplete', (event: google.maps.drawing.OverlayCompleteEvent) => {
const newShape = event.overlay as google.maps.Circle | google.maps.Polygon;
if (this.selectedShape) {
this.selectedShape.setMap(null);
}
this.selectedShape = newShape;
newShape.setEditable(true);
const shapeType = event.type;
let path: any;
if (shapeType === google.maps.drawing.OverlayType.CIRCLE) {
const circle = newShape as google.maps.Circle;
const center = circle.getCenter();
if (center) {
path = {
lat: center.lat(),
lng: center.lng(),
radius: circle.getRadius()
};
}
} else if (shapeType === google.maps.drawing.OverlayType.POLYGON) {
const polygon = newShape as google.maps.Polygon;
path = polygon.getPath().getArray().map(latLng => ({
lat: latLng.lat(),
lng: latLng.lng()
}));
}
if (path) {
this.geofences.push({
path: path,
type: shapeType === google.maps.drawing.OverlayType.CIRCLE ? 'circle' : 'polygon'
});
this.shapeHistory.push(newShape);
}
});
}
undoShape(): void {
const lastShape = this.shapeHistory.pop();
if (lastShape) {
lastShape.setMap(null);
this.geofences.pop();
}
}
clearShapes(): void {
this.shapeHistory.forEach(shape => shape.setMap(null));
this.shapeHistory = [];
this.geofences = [];
}
convertToTicks(time: string | null): { ticks: number } {
if (!time) {
return { ticks: 0 };
}
const [hours, minutes] = time.split(':').map(Number);
const ticks = (hours * 60 + minutes) * 600000000;
return { ticks };
}
public GetGeofencing(): void {
console.warn('GetGeofencing method called');
const user_id_str = localStorage.getItem("KLS_USER_ID");
if (!user_id_str) {
console.warn('No user_id found in localStorage');
return;
}
const apiurl: string = Generics.API_ENDPOINT + `Geofencing?user_id=${encodeURIComponent(user_id_str?.toString() || '')}`;
console.warn('API URL for Geofencing:', apiurl);
this.http.get<Geofence[]>(apiurl).subscribe(
(data: Geofence[]) => {
console.warn('Geofencing Data:', data);
this.geofences = data;
this.displayGeofences();
},
(error: any) => {
console.warn('Error fetching Geofencing Data', error);
}
);
}
private convertToGoogleMapsPath(apiPath: { Lat: number; Lng: number }[]): google.maps.LatLngLiteral[] {
return apiPath.map(point => ({
lat: point.Lat,
lng: point.Lng
}));
}
public SaveGeoFencing(): void {
const user_id_str = localStorage.getItem("KLS_USER_ID");
if (!user_id_str) {
console.error('No user_id found in localStorage');
return;
}
console.warn("Inside Save");
console.warn("this.startTime:", this.startTime);
console.warn("this.endTime:", this.endTime);
this.geofences.forEach(geofence => {
const path = Array.isArray(geofence.path) ? geofence.path.map(p => ({
lat: typeof p.lat === 'number' ? p.lat : 0,
lng: typeof p.lng === 'number' ? p.lng : 0
})) : [{ lat: 0, lng: 0 }];
const request: any = {
lat: typeof geofence.lat === 'number' ? geofence.lat : 0,
lng: typeof geofence.lng === 'number' ? geofence.lng : 0,
radius: typeof geofence.radius === 'number' ? geofence.radius : 0,
path: path,
type: typeof geofence.type === 'string' ? geofence.type : '',
user_id: user_id_str,
startTime: this.startTime ,
endTime: this.endTime
};
console.warn("Done Preparing");
console.warn("Remove bad Entries");
Object.keys(request).forEach(key => {
if (request[key] === null || request[key] === undefined) {
delete request[key];
}
});
console.warn("Done Removing bad entries");
console.warn("Preparing data to send");
const serializedData = JSON.stringify(request);
console.warn('Map Data to be sent:', serializedData);
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
console.warn("URL to use " + Generics.API_ENDPOINT + `Geofencing`);
this.http.post<any>(Generics.API_ENDPOINT + `Geofencing`, serializedData, { headers })
.subscribe(
response => {
console.log('Geofence saved successfully', response);
this.generics.showSuccess("Geofence saved successfully", this.notificationService);
this.GetGeofencing();
},
error => {
console.error('Error saving geofence', error);
this.generics.showdanger("Error saving geofence", this.notificationService);
}
);
});
}
private calculatePolygonCenter(path: google.maps.MVCArray<google.maps.LatLng>): { lat: number, lng: number } | null {
if (path.getLength() === 0) return null;
let latSum = 0;
let lngSum = 0;
const count = path.getLength();
for (let i = 0; i < count; i++) {
const point = path.getAt(i);
latSum += point.lat();
lngSum += point.lng();
}
return {
lat: latSum / count,
lng: lngSum / count
};
}
private handlePolygonComplete(polygon: google.maps.Polygon): void {
const path = polygon.getPath();
const center = this.calculatePolygonCenter(path);
if (center) {
this.geofences.push({
path: path.getArray().map(latLng => ({
lat: latLng.lat(),
lng: latLng.lng()
})),
center: center,
type: 'polygon'
});
this.shapeHistory.push({
type: 'polygon',
data: {
path: path.getArray().map(latLng => ({
lat: latLng.lat(),
lng: latLng.lng()
})),
center: center
}
});
}
}
}
```
when i try this , it does not show the polygon
What I have tried:
i tried to hard code it , it shows but when brining data dynamically it does not show. the data that i gave an example , comes from an api