diff --git a/package-lock.json b/package-lock.json
index bc55c27..7d7b150 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1887,9 +1887,8 @@
}
},
"@inst-iot/bosch-angular-ui-components": {
- "version": "0.6.0",
- "resolved": "https://rb-artifactory.bosch.com:443/artifactory/api/npm/iot-insights-release-local/@inst-iot/bosch-angular-ui-components/-/@inst-iot/bosch-angular-ui-components-0.6.0.tgz",
- "integrity": "sha1-+yjXwe/qCeBHYL+WoG7mOarPXIQ=",
+ "version": "file:../Bosch-UI-Components/bosch-angular-ui-components/dist-lib/inst-iot-bosch-angular-ui-components-0.6.0.tgz",
+ "integrity": "sha512-A4nKOvpdKzq+GWSZlL7U511Ii1vdSA905Q0tru7jAzpBzjRaYqCTiCvsAjRDLM+gVPpzgZ8HpMYfNfhMoNlG/w==",
"requires": {
"tslib": "^1.10.0"
}
@@ -2002,6 +2001,14 @@
}
}
},
+ "@types/chart.js": {
+ "version": "2.9.22",
+ "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.22.tgz",
+ "integrity": "sha512-CneMxwh2T5fyMpXE5fuprTTmFtlLyZUFq1A3laUrCgOblDzupgiohrFg3jjsTIrqRI5K4qLZdrLN4zT9/MY5Dw==",
+ "requires": {
+ "moment": "^2.10.2"
+ }
+ },
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -3355,6 +3362,37 @@
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
+ "chart.js": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz",
+ "integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==",
+ "requires": {
+ "chartjs-color": "^2.1.0",
+ "moment": "^2.10.2"
+ }
+ },
+ "chartjs-color": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
+ "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
+ "requires": {
+ "chartjs-color-string": "^0.6.0",
+ "color-convert": "^1.9.3"
+ }
+ },
+ "chartjs-color-string": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
+ "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
+ "requires": {
+ "color-name": "^1.0.0"
+ }
+ },
+ "chartjs-plugin-datalabels": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-0.7.0.tgz",
+ "integrity": "sha512-PKVUX14nYhH0wcdCpgOoC39Gbzvn6cZ7O9n+bwc02yKD9FTnJ7/TSrBcfebmolFZp1Rcicr9xbT0a5HUbigS7g=="
+ },
"chokidar": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
@@ -3588,7 +3626,6 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
"requires": {
"color-name": "1.1.3"
}
@@ -3596,8 +3633,7 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.3",
@@ -8063,6 +8099,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
+ "lodash-es": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
+ "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
+ },
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
@@ -8658,6 +8699,11 @@
"minimist": "^1.2.5"
}
},
+ "moment": {
+ "version": "2.27.0",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
+ "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
+ },
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -8738,6 +8784,16 @@
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
"dev": true
},
+ "ng2-charts": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-2.3.2.tgz",
+ "integrity": "sha512-T0rPivwZITKtEtFRVodRCO+kIczWIP6V4YLZvf6Kg1jqc8jYGZ37H5ywT0Q7N0Rt5dJGhC5z1/38nWFBVFx5iw==",
+ "requires": {
+ "@types/chart.js": "^2.7.48",
+ "lodash-es": "^4.17.11",
+ "tslib": "^1.9.0"
+ }
+ },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
diff --git a/package.json b/package.json
index b188818..9941ad5 100644
--- a/package.json
+++ b/package.json
@@ -23,10 +23,13 @@
"@angular/platform-browser-dynamic": "~9.1.7",
"@angular/router": "~9.1.7",
"@hapi/joi": "^17.1.1",
- "@inst-iot/bosch-angular-ui-components": "^0.6.0",
+ "@inst-iot/bosch-angular-ui-components": "file:../Bosch-UI-Components/bosch-angular-ui-components/dist-lib/inst-iot-bosch-angular-ui-components-0.6.0.tgz",
"angular-2-local-storage": "^3.0.2",
+ "chart.js": "^2.9.3",
+ "chartjs-plugin-datalabels": "^0.7.0",
"flatpickr": "^4.6.3",
"lodash": "^4.17.15",
+ "ng2-charts": "^2.3.2",
"quick-score": "0.0.8",
"rxjs": "~6.5.5",
"tslib": "^1.10.0",
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 0546de3..405c832 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -4,19 +4,21 @@
Samples
-
-
-
+
+
DEVELOPMENTDigital Fingerprint of Plastics
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 8b6391c..fc074c0 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,5 +1,6 @@
import { Component, isDevMode} from '@angular/core';
import {LoginService} from './services/login.service';
+import {Router} from '@angular/router';
// TODO: add multiple samples at once
// TODO: guess properties from material name
@@ -16,11 +17,17 @@ import {LoginService} from './services/login.service';
export class AppComponent {
constructor(
- public loginService: LoginService
+ public loginService: LoginService,
+ private router: Router
) {
}
get devMode() {
return isDevMode();
}
+
+ logout() {
+ this.loginService.logout();
+ this.router.navigate(['/']);
+ }
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 60c0738..663e8e9 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -1,5 +1,6 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
+import { ChartsModule } from 'ng2-charts';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@@ -16,6 +17,7 @@ import { ValidateDirective } from './validate.directive';
import {CommonModule} from '@angular/common';
import { ErrorComponent } from './error/error.component';
import { ObjectPipe } from './object.pipe';
+import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@NgModule({
declarations: [
@@ -34,6 +36,7 @@ import { ObjectPipe } from './object.pipe';
storageType: 'localStorage'
}),
BrowserModule,
+ BrowserAnimationsModule,
AppRoutingModule,
RbUiComponentsModule,
FormsModule,
@@ -41,7 +44,8 @@ import { ObjectPipe } from './object.pipe';
RbTableModule,
ReactiveFormsModule,
FormFieldsModule,
- CommonModule
+ CommonModule,
+ ChartsModule
],
providers: [
ModalService
diff --git a/src/app/login/login.component.ts b/src/app/login/login.component.ts
index 765d641..6c28dcc 100644
--- a/src/app/login/login.component.ts
+++ b/src/app/login/login.component.ts
@@ -29,7 +29,7 @@ export class LoginComponent implements OnInit {
login() {
this.loginService.login(this.username, this.password).then(ok => {
if (ok) {
- this.message = 'Login successful'; // TODO: think about following action
+ this.message = 'Login successful';
this.router.navigate(['/samples']);
}
else {
diff --git a/src/app/sample/sample.component.html b/src/app/sample/sample.component.html
index 1274b1b..138e0e9 100644
--- a/src/app/sample/sample.component.html
+++ b/src/app/sample/sample.component.html
@@ -6,14 +6,14 @@
-
+
Cannot be empty
Unknown material, add properties for new material
-
+
Material properties
{{supplierInput.errors.failure}}
@@ -38,7 +38,7 @@
-
+
@@ -69,7 +69,7 @@
{{commentInput.errors.failure}}
Additional properties
-
+
{{keyInput.errors.failure}}
@@ -89,7 +89,7 @@
Condition
-
+
@@ -105,8 +105,8 @@
Measurements
-
-
+
+
@@ -115,9 +115,16 @@
{{parameterInput.errors.failure}}
Cannot be empty
-
+
Cannot be empty
+
@@ -130,7 +137,6 @@
-
diff --git a/src/app/sample/sample.component.scss b/src/app/sample/sample.component.scss
index c65b876..8b4e416 100644
--- a/src/app/sample/sample.component.scss
+++ b/src/app/sample/sample.component.scss
@@ -15,3 +15,7 @@ td:first-child {
grid-template-columns: 1fr 1fr;
grid-column-gap: 10px;
}
+
+.dpt-chart {
+ max-width: 400px;
+}
diff --git a/src/app/sample/sample.component.ts b/src/app/sample/sample.component.ts
index 96d57c3..ba13d26 100644
--- a/src/app/sample/sample.component.ts
+++ b/src/app/sample/sample.component.ts
@@ -14,20 +14,35 @@ import {NgForm, Validators} from '@angular/forms';
import {ValidationService} from '../services/validation.service';
import {TemplateModel} from '../models/template.model';
import {MeasurementModel} from '../models/measurement.model';
+import { ChartOptions } from 'chart.js';
+import {animate, style, transition, trigger} from '@angular/animations';
// TODO: tests
// TODO: confirmation for new group/supplier
-// TODO: DPT preview
// TODO: work on better recognition for file input
// TODO: only show condition (if not set) and measurements in edit sample dialog at first
-// TODO: multiple spectra, drag and drop
+// TODO: multiple spectra
// TODO: multiple samples for base data, extend multiple measurements, conditions
@Component({
selector: 'app-sample',
templateUrl: './sample.component.html',
- styleUrls: ['./sample.component.scss']
+ styleUrls: ['./sample.component.scss'],
+ animations: [
+ trigger(
+ 'inOut', [
+ transition(':enter', [
+ style({height: 0, opacity: 0}),
+ animate('0.5s ease-out', style({height: '*', opacity: 1}))
+ ]),
+ transition(':leave', [
+ style({height: '*', opacity: 1}),
+ animate('0.5s ease-in', style({height: 0, opacity: 0}))
+ ])
+ ]
+ )
+ ]
})
export class SampleComponent implements OnInit, AfterContentChecked {
@@ -49,6 +64,27 @@ export class SampleComponent implements OnInit, AfterContentChecked {
measurementTemplates: TemplateModel[];
loading = 0; // number of currently loading instances
checkFormAfterInit = false;
+ charts = []; // chart data for spectrums
+ readonly chartInit = [{
+ data: [],
+ label: 'Spectrum',
+ showLine: true,
+ fill: false,
+ pointRadius: 0,
+ borderColor: '#00a8b0',
+ borderWidth: 2
+ }];
+ readonly chartOptions: ChartOptions = {
+ scales: {
+ xAxes: [{ticks: {min: 400, max: 4000, stepSize: 400, reverse: true}}],
+ yAxes: [{ticks: {min: 0, max: 1}}]
+ },
+ responsive: true,
+ tooltips: {enabled: false},
+ hover: {mode: null},
+ maintainAspectRatio: true,
+ plugins: {datalabels: {display: false}}
+ };
constructor(
private router: Router,
@@ -90,6 +126,19 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.loading++;
this.api.get
('/sample/' + this.route.snapshot.paramMap.get('id'), sData => {
this.sample.deserialize(sData);
+ this.charts = [];
+ const spectrumTemplate = this.measurementTemplates.find(e => e.name === 'spectrum')._id;
+ let spectrumCounter = 0;
+ this.sample.measurements.forEach((measurement, i) => {
+ this.charts.push(_.cloneDeep(this.chartInit));
+ if (measurement.measurement_template === spectrumTemplate) {
+ setTimeout(() => {
+ this.generateChart(measurement.values.dpt, i);
+ console.log(this.charts);
+ }, spectrumCounter * 20);
+ spectrumCounter ++;
+ }
+ });
this.material = sData.material;
this.customFields = this.sample.notes.custom_fields && this.sample.notes.custom_fields !== {} ? Object.keys(this.sample.notes.custom_fields).map(e => [e, this.sample.notes.custom_fields[e]]) : [['', '']];
if ('condition_template' in this.sample.condition) {
@@ -225,8 +274,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.setNewMaterial();
}
- preventSubmit(event) {
- if (event.key === 'Enter') {
+ preventDefault(event) {
+ if (event.key && event.key === 'Enter' || event.type === 'dragover') {
event.preventDefault();
}
}
@@ -285,6 +334,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
addMeasurement() {
this.sample.measurements.push(new MeasurementModel(this.measurementTemplates[0]._id));
+ this.charts.push(_.cloneDeep(this.chartInit));
}
removeMeasurement(index) {
@@ -292,14 +342,24 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.api.delete('/measurement/' + this.sample.measurements[index]._id);
}
this.sample.measurements.splice(index, 1);
+ this.charts.splice(index, 1);
}
- fileToArray(event, mIndex, parameter) {
+ clearChart(index) {
+ this.charts[index][0].data = [];
+ }
+
+ fileToArray(files, mIndex, parameter) {
const fileReader = new FileReader();
fileReader.onload = () => {
this.sample.measurements[mIndex].values[parameter] = fileReader.result.toString().split('\r\n').map(e => e.split(','));
+ this.generateChart(this.sample.measurements[mIndex].values[parameter], mIndex);
};
- fileReader.readAsText(event.target.files[0]);
+ fileReader.readAsText(files[0]);
+ }
+
+ generateChart(spectrum, index) {
+ this.charts[index][0].data = spectrum.map(e => ({x: parseFloat(e[0]), y: parseFloat(e[1])}));
}
toggleCondition() {
diff --git a/src/app/samples/samples.component.html b/src/app/samples/samples.component.html
index ee76318..9aae131 100644
--- a/src/app/samples/samples.component.html
+++ b/src/app/samples/samples.component.html
@@ -45,7 +45,7 @@
-
+
@@ -54,11 +54,6 @@
-
-
-
-
-
@@ -91,8 +86,6 @@
diff --git a/src/app/samples/samples.component.scss b/src/app/samples/samples.component.scss
index 0641a55..9b4a2f6 100644
--- a/src/app/samples/samples.component.scss
+++ b/src/app/samples/samples.component.scss
@@ -169,3 +169,8 @@ textarea.linkmodal {
min-height: 200px;
border: none;
}
+
+.filter-inputs > * {
+ display: inline-block;
+ max-width: 250px;
+}
diff --git a/src/app/services/login.service.ts b/src/app/services/login.service.ts
index 5cc336f..088792a 100644
--- a/src/app/services/login.service.ts
+++ b/src/app/services/login.service.ts
@@ -42,6 +42,11 @@ export class LoginService implements CanActivate {
});
}
+ logout() {
+ this.storage.remove('basicAuth');
+ this.loggedIn = false;
+ }
+
canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable {
return new Observable(observer => {
if (this.loggedIn === undefined) {
@@ -60,4 +65,8 @@ export class LoginService implements CanActivate {
get isLoggedIn() {
return this.loggedIn;
}
+
+ get username() {
+ return atob(this.storage.get('basicAuth')).split(':')[0];
+ }
}
|