Skip to content

Commit

Permalink
Add markers for devices on map
Browse files Browse the repository at this point in the history
  • Loading branch information
stalehd committed Apr 10, 2023
1 parent 1b37c5c commit e69d29b
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 64 deletions.
28 changes: 14 additions & 14 deletions frontend/src/app/device-map-view/device-map-view.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnDestroy, OnIn
import { V1Device } from '../api/pax';
import { environment } from 'src/environments/environment';
import { AttributionControl, FullscreenControl, Map, NavigationControl, Marker, MarkerOptions } from 'maplibre-gl';
import { SampleService } from '../sample.service';

@Component({
selector: 'app-device-map-view',
Expand All @@ -14,13 +15,16 @@ export class DeviceMapViewComponent implements OnInit, AfterViewInit, OnDestroy,
@ViewChild("map") mapContainer?: ElementRef<HTMLElement>;
map?: Map;

constructor() { }
constructor(
private samples: SampleService,
) {
}

ngOnInit(): void {
}

ngOnChanges() {
this.addMarkerForDevice(this.device, this.map);
this.flyToMarker(this.device, this.map);
}
ngAfterViewInit(): void {
if (this.map) {
Expand All @@ -40,8 +44,12 @@ export class DeviceMapViewComponent implements OnInit, AfterViewInit, OnDestroy,
"Style © <a href='http://openmaptiles.org/'>MapTiler</a> | " +
"Data © <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap contributors</a>"
}));

this.addMarkerForDevice(this.device, this.map);
this.samples.activeDevices().subscribe({
complete: () => {
this.samples.addMapMarkers(this.map!);
}
});
this.flyToMarker(this.device, this.map);
}

ngOnDestroy(): void {
Expand All @@ -52,7 +60,7 @@ export class DeviceMapViewComponent implements OnInit, AfterViewInit, OnDestroy,
cameraBearing: number = 0;
enableRotation: boolean = false;

addMarkerForDevice(device?: V1Device, map?: Map): void {
flyToMarker(device?: V1Device, map?: Map): void {
if (!device || !map) {
return;
}
Expand All @@ -77,14 +85,6 @@ export class DeviceMapViewComponent implements OnInit, AfterViewInit, OnDestroy,
});
return
}
let d_lat = device.lat
let d_lon = device.lon
let marker = new Marker({
color: '#ff0000',
});

marker.setLngLat([d_lat, d_lon]);
marker.addTo(this.map!);

if (this.enableRotation) {
// Already animating something
Expand All @@ -96,7 +96,7 @@ export class DeviceMapViewComponent implements OnInit, AfterViewInit, OnDestroy,
this.map?.flyTo({
// These options control the ending camera position: centered at
// the target, at zoom level 9, and north up.
center: [d_lat, d_lon],
center: [device.lat, device.lon],
zoom: 16,
pitch: 45,
bearing: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="all-chart">
<h2>Totalt for alle enheter</h2>
<div #allchart id="allchart" class="allchart"></div>
<div class="update">Sist oppdatert {{ samples.lastDataUpdate |date:'YYYY-mm-dd HH:MM'}}</div>
<div class="update">Sist oppdatert {{ samples.lastDataUpdate |date:'YYYY-MM-dd HH:mm'}}</div>
</div>
</div>
<div class="cell-chart">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/device-view/device-view.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="data">
<h2>{{ device.name }}</h2>
<div #chart id="chart" class="chart"></div>
Sist oppdatert {{ samples.lastDataUpdate |date:'YYYY-mm-dd HH:MM'}}
Sist oppdatert {{ samples.lastDataUpdate |date:'YYYY-MM-dd HH:mm'}}
</div>
<div class="device-info">
<div class="metric">
Expand Down
78 changes: 30 additions & 48 deletions frontend/src/app/sample.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Injectable } from '@angular/core';
import { PaxServiceService, V1Data, V1Device, V1ListDataResponse, V1ListDevicesResponse, V1Sample } from './api/pax';
import { Observable, ReplaySubject, interval } from 'rxjs';
import { PaxServiceService, V1Data, V1Device, V1ListDataResponse } from './api/pax';
import { Observable, ReplaySubject } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
import { Map, Marker } from 'maplibre-gl';

// Also a custom sample setup
export interface DeviceSample {
Expand All @@ -20,27 +21,23 @@ export class SampleService {
public errorMessage: string = "";

public lastDataUpdate: Date = new Date();
private lastPoll: Date = new Date();

// Subject for initial data load
private dataSubject = new ReplaySubject<DeviceSample>();

// Subject for updates
private updateSubject = new ReplaySubject<DeviceSample>();

private activeDeviceSubject = new ReplaySubject<V1Device>();

// Might not need this
private allSamples: V1Data[] = [];

private allActiveDevices: V1Device[] = [];
// Return a list of active devices, ie devices with data in the selected interval. We won't care about
// devices that goes out of fashion, ie if the selected interval changes and the device hasn't sent any
// data. A simple refresh of the page will fix that issue.
public activeDevices(): Observable<V1Device> {
return this.activeDeviceSubject;
}

dataUpdater = interval(60000).subscribe((val) => this.pollForChanges());

constructor(
protected paxService: PaxServiceService,
) {
Expand All @@ -52,7 +49,6 @@ export class SampleService {
let dayAgo: string = "" + (new Date().getTime() - (chartIntervalHours * 3600 * 1000));
let now: string = "" + (new Date().getTime());
this.lastDataUpdate = new Date();
this.lastPoll = new Date();
this.paxService.paxServiceListData(dayAgo, now).subscribe({
next: (value: V1ListDataResponse) => {
if (value.data) {
Expand All @@ -69,16 +65,18 @@ export class SampleService {
});
});
});
this.allSamples.map(v => {
this.allActiveDevices = this.allSamples.map(v => {
let ret: V1Device = {
id: v.deviceId,
name: v.deviceName,
lat: v.lat,
lon: v.lon,
};
return ret;
}).forEach((device => {
});
this.allActiveDevices.forEach((device => {
this.activeDeviceSubject.next(device);
this.allActiveDevices.push(device);
}));
},
error: (e: HttpErrorResponse) => {
Expand All @@ -94,49 +92,33 @@ export class SampleService {
});
}

private pollForChanges(): void {
let lastCheck: string = "" + this.lastPoll.getTime();
this.lastPoll = new Date();
this.paxService.paxServiceListData(lastCheck).subscribe({
next: (value: V1ListDataResponse) => {
if (value.data) {
value.data.forEach((data) => this.addDataToSamples(data));
}
},
error: (e: HttpErrorResponse) => {
this.errorMessage = e.message;
this.updateSubject.error(e);
},
complete: () => {
},
});
}

// Add samples to the existing data set
private addDataToSamples(data: V1Data): void {
var exists: boolean = false;
this.allSamples.forEach((set, index) => {
if (set.deviceId == data.deviceId) {
exists = true;
set.samples?.forEach((sample) => {
this.allSamples[index].samples?.push(sample);
});
console.debug("Added " + (set.samples?.length || 0) + " samples to data for " + set.deviceId)
}
});
if (!exists) {
console.debug("New device; adding new sample set: ", data);
this.allSamples.push(data);
}
}

public hasError(): boolean {
return this.errorMessage != "";
}

public allData(): Observable<DeviceSample> {
// TODO: If the data is more than N minutes old return a new sample set
let now = new Date()
let diff = now.getTime() - this.lastDataUpdate.getTime();
if (diff > 60000) {
this.dataSubject = new ReplaySubject<DeviceSample>();
this.activeDeviceSubject = new ReplaySubject<V1Device>();
this.fetchData();
}
return this.dataSubject;
}

// A bit hackish: Add map markers for all devices with positions. This should *strictly* be in part of the
// presentation layer but.. this works too.
public addMapMarkers(map: Map) {
this.allActiveDevices.forEach((device: V1Device) => {
if (device.lat && device.lat != 0 && device.lon && device.lon != 0) {
let marker = new Marker({
color: '#ff0000',
});

marker.setLngLat([device.lat, device.lon]);
marker.addTo(map);
}
});
}
}

0 comments on commit e69d29b

Please sign in to comment.