Commit 287033a627a21c20487d99d4637dcbde8517f044
1 parent
c4e00deb95
Exists in
master
add vessel position to map
Showing 5 changed files with 54 additions and 21 deletions Inline Diff
src/app/component/import-vessels/import-vessels.component.ts
View file @
287033a
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; | 1 | 1 | import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; | |
import {VesselsService} from '../../service/vessels.service'; | 2 | 2 | import {VesselsService} from '../../service/vessels.service'; | |
import {Message} from '../../model/message'; | 3 | 3 | import {Message} from '../../model/message'; | |
import {Vessels} from '../../model/vessels'; | 4 | 4 | import {Vessels} from '../../model/vessels'; | |
5 | 5 | |||
@Component({ | 6 | 6 | @Component({ | |
selector: 'app-import-vessels', | 7 | 7 | selector: 'app-import-vessels', | |
templateUrl: './import-vessels.component.html', | 8 | 8 | templateUrl: './import-vessels.component.html', | |
styleUrls: ['./import-vessels.component.scss'] | 9 | 9 | styleUrls: ['./import-vessels.component.scss'] | |
}) | 10 | 10 | }) | |
export class ImportVesselsComponent implements OnInit { | 11 | 11 | export class ImportVesselsComponent implements OnInit { | |
vessels: Vessels; | 12 | 12 | vessels: Vessels; | |
13 | 13 | |||
constructor(private vesselsService: VesselsService) { | 14 | 14 | constructor(private vesselsService: VesselsService) { | |
} | 15 | 15 | } | |
16 | 16 | |||
@ViewChild('fileDropRef', {static: false}) fileDropEl: ElementRef; | 17 | 17 | @ViewChild('fileDropRef', {static: false}) fileDropEl: ElementRef; | |
files: any[] = []; | 18 | 18 | files: any[] = []; | |
19 | 19 | |||
ngOnInit(): void { | 20 | 20 | ngOnInit(): void { | |
this.vesselsService.currentVessels.subscribe(vessels => this.vessels = vessels); | 21 | 21 | this.vesselsService.currentVessels.subscribe(vessels => this.vessels = vessels); | |
} | 22 | 22 | } | |
23 | 23 | |||
/** | 24 | |||
* on file drop handler | 25 | |||
*/ | 26 | |||
onFileDropped($event): void { | 27 | 24 | onFileDropped($event): void { | |
this.prepareFilesList($event); | 28 | 25 | this.prepareFilesList($event); | |
} | 29 | 26 | } | |
30 | 27 | |||
/** | 31 | |||
* handle file from browsing | 32 | |||
*/ | 33 | |||
fileBrowseHandler(files): void { | 34 | 28 | fileBrowseHandler(files): void { | |
this.prepareFilesList(files); | 35 | 29 | this.prepareFilesList(files); | |
} | 36 | 30 | } | |
37 | 31 | |||
/** | 38 | |||
* Delete file from files list | 39 | |||
* @param index (File index) | 40 | |||
*/ | 41 | |||
deleteFile(index: number): void { | 42 | 32 | deleteFile(index: number): void { | |
if (this.files[index].progress < 100) { | 43 | 33 | if (this.files[index].progress < 100) { | |
return; | 44 | 34 | return; | |
} | 45 | 35 | } | |
this.vessels = new Vessels(); | 46 | 36 | this.vessels = new Vessels(); | |
this.vesselsService.changeVesselsSet(this.vessels); | 47 | 37 | this.vesselsService.changeVesselsSet(this.vessels); | |
this.files.splice(index, 1); | 48 | 38 | this.files.splice(index, 1); | |
} | 49 | 39 | } | |
50 | 40 | |||
51 | ||||
uploadFiles(index: number): void { | 52 | 41 | uploadFiles(index: number): void { | |
const fileReader = new FileReader(); | 53 | 42 | const fileReader = new FileReader(); | |
let nbLine: number; | 54 | 43 | let nbLine: number; | |
fileReader.onload = (e) => { | 55 | 44 | fileReader.onload = () => { | |
this.vessels = new Vessels(); | 56 | 45 | this.vessels = new Vessels(); | |
const lines: string[] = (fileReader.result as string).split('\n'); | 57 | 46 | const lines: string[] = (fileReader.result as string).split('\n'); | |
nbLine = lines.length; | 58 | 47 | nbLine = lines.length; | |
for (let line of lines) { | 59 | 48 | for (let line of lines) { | |
line = line.replace(/[^\x20-\x7F]/g, ''); | 60 | 49 | line = line.replace(/[^\x20-\x7F]/g, ''); | |
const splitLine = line.split(','); | 61 | 50 | const splitLine = line.split(','); | |
if (isNaN(Number(splitLine[0])) || line === '') { | 62 | 51 | if (isNaN(Number(splitLine[0])) || line === '') { | |
continue; | 63 | 52 | continue; | |
} | 64 | 53 | } | |
const newMessage = new Message(splitLine); | 65 | 54 | const newMessage = new Message(splitLine); | |
this.vessels.addMessage(newMessage); | 66 | 55 | this.vessels.addMessage(newMessage); | |
} | 67 | 56 | } | |
this.vesselsService.changeVesselsSet(this.vessels); | 68 | 57 | this.vesselsService.changeVesselsSet(this.vessels); | |
}; | 69 | 58 | }; | |
70 | 59 | |||
fileReader.onprogress = (e) => { | 71 | 60 | fileReader.onprogress = (e) => { | |
if (e.lengthComputable) { | 72 | 61 | if (e.lengthComputable) { | |
this.files[index].progress = Math.round(((e.loaded / e.total) * 100)); | 73 | 62 | this.files[index].progress = Math.round(((e.loaded / e.total) * 100)); | |
} | 74 | 63 | } | |
}; | 75 | 64 | }; | |
76 | 65 | |||
fileReader.readAsText(this.files[index]); | 77 | 66 | fileReader.readAsText(this.files[index]); | |
} | 78 | 67 | } | |
79 | 68 | |||
prepareFilesList(files: Array<any>): void { | 80 | 69 | prepareFilesList(files: Array<any>): void { | |
this.files = []; | 81 | 70 | this.files = []; | |
for (const item of files) { | 82 | 71 | for (const item of files) { | |
item.progress = 0; | 83 | 72 | item.progress = 0; | |
this.files.push(item); | 84 | 73 | this.files.push(item); | |
} | 85 | 74 | } | |
this.fileDropEl.nativeElement.value = ''; | 86 | 75 | this.fileDropEl.nativeElement.value = ''; | |
this.uploadFiles(0); | 87 | 76 | this.uploadFiles(0); | |
} | 88 | 77 | } |
src/app/component/list-vessel/list-vessel.component.ts
View file @
287033a
import {Component, OnInit} from '@angular/core'; | 1 | 1 | import {AfterViewInit, Component, OnInit} from '@angular/core'; | |
import {VesselsService} from '../../service/vessels.service'; | 2 | 2 | import {VesselsService} from '../../service/vessels.service'; | |
import {Vessels} from '../../model/vessels'; | 3 | 3 | import {Vessels} from '../../model/vessels'; | |
4 | ||||
declare var $: any; | 4 | 5 | declare var $: any; | |
5 | 6 | |||
@Component({ | 6 | 7 | @Component({ | |
selector: 'app-list-vessel', | 7 | 8 | selector: 'app-list-vessel', | |
templateUrl: './list-vessel.component.html', | 8 | 9 | templateUrl: './list-vessel.component.html', | |
styleUrls: ['./list-vessel.component.scss'] | 9 | 10 | styleUrls: ['./list-vessel.component.scss'] | |
}) | 10 | 11 | }) | |
export class ListVesselComponent implements OnInit { | 11 | 12 | export class ListVesselComponent implements OnInit { | |
vessels: Vessels; | 12 | 13 | vessels: Vessels; | |
13 | 14 | |||
14 | ||||
constructor(private vesselsService: VesselsService) { | 15 | 15 | constructor(private vesselsService: VesselsService) { | |
} | 16 | 16 | } | |
17 | 17 | |||
ngOnInit(): void { | 18 | 18 | ngOnInit(): void { | |
this.vesselsService.currentVessels.subscribe(vessels => { | 19 | 19 | this.vesselsService.currentVessels.subscribe(vessels => { | |
this.vessels = vessels; | 20 | 20 | setTimeout(() => | |
21 | this.vessels = vessels | |||
22 | ); | |||
}); | 21 | 23 | }); | |
22 | 24 | |||
$(document).ready(() => { | 23 | 25 | $(document).ready(() => { | |
$('#myInput').on('keyup', function(): void { | 24 | 26 | $('#myInput').on('keyup', function(): void { | |
const value = $(this).val().toLowerCase(); | 25 | 27 | const value = $(this).val().toLowerCase(); | |
$('#list-tab a').filter(function(): void { | 26 | 28 | $('#list-tab a').filter(function(): void { | |
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1); | 27 | 29 | $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1); | |
}); | 28 | 30 | }); | |
}); | 29 | 31 | }); | |
}); | 30 | 32 | }); | |
} | 31 | 33 | } | |
34 | ||||
35 | // ngAfterViewInit(): void { | |||
36 | // this.vesselsService.currentVessels.subscribe(vessels => { | |||
37 | // setTimeout(() => | |||
38 | // this.vessels = vessels | |||
39 | // ); | |||
40 | // }); |
src/app/component/map/map.component.ts
View file @
287033a
import { Component, OnInit } from '@angular/core'; | 1 | 1 | import {Component, OnInit} from '@angular/core'; | |
import * as L from 'leaflet'; | 2 | 2 | import * as L from 'leaflet'; | |
3 | import {CircleMarker} from 'leaflet'; | |||
import {Vessels} from '../../model/vessels'; | 3 | 4 | import {Vessels} from '../../model/vessels'; | |
import {VesselsService} from '../../service/vessels.service'; | 4 | 5 | import {VesselsService} from '../../service/vessels.service'; | |
6 | import {Message} from '../../model/message'; | |||
5 | 7 | |||
@Component({ | 6 | 8 | @Component({ | |
selector: 'app-map', | 7 | 9 | selector: 'app-map', | |
templateUrl: './map.component.html', | 8 | 10 | templateUrl: './map.component.html', | |
styleUrls: ['./map.component.scss'] | 9 | 11 | styleUrls: ['./map.component.scss'] | |
}) | 10 | 12 | }) | |
export class MapComponent implements OnInit { | 11 | 13 | export class MapComponent implements OnInit { | |
vessels: Vessels; | 12 | 14 | vessels: Vessels; | |
15 | public map: L.Map; | |||
16 | circleMarkers: Map<number, CircleMarker> = new Map<number, CircleMarker>(); | |||
13 | 17 | |||
constructor(private vesselsService: VesselsService) { } | 14 | 18 | constructor(private vesselsService: VesselsService) { | |
19 | } | |||
15 | 20 | |||
ngOnInit(): void { | 16 | 21 | ngOnInit(): void { | |
this.connectVesselObservable(); | 17 | |||
this.initMap(); | 18 | 22 | this.initMap(); | |
23 | this.connectVesselObservable(); | |||
} | 19 | 24 | } | |
20 | 25 | |||
connectVesselObservable(): void { | 21 | 26 | connectVesselObservable(): void { | |
this.vesselsService.currentVessels.subscribe(vessels => { | 22 | 27 | this.vesselsService.currentVessels.subscribe(vessels => { | |
this.vessels = vessels; | 23 | 28 | this.vessels = vessels; | |
29 | this.updateMap(); | |||
}); | 24 | 30 | }); | |
} | 25 | 31 | } | |
26 | 32 | |||
initMap(): void { | 27 | 33 | initMap(): void { | |
const myMap = L.map('map').setView([0, 0], 1); | 28 | 34 | this.map = L.map('map', { | |
35 | preferCanvas: true | |||
36 | }).setView([0, 0], 1); | |||
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { | 29 | 37 | L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { | |
attribution: 'map' | 30 | 38 | attribution: 'map', | |
}).addTo(myMap); | 31 | 39 | }).addTo(this.map); | |
40 | } | |||
41 | ||||
42 | addCircleMarker(message: Message, color: string): void { | |||
43 | const circleMarker = L.circleMarker([+message.latitude, +message.longitude], | |||
44 | { | |||
45 | radius: 0.1, | |||
46 | color | |||
47 | }).addTo(this.map); | |||
48 | this.circleMarkers.set(Number(message.mmsi), circleMarker); | |||
49 | } | |||
50 | ||||
51 | updateMap(): void { | |||
52 | let nbMessage = 0; | |||
53 | this.vessels.vessels.forEach(((vessel, key) => { | |||
54 | const color = vessel.getColor(); | |||
55 | vessel.messages.forEach((message) => { | |||
56 | nbMessage++; | |||
57 | this.addCircleMarker(message, color); | |||
58 | }); | |||
59 | })); | |||
} | 32 | 60 | } | |
33 | 61 |
src/app/model/vessel.ts
View file @
287033a
import {Message} from './message'; | 1 | 1 | import {Message} from './message'; | |
2 | 2 | |||
export class Vessel { | 3 | 3 | export class Vessel { | |
messages: Array<Message>; | 4 | 4 | messages: Array<Message>; | |
5 | 5 | |||
constructor(messages: Array<Message>) { | 6 | 6 | constructor(messages: Array<Message>) { | |
this.messages = messages; | 7 | 7 | this.messages = messages; | |
} | 8 | 8 | } | |
9 | 9 | |||
addMessage(message: Message): void { | 10 | 10 | addMessage(message: Message): void { | |
this.messages.push(message); | 11 | 11 | this.messages.push(message); | |
} | 12 | 12 | } | |
13 | 13 | |||
getMMSI(): string { | 14 | 14 | getMMSI(): string { | |
return this.messages[0].mmsi; | 15 | 15 | return this.messages[0].mmsi; | |
} | 16 | 16 | } | |
17 | 17 | |||
getName(): string { | 18 | 18 | getName(): string { | |
return this.messages[0].vesselName; | 19 | 19 | return this.messages[0].vesselName; | |
} | 20 | 20 | } |
src/app/model/vessels.ts
View file @
287033a
import {Vessel} from './vessel'; | 1 | 1 | import {Vessel} from './vessel'; | |
import {Message} from './message'; | 2 | 2 | import {Message} from './message'; | |
3 | import { delay } from 'rxjs/operators'; | |||
3 | 4 | |||
export class Vessels { | 4 | 5 | export class Vessels { | |
vessels: Map<number, Vessel>; | 5 | 6 | vessels: Map<number, Vessel>; | |
6 | 7 | |||
constructor() { | 7 | 8 | constructor() { | |
this.vessels = new Map<number, Vessel>(); | 8 | 9 | this.vessels = new Map<number, Vessel>(); | |
} | 9 | 10 | } | |
10 | 11 | |||
addMessage(message: Message): void { | 11 | 12 | addMessage(message: Message): void { | |
if (!this.vessels.get(Number(message.mmsi))) { | 12 | 13 | if (!this.vessels.get(Number(message.mmsi))) { | |
this.vessels.set(Number(message.mmsi), new Vessel(new Array<Message>())); | 13 | 14 | this.vessels.set(Number(message.mmsi), new Vessel(new Array<Message>())); | |
} | 14 | 15 | } |