Click here to Skip to main content
16,004,505 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
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; // Format: 'HH:MM:SS'
  endTime?: string;   // Format: 'HH:MM:SS',

}
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();
    // Save geofences logic
    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[] = []; // Store history of shapes for undo
 
  startTime: string = '';
  endTime: string = '';
  noTimeLimit: boolean = false;
  ngAfterViewInit(): void {
    this.cdr.detectChanges();
    this.ngZone.runOutsideAngular(() => {
      this.initMap();
    });
    //this.GetDevicePositions();
    this.GetGeofencing();
    this.generics.CheckUserProfilePermission(); 
  
    setInterval(() => {
    //  this.GetDevicePositions();
    }, 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
    };
  }
// Ensure that item.path is properly typed
private mapApiDataToGeofences(apiData: any[]): Geofence[] {
  return apiData.map(item => ({
    type: item.Type.toLowerCase(), // Convert 'Type' to lowercase
    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;
  
    // Clear existing geofences
    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); // Log path to ensure it's correct
  
    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';

    // Clear existing markers from the map
    this.mapMarkers.forEach(marker => marker.setMap(null));
    this.mapMarkers = [];

    // Add new markers
    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, // Set the custom marker image
          scaledSize: new google.maps.Size(50, 50) // Optional: Scale the image
        }
      });

      const infowindow = new google.maps.InfoWindow({
        content: markerData.infoWindowContent || '' // Correct type for content
      });

      marker.addListener('click', () => {
        infowindow.open(this.map, marker);
      });

      // Save marker to clear it later
      this.mapMarkers.push(marker);
    });

    // Only set the center initially or if there are no existing markers
    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);
  
    // Verify map initialization
    google.maps.event.addListenerOnce(this.map, 'idle', () => {
      console.log('Map initialized');
      this.initDrawingManager();
      this.loadGeofences(); // Load geofences after map is initialized
    });
  }
  

  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); // Store the shape in history
      }
    });
  }
  undoShape(): void {
    const lastShape = this.shapeHistory.pop();
    if (lastShape) {
      lastShape.setMap(null);
      this.geofences.pop(); // Remove corresponding geofence entry
    }
  }
  
  // Clear all shapes
  clearShapes(): void {
    this.shapeHistory.forEach(shape => shape.setMap(null));
    this.shapeHistory = [];
    this.geofences = [];
  }
// Helper function to convert time to ticks
convertToTicks(time: string | null): { ticks: number } {
  if (!time) {
    return { ticks: 0 }; // Default to 0 ticks if time is null
  }

  // Example conversion logic, adjust based on your needs
  const [hours, minutes] = time.split(':').map(Number);
  const ticks = (hours * 60 + minutes) * 600000000; // Example conversion to ticks
  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 => {
    // Ensure path is an array of objects with correct format
    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 }];

    // Prepare the request payload
    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, // Use the array directly
      type: typeof geofence.type === 'string' ? geofence.type : '',
      user_id:  user_id_str, // Replace with actual user ID if needed
      startTime:  this.startTime ,
      endTime:  this.endTime 
    };

    console.warn("Done Preparing");

    console.warn("Remove bad Entries");

    // Remove properties with null or undefined values
    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");

    // Prepare serialized data for POST request
    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`);

    // Send POST request to API
    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, // Ensure this matches the Geofence type definition
      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
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900