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 | } |