← Back to Blog Archive

Part 3: Modern Frontend with 3D Map and Live Panel

Learn how to build a high-performance 3D asset tracking dashboard using Angular and Cesium.js. Featuring real-time SignalR integration, dynamic 3D models, and geofence alerting.

Part 3: Modern Frontend with 3D Map and Live Panel Cover Image

Modern Frontend with 3D Map and Live Panel

GitHub Repo

Angular & Cesium for Real-Time Asset Tracking on a 3D Map

In previous parts, we built a simulator and backend API. Now we'll visualize everything with Angular and Cesium.js for real-time 3D asset tracking.


Key Features

  • Real-Time Updates: SignalR connection for live telemetry
  • 3D Visualization: Cesium renders assets with dynamic models and trails
  • Modern UI: Card-based panel with color-coded badges
  • Geofence Management: Draw boundaries and get instant alerts
  • Responsive Design: Works on desktop and mobile

Architecture

src/app/
├── components/
│   ├── cesium-map/              # 3D map with Cesium
│   ├── connection-status-badge/ # Connection indicator
│   ├── geofence-alert/          # Violation alerts
│   └── telemetry-panel/         # Live asset cards
├── services/
│   ├── signalr.service.ts       # WebSocket connection
│   └── geofence.service.ts      # Boundary logic
├── models/
│   ├── telemetry-point.model.ts
│   └── geofence.model.ts
├── enums/
├── helpers/
└── utilities/

SignalR Connection

The SignalRService handles real-time updates:

export class SignalRService {
  async startConnection(url: string): Promise<void> {
    this.hubConnection = new signalR.HubConnectionBuilder()
      .withUrl(url)
      .withAutomaticReconnect()
      .build();

    this.hubConnection.on('ReceiveTelemetry', (data: TelemetryPoint) => {
      this.telemetrySubject.next(data);
    });

    await this.hubConnection.start();
  }
}

How it works:

  1. Establishes WebSocket connection to backend
  2. Automatically reconnects on connection loss
  3. Listens for ReceiveTelemetry events
  4. Broadcasts updates to all subscribers via RxJS Subject

3D Map with Cesium

The CesiumMapComponent renders assets in 3D with:

  • Dynamic Models: Different 3D models for aircraft, drones, vehicles
  • Trails: Visual path history
  • Orientation: Assets rotate based on heading/pitch/roll
  • Geofence Drawing: Click to create boundaries

Creating Entities

viewer.entities.add({
  id: pt.assetId,
  position,
  orientation: new Cesium.ConstantProperty(orientation),
  model: {
    uri: CesiumUtility.getModelUri(pt.assetType),
    scale: 2,
    minimumPixelSize: 64
  },
  polyline: {
    positions: this._trails.get(pt.assetId),
    width: 2,
    material: CesiumUtility.getTrailColor(pt.assetType)
  }
});

Key Components:

  • position: Geographic coordinates (latitude, longitude, altitude)
  • orientation: 3D rotation based on heading, pitch, roll
  • model: 3D GLB model file for visual representation
  • polyline: Trail showing asset's movement history

Performance

Updates are throttled to 100ms intervals for smooth rendering even with 45+ concurrent assets.


Telemetry Panel

The TelemetryPanelComponent displays assets in expandable cards:

  • Color-Coded Badges: Blue (aircraft), orange (drone), green (vehicle)
  • Material Icons: Visual asset type indicators
  • Click to Zoom: Selecting a card zooms the map to that asset
  • Smooth Animations: 225ms transitions
<div class="asset-card" (click)="toggleRow(asset)">
  <div class="asset-type-badge" [style.background]="getAssetTypeColor(asset.raw?.assetType)">
    <mat-icon>{{ getAssetTypeIcon(asset.raw?.assetType) }}</mat-icon>
  </div>
  <div class="asset-id">{{ asset.id }}</div>
  <span class="metric-value">{{ asset.speed }} m/s</span>
</div>

Features:

  • Real-time metric updates (speed, altitude, heading)
  • Expandable details view
  • Last update timestamp
  • Smooth card animations

Geofence Management

The GeofenceService enables boundary monitoring:

  1. Click Draw Geofence button
  2. Click points on the map
  3. Double-click to finish
  4. Get instant alerts on entry/exit violations
checkGeofenceViolations(assetId: string, point: TelemetryPoint): GeofenceViolation[] {
  this.geofences.forEach(geofence => {
    const isInside = this._isPointInPolygon(point, geofence.polygon);
    const wasInside = this.assetStates.get(assetId)?.get(geofence.id) ?? false;

    if (isInside && !wasInside && geofence.alertOnEntry) {
      violations.push({ type: 'ENTRY', geofenceId: geofence.id });
    }
  });
}

Violation Detection:

  • Uses point-in-polygon algorithm
  • Tracks previous asset states
  • Detects both entry and exit events
  • Configurable alert types per geofence

The GeofenceAlertComponent shows blinking notifications with sound alerts that auto-dismiss after 15 seconds.


User Experience

  • Connection Badge: Shows SignalR status (connected/disconnected/reconnecting)
  • Trail Toggle: Show/hide asset paths
  • Auto Zoom: Map automatically fits all assets on first load
  • Responsive: Panel collapses on mobile devices

Configuration

Edit environment.ts:

export const environment = {
  production: false,
  signalRHubUrl: 'http://localhost:5073/hubs/telemetry',
  cesiumBaseUrl: 'assets/cesium',
  cesiumIonToken: '' // Optional
};

Configuration Options:

  • signalRHubUrl: Backend SignalR hub endpoint
  • cesiumBaseUrl: Path to Cesium library assets
  • cesiumIonToken: Optional token for Cesium Ion services (better terrain, imagery)

Running

cd backend
docker compose up --build

Open http://localhost:5073

Local Development

cd frontend/critical-asset-frontend
npm install
npm start

Open http://localhost:4200


Customization

Add Asset Types

In CesiumUtility:

public static getModelUri(type?: AssetType): string {
  const models: Record<AssetType, string> = {
    [AssetType.Aircraft]: 'assets/models/Cesium_Air.glb',
    [AssetType.Drone]: 'assets/models/drone.glb',
    [AssetType.Vehicle]: 'assets/models/GroundVehicle.glb',
    [AssetType.YourNewType]: 'assets/models/YourModel.glb'
  };
  return models[type ?? AssetType.Aircraft];
}

Adjust Throttling

private _updateThrottleMs = 100; // Lower = more updates, higher CPU usage

Customize Colors

public static getAssetTypeColor(type?: AssetType): string {
  const colors: Record<AssetType, string> = {
    [AssetType.Aircraft]: '#2196F3',  // Blue
    [AssetType.Drone]: '#FF9800',     // Orange
    [AssetType.Vehicle]: '#4CAF50'    // Green
  };
}

Conclusion

The frontend combines Angular's component architecture with Cesium's 3D rendering for a powerful real-time monitoring dashboard. SignalR ensures live updates, while throttling and optimization maintain smooth performance with dozens of concurrent assets.

Key Takeaways

  • SignalR provides WebSocket-based real-time updates
  • Cesium renders 3D assets with trails and orientation
  • Card-based UI improves readability and interaction
  • Geofence alerts enable proactive monitoring
  • Optimizations ensure 60 FPS with 45+ assets

Next Steps

In Part 4: CI/CD and Monitoring with Prometheus & Grafana, we will dive into the operational side of the project:

  • Automated Pipelines: Setting up CI/CD for both the .NET backend and Angular frontend.
  • Infrastructure as Code: Containerizing the entire stack using Docker and Orchestration.
  • Full-Stack Observability: Implementing Prometheus metrics and Grafana dashboards to monitor SignalR throughput, message latency, and system health.

Prepared by Burhan Sözer
Software & GIS Engineer*