Skip to content
Snippets Groups Projects
Commit 4e690bc2 authored by Oleksandr Husak's avatar Oleksandr Husak
Browse files

gantt chart for objects, zones vs. time

parent 061803a0
No related branches found
No related tags found
No related merge requests found
Showing
with 499 additions and 32 deletions
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
- new positions - new positions
- ```json - ```json
{ {
"object": [ "objects": [
{ {
"id": "Employee1", "id": "Employee1",
"sensorId": "UWB_1", "sensorId": "UWB_1",
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
"position": { "position": {
"refSystemId": "ROOT", "refSystemId": "ROOT",
"point": { "point": {
"x": 13, "x": 3,
"y": 22, "y": 2,
"z": 3 "z": 3
}, },
"accuracy": 1 "accuracy": 1
...@@ -40,7 +40,13 @@ ...@@ -40,7 +40,13 @@
"z": 1, "z": 1,
"w": 1.5 "w": 1.5
}, },
"lastPosUpdate": "2021-09-14T09:41:20+00:00" "lastPosUpdate": "2021-09-14T09:41:20+00:00",
"zoneDescriptors": [
{
"zoneId": "door_zone",
"notificationType": "EntryNotification"
}
]
} }
], ],
"type": "EntryNotification" "type": "EntryNotification"
......
...@@ -38,7 +38,9 @@ ...@@ -38,7 +38,9 @@
"src/styles.scss", "src/styles.scss",
"./node_modules/leaflet/dist/leaflet.css" "./node_modules/leaflet/dist/leaflet.css"
], ],
"scripts": [] "scripts": [
"node_modules/apexcharts/dist/apexcharts.min.js"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
...@@ -107,7 +109,9 @@ ...@@ -107,7 +109,9 @@
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss" "src/styles.scss"
], ],
"scripts": [] "scripts": [
"node_modules/apexcharts/dist/apexcharts.min.js"
]
} }
} }
} }
......
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
"@angular/platform-browser-dynamic": "~12.2.0", "@angular/platform-browser-dynamic": "~12.2.0",
"@angular/router": "~12.2.0", "@angular/router": "~12.2.0",
"@asymmetrik/ngx-leaflet": "^8.1.0", "@asymmetrik/ngx-leaflet": "^8.1.0",
"apexcharts": "^3.29.0",
"leaflet": "^1.7.1", "leaflet": "^1.7.1",
"moment": "^2.24.0",
"ng-apexcharts": "^1.5.12",
"ngx-mqtt": "^9.0.5", "ngx-mqtt": "^9.0.5",
"rxjs": "~6.6.0", "rxjs": "~6.6.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
...@@ -3002,6 +3005,19 @@ ...@@ -3002,6 +3005,19 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/apexcharts": {
"version": "3.29.0",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.29.0.tgz",
"integrity": "sha512-PhI17VayidYAbLb5/g+7WOeirgFrVopzt0qGwLq8V+cd6NXx4CeHYq3S0pDZiUGO7UFQ4YIrT8+ie9/Fnler+w==",
"dependencies": {
"svg.draggable.js": "^2.2.2",
"svg.easing.js": "^2.0.0",
"svg.filter.js": "^2.0.2",
"svg.pathmorphing.js": "^0.1.3",
"svg.resize.js": "^1.4.3",
"svg.select.js": "^3.0.1"
}
},
"node_modules/aproba": { "node_modules/aproba": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
...@@ -9419,6 +9435,14 @@ ...@@ -9419,6 +9435,14 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
"engines": {
"node": "*"
}
},
"node_modules/mqtt": { "node_modules/mqtt": {
"version": "4.2.6", "version": "4.2.6",
"resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.2.6.tgz", "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.2.6.tgz",
...@@ -9585,6 +9609,25 @@ ...@@ -9585,6 +9609,25 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true "dev": true
}, },
"node_modules/ng-apexcharts": {
"version": "1.5.12",
"resolved": "https://registry.npmjs.org/ng-apexcharts/-/ng-apexcharts-1.5.12.tgz",
"integrity": "sha512-k82AdWNbZs5yqGCjiX7PGS11Cy1+1Oo/RGt2lT89xReD9N9Vvo1t34p1dmzS+U6W5wOFlLEKKVLGNQqENW8cTQ==",
"dependencies": {
"tslib": "^1.10.0"
},
"peerDependencies": {
"@angular/common": ">=9.0.0 <13.0.0",
"@angular/core": ">=9.0.0 <13.0.0",
"apexcharts": "^3.19.2",
"rxjs": "^6.5.5"
}
},
"node_modules/ng-apexcharts/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/ngx-mqtt": { "node_modules/ngx-mqtt": {
"version": "9.0.5", "version": "9.0.5",
"resolved": "https://registry.npmjs.org/ngx-mqtt/-/ngx-mqtt-9.0.5.tgz", "resolved": "https://registry.npmjs.org/ngx-mqtt/-/ngx-mqtt-9.0.5.tgz",
...@@ -14402,6 +14445,89 @@ ...@@ -14402,6 +14445,89 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"dependencies": {
"svg.js": "^2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.easing.js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=",
"dependencies": {
"svg.js": ">=2.3.x"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.filter.js": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
},
"node_modules/svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"dependencies": {
"svg.js": "^2.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"dependencies": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js/node_modules/svg.select.js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.select.js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"dependencies": {
"svg.js": "^2.6.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svgo": { "node_modules/svgo": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.7.0.tgz", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.7.0.tgz",
...@@ -18525,6 +18651,19 @@ ...@@ -18525,6 +18651,19 @@
"picomatch": "^2.0.4" "picomatch": "^2.0.4"
} }
}, },
"apexcharts": {
"version": "3.29.0",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.29.0.tgz",
"integrity": "sha512-PhI17VayidYAbLb5/g+7WOeirgFrVopzt0qGwLq8V+cd6NXx4CeHYq3S0pDZiUGO7UFQ4YIrT8+ie9/Fnler+w==",
"requires": {
"svg.draggable.js": "^2.2.2",
"svg.easing.js": "^2.0.0",
"svg.filter.js": "^2.0.2",
"svg.pathmorphing.js": "^0.1.3",
"svg.resize.js": "^1.4.3",
"svg.select.js": "^3.0.1"
}
},
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
...@@ -23508,6 +23647,11 @@ ...@@ -23508,6 +23647,11 @@
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true "dev": true
}, },
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"mqtt": { "mqtt": {
"version": "4.2.6", "version": "4.2.6",
"resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.2.6.tgz", "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.2.6.tgz",
...@@ -23647,6 +23791,21 @@ ...@@ -23647,6 +23791,21 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true "dev": true
}, },
"ng-apexcharts": {
"version": "1.5.12",
"resolved": "https://registry.npmjs.org/ng-apexcharts/-/ng-apexcharts-1.5.12.tgz",
"integrity": "sha512-k82AdWNbZs5yqGCjiX7PGS11Cy1+1Oo/RGt2lT89xReD9N9Vvo1t34p1dmzS+U6W5wOFlLEKKVLGNQqENW8cTQ==",
"requires": {
"tslib": "^1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"ngx-mqtt": { "ngx-mqtt": {
"version": "9.0.5", "version": "9.0.5",
"resolved": "https://registry.npmjs.org/ngx-mqtt/-/ngx-mqtt-9.0.5.tgz", "resolved": "https://registry.npmjs.org/ngx-mqtt/-/ngx-mqtt-9.0.5.tgz",
...@@ -27259,6 +27418,70 @@ ...@@ -27259,6 +27418,70 @@
"has-flag": "^3.0.0" "has-flag": "^3.0.0"
} }
}, },
"svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"requires": {
"svg.js": "^2.0.1"
}
},
"svg.easing.js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=",
"requires": {
"svg.js": ">=2.3.x"
}
},
"svg.filter.js": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=",
"requires": {
"svg.js": "^2.2.5"
}
},
"svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
},
"svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"requires": {
"svg.js": "^2.4.0"
}
},
"svg.resize.js": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"requires": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
},
"dependencies": {
"svg.select.js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"requires": {
"svg.js": "^2.2.5"
}
}
}
},
"svg.select.js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"requires": {
"svg.js": "^2.6.5"
}
},
"svgo": { "svgo": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.7.0.tgz", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.7.0.tgz",
<div class="wrapper">
<h1>Consumer</h1>
</div>
<app-map class="wrapper"></app-map> <app-map class="wrapper"></app-map>
<chart-timeline></chart-timeline>
\ No newline at end of file
@import './src/variables.scss';
.wrapper {
padding: 0 calc((100% - #{$break-large})/2);
}
\ No newline at end of file
...@@ -4,11 +4,13 @@ import { BrowserModule } from '@angular/platform-browser'; ...@@ -4,11 +4,13 @@ import { BrowserModule } from '@angular/platform-browser';
// --- Map // --- Map
import { LeafletModule } from '@asymmetrik/ngx-leaflet'; import { LeafletModule } from '@asymmetrik/ngx-leaflet';
// --- Charts
import { NgApexchartsModule } from 'ng-apexcharts';
// --- MQTT // --- MQTT
import { MqttModule } from 'ngx-mqtt'; import { MqttModule } from 'ngx-mqtt';
import { MQTTconfig } from './../environments/environment'; import { MQTTconfig } from './../environments/environment';
// --- WS // --- WS
// import * as SockJS from 'sockjs-client'; // import * as SockJS from 'sockjs-client';
...@@ -25,13 +27,16 @@ import { AppComponent } from './app.component'; ...@@ -25,13 +27,16 @@ import { AppComponent } from './app.component';
import { MapComponent } from './components/map/map.component'; import { MapComponent } from './components/map/map.component';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ChartTimelineComponent } from './components/chart-timeline/chart-timeline.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
MapComponent MapComponent,
ChartTimelineComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
...@@ -40,7 +45,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; ...@@ -40,7 +45,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
CoreModule, CoreModule,
LeafletModule, LeafletModule,
BrowserAnimationsModule, BrowserAnimationsModule,
MqttModule.forRoot(MQTTconfig) MqttModule.forRoot(MQTTconfig),
NgApexchartsModule
], ],
providers: [ApiService], providers: [ApiService],
bootstrap: [AppComponent] bootstrap: [AppComponent]
......
<div id="chart" class="wrapper">
<apx-chart
[series]="chartOptions.series"
[chart]="chartOptions.chart"
[dataLabels]="chartOptions.dataLabels"
[plotOptions]="chartOptions.plotOptions"
[xaxis]="chartOptions.xaxis"
[legend]="chartOptions.legend"
></apx-chart>
</div>
#chart {
margin: 35px auto;
}
apx-chart {
height: 300px;
}
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChartTimelineComponent } from './chart-timeline.component';
describe('ChartTimelineComponent', () => {
let component: ChartTimelineComponent;
let fixture: ComponentFixture<ChartTimelineComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ChartTimelineComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ChartTimelineComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, ViewChild } from '@angular/core';
// --- MQTT
import { Subscription } from 'rxjs';
import { IMqttMessage, MqttService } from 'ngx-mqtt';
// --- Chart
import * as moment from "moment";
import {
ApexAxisChartSeries,
ApexChart,
ApexDataLabels,
ApexLegend,
ApexPlotOptions,
ApexXAxis,
ChartComponent
} from 'ng-apexcharts';
import { MarkerColorMap } from 'src/environments/environment';
import {Object, PositionUpdate} from 'src/app/model/base-model';
export type ChartOptions = {
series: ApexAxisChartSeries;
chart: ApexChart;
dataLabels: ApexDataLabels;
legend: ApexLegend;
xaxis: ApexXAxis;
plotOptions: ApexPlotOptions;
};
@Component({
selector: 'chart-timeline',
templateUrl: './chart-timeline.component.html',
styleUrls: ['./chart-timeline.component.scss']
})
export class ChartTimelineComponent implements OnInit {
@ViewChild("chart", { static: false }) chart!: ChartComponent;
private subsPosition: Subscription;
public chartOptions: Partial<ChartOptions> | any;
// public series: ApexAxisChartSeries;
public seriesData: ApexAxisChartSeries;
constructor(private _mqttService: MqttService) {
this.seriesData = [
{
name: "Bob",
data: [
{
x: "Design",
y: [
new Date("2021-09-14T09:41:20+00:00").getTime(),
new Date("2021-09-14T09:51:20+00:00").getTime()
]
},
{
x: "Code",
y: [
new Date("2021-09-14T09:52:20+00:00").getTime(),
new Date("2021-09-14T09:54:20+00:00").getTime()
]
},
{
x: "Test",
y: [
new Date("2021-09-14T10:21:20+00:00").getTime(),
new Date("2021-09-14T10:31:20+00:00").getTime()
]
}
]
},
{
name: "Joe",
data: [
{
x: "Design",
y: [
new Date("2021-09-14T09:11:20+00:00").getTime(),
new Date("2021-09-14T09:21:20+00:00").getTime()
]
},
{
x: "Code",
y: [
new Date("2021-09-14T09:11:20+00:00").getTime(),
new Date("2021-09-14T09:41:20+00:00").getTime()
]
},
{
x: "Test",
y: [
new Date("2021-09-14T11:31:20+00:00").getTime(),
new Date("2021-09-14T11:41:20+00:00").getTime()
]
}
]
}
],
this.chartOptions = {
series: [],
chart: {
height: 350,
type: "rangeBar"
},
plotOptions: {
bar: {
horizontal: true
}
},
dataLabels: {
enabled: true,
formatter: function(val: any) {
var a = moment(val[0]);
var b = moment(val[1]);
var diff = b.diff(a, "minutes");
return diff + "min";
}
},
xaxis: {
type: "datetime"
},
legend: {
position: "top"
}
};
this.subsPosition = this._mqttService.observe('ipos/client/position').subscribe((message: IMqttMessage) => {
let upd: PositionUpdate = JSON.parse(message.payload.toString())
upd.objects.forEach(obj => this.addNewSeries(obj))
});
}
ngOnInit(): void {
}
addNewSeries(obj: Object) {
let name = obj.id
let idx = this.chartOptions.series.findIndex((s: { name: string; }) => s.name === name)
if (idx == -1) {
idx = this.chartOptions.series.push({"name": name, "data": []})
idx = idx - 1
}
// --- Marker
if (name in MarkerColorMap) {
var markerConf = MarkerColorMap[name]
this.chartOptions.series[idx]["color"] = markerConf?.circle
}
// --- Colect new data
let dataPatch: any[] = obj.zoneDescriptors.map(zone => {
return {
"x": zone.zoneId,
"y": [
new Date(obj.lastPosUpdate).getTime(),
new Date(obj.lastPosUpdate).getTime() + 360000
],
"fillColor": markerConf?.circle,
"strokeColor": markerConf?.circle
}
});
// --- Add it
this.chartOptions.series[idx]["data"] = dataPatch.concat(this.chartOptions.series[idx]["data"])
this.chartOptions.series = this.chartOptions.series.map((s: any) => Object.assign({}, s));
}
public ngOnDestroy() {
this.subsPosition.unsubscribe();
}
}
<div style="height: 80vh;" <div class="map"
leaflet leaflet
[leafletOptions]="options" [leafletOptions]="options"
(leafletMapReady)="onMapReady($event)"> (leafletMapReady)="onMapReady($event)">
......
.map { .map {
margin-bottom: 20px; margin-bottom: 20px;
height: 70vh height: 60vh
} }
table { table {
......
...@@ -16,7 +16,7 @@ import {Position, PositionUpdate, RelativePos, WGS84} from 'src/app/model/base-m ...@@ -16,7 +16,7 @@ import {Position, PositionUpdate, RelativePos, WGS84} from 'src/app/model/base-m
export class MapComponent implements OnInit { export class MapComponent implements OnInit {
private subsPosition: Subscription; private subsPosition: Subscription;
private subsOrigin: Subscription; private subsRoot: Subscription;
private map!: L.Map; private map!: L.Map;
private root!: Position; private root!: Position;
...@@ -28,15 +28,15 @@ export class MapComponent implements OnInit { ...@@ -28,15 +28,15 @@ export class MapComponent implements OnInit {
constructor(private _mqttService: MqttService) { constructor(private _mqttService: MqttService) {
this.root = {"refSystemId": "ROOT", "point": {"latitude": 51.02545, "longitude": 13.72295}} this.root = {"refSystemId": "ROOT", "point": {"latitude": 51.02545, "longitude": 13.72295}}
this.subsPosition = this._mqttService.observe('ipos/client/root').subscribe((message: IMqttMessage) => { this.subsRoot = this._mqttService.observe('ipos/client/root').subscribe((message: IMqttMessage) => {
this.root = JSON.parse(message.payload.toString()) this.root = JSON.parse(message.payload.toString())
console.log("New root: ", this.root) console.log("New root: ", this.root)
this.registerPoint("ROOT", {"position": this.root}) this.registerPoint("ROOT", {"position": this.root})
}); });
this.subsOrigin = this._mqttService.observe('ipos/client/position').subscribe((message: IMqttMessage) => { this.subsPosition = this._mqttService.observe('ipos/client/position').subscribe((message: IMqttMessage) => {
let upd: PositionUpdate = JSON.parse(message.payload.toString()) let upd: PositionUpdate = JSON.parse(message.payload.toString())
upd.object.forEach(obj => this.registerPoint(obj.id, obj)); upd.objects.forEach(obj => this.registerPoint(obj.id, obj));
}); });
} }
...@@ -173,7 +173,7 @@ export class MapComponent implements OnInit { ...@@ -173,7 +173,7 @@ export class MapComponent implements OnInit {
public ngOnDestroy() { public ngOnDestroy() {
this.subsPosition.unsubscribe(); this.subsPosition.unsubscribe();
this.subsOrigin.unsubscribe(); this.subsRoot.unsubscribe();
} }
} }
export interface PositionUpdate { export interface PositionUpdate {
object: Object[] objects: Object[]
type: NotificationType type: NotificationType
} }
...@@ -12,6 +12,7 @@ export interface Object { ...@@ -12,6 +12,7 @@ export interface Object {
position: Position position: Position
orientation?: Orientation orientation?: Orientation
lastPosUpdate: string lastPosUpdate: string
zoneDescriptors: ZoneDesc[]
} }
export interface Position { export interface Position {
...@@ -32,6 +33,11 @@ export interface RelativePos { ...@@ -32,6 +33,11 @@ export interface RelativePos {
z?: number z?: number
} }
interface ZoneDesc {
zoneId: string
notificationType: NotificationType
}
interface Orientation { interface Orientation {
x: number x: number
y: number y: number
......
...@@ -16,9 +16,9 @@ app-root { ...@@ -16,9 +16,9 @@ app-root {
min-height: 100vh; min-height: 100vh;
} }
html, body { height: 100%; } .wrapper {
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } padding: 0 calc((100% - #{$break-large})/2);
}
/*Legend specific*/ /*Legend specific*/
.legend { .legend {
......
...@@ -15,4 +15,4 @@ $divider-color: #BDBDBD; ...@@ -15,4 +15,4 @@ $divider-color: #BDBDBD;
$break-small: 380px; $break-small: 380px;
$break-large: 1100px; $break-large: 1200px;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment