Compare commits
No commits in common. "471a85a4286293e6496b6da2e30d47e67785a55d" and "4a64a702e81598202f2e027c9af1f26a5551c48c" have entirely different histories.
471a85a428
...
4a64a702e8
@ -23,7 +23,7 @@ docker run -t -i --entrypoint /bin/bash -p 4200:4200 node:10.16.0
|
|||||||
Inside the running container
|
Inside the running container
|
||||||
```
|
```
|
||||||
git clone https://git.akkerweb.nl/FarmMaps/FarmMapsLib.git
|
git clone https://git.akkerweb.nl/FarmMaps/FarmMapsLib.git
|
||||||
cd FarmMapsLib
|
cd FarmMapslib
|
||||||
npm config set @farmmaps:registry https://repository.akkerweb.nl/repository/npm-group/
|
npm config set @farmmaps:registry https://repository.akkerweb.nl/repository/npm-group/
|
||||||
npm install -g @angular/cli
|
npm install -g @angular/cli
|
||||||
npm install
|
npm install
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
.head {
|
||||||
|
color: grey;
|
||||||
|
font-weight: bold;
|
||||||
|
/*border-bottom:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateformat {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
<div class="widget">
|
||||||
|
<div class="d-flex flex-column justify-content-center w-100 h-100">
|
||||||
|
<div class="head h-20 p-1" i18n>Bofek Bodem {{ feature?.bodem }}</div>
|
||||||
|
<div class="body d-flex flex-column h-100 w-100">
|
||||||
|
<small i18n>Periode:{{ feature?.periode }}</small>
|
||||||
|
<small i18n>dmgdry/dmgwet:{{ feature?.dmgdry | number:'0.1-2'}}/{{ feature?.dmgwet | number:'0.1-2'}}</small>
|
||||||
|
<small i18n>dmgind:{{ feature?.dmgind | number:'0.1-2'}}</small>
|
||||||
|
<small i18n>gewas:{{ feature?.gewas}}</small>
|
||||||
|
<small i18n>glg/ghg:{{ feature?.glg}}/{{ feature?.ghg}}</small>
|
||||||
|
<small i18n>station:{{ feature?.station}}</small>
|
||||||
|
<small i18n>hrvpotbio:{{ feature?.hrvpotbio}}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,42 @@
|
|||||||
|
import { Component, OnInit, Injectable } from '@angular/core';
|
||||||
|
import { Input } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import * as mapReducers from '../../reducers/map.reducer';
|
||||||
|
import { commonReducers, ItemTypeService, ItemService, IListItem } from '@farmmaps/common';
|
||||||
|
import { AbstractItemListItemComponent } from '../item-list-item/item-list-item.component'
|
||||||
|
import { ForItemType } from '../for-item/for-itemtype.decorator';
|
||||||
|
import { ForSourceTask } from '../for-item/for-sourcetask.decorator';
|
||||||
|
|
||||||
|
@ForItemType("vnd.farmmaps.itemtype.shape.processed")
|
||||||
|
@ForSourceTask("vnd.farmmaps.task.bofek")
|
||||||
|
@Injectable()
|
||||||
|
@Component({
|
||||||
|
selector: 'fm-map-item-list-item-bofek',
|
||||||
|
templateUrl: './item-list-item-bofek.component.html',
|
||||||
|
styleUrls: ['./item-list-item-bofek.component.css']
|
||||||
|
})
|
||||||
|
export class ItemListItemBofekComponent extends AbstractItemListItemComponent implements OnInit {
|
||||||
|
@Input() item: IListItem;
|
||||||
|
feature;
|
||||||
|
|
||||||
|
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, private itemService$: ItemService) {
|
||||||
|
super(store, itemTypeService);
|
||||||
|
}
|
||||||
|
ngOnInit() {
|
||||||
|
this.itemService$.getItem(this.item.code).subscribe(i => {
|
||||||
|
this.itemService$.getChildItemList(i.parentCode, "vnd.farmmaps.itemtype.trijntje").subscribe(t => {
|
||||||
|
if (t.length > 0) {
|
||||||
|
var data = t[0].data;
|
||||||
|
var bofekId = data["wwl-yieldloss-data"]["feature-with-largest-area"];
|
||||||
|
var features = data["wwl-yieldloss-data"]["features"];
|
||||||
|
for (var i = 0; i < features.length; i++) {
|
||||||
|
if (features[i]["bodem"] == bofekId) {
|
||||||
|
this.feature = features[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
.head {
|
||||||
|
color: grey;
|
||||||
|
font-weight: bold;
|
||||||
|
/*border-bottom:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mean {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 7.5rem;
|
||||||
|
color: deeppink;
|
||||||
|
/*border-right:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.min {
|
||||||
|
/*border-bottom:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.min, .max {
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 3.48rem;
|
||||||
|
color: gray;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
color: gray;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<div *ngIf="(selectedItem|async) as selectedItem; else noData">
|
||||||
|
|
||||||
|
<div *ngIf="selectedItem.data.layers[0].renderer.band.histogram;let histogram">
|
||||||
|
<div class="widget">
|
||||||
|
<div class="d-flex flex-column justify-content-center w-100 h-100">
|
||||||
|
<div class="head h-20 p-1">Height</div>
|
||||||
|
<div class="body d-flex flex-row h-100 w-100">
|
||||||
|
<div *ngIf="histogram.mean; else noMeanPresent">
|
||||||
|
<div class="mean flex-grow-1 pr-2 pl-2">{{histogram.mean | number:'0.1-2'}}<span class="unit"></span></div>
|
||||||
|
</div>
|
||||||
|
<ng-template #noMeanPresent>
|
||||||
|
<div class="mean flex-grow-1 pr-2 pl-2">{{(histogram.max+histogram.min)/2 | number:'0.1-2'}}<span class="unit">‰</span></div>
|
||||||
|
</ng-template>
|
||||||
|
<div class="d-flex flex-column w-20">
|
||||||
|
<div class="justify-content-center pr-2 pl-2 min">{{histogram.min | number:'0.1-2'}}</div>
|
||||||
|
<div class="justify-content-center pr-2 pl-2 max">{{histogram.max | number:'0.1-2'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ng-template #noData>
|
||||||
|
<div class="widget">
|
||||||
|
<div class="d-flex flex-column justify-content-center w-100 h-100">
|
||||||
|
<div class="head h-20 p-1">Height</div>
|
||||||
|
<div class="body d-flex flex-row h-100 w-100">
|
||||||
|
<div class="p-1">No data available</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
@ -0,0 +1,32 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Input, Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import * as mapReducers from '../../reducers/map.reducer';
|
||||||
|
import { commonReducers, ItemTypeService, IItem, Item, ItemService, FolderService, IListItem } from '@farmmaps/common';
|
||||||
|
import { ForItemType } from '../for-item/for-itemtype.decorator';
|
||||||
|
import { ForSourceTask } from '../for-item/for-sourcetask.decorator';
|
||||||
|
import { AbstractItemListItemComponent } from '../item-list-item/item-list-item.component'
|
||||||
|
import { withLatestFrom, switchMap, map, switchMapTo, catchError, mergeMap, delay } from 'rxjs/operators';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { ControlScaleLineComponent } from 'ngx-openlayers';
|
||||||
|
|
||||||
|
|
||||||
|
@ForItemType("vnd.farmmaps.itemtype.geotiff.processed")
|
||||||
|
@ForSourceTask("vnd.farmmaps.task.ahn")
|
||||||
|
@Injectable()
|
||||||
|
@Component({
|
||||||
|
selector: 'fm-map-item-list-item-height',
|
||||||
|
templateUrl: './item-list-item-height.component.html',
|
||||||
|
styleUrls: ['./item-list-item-height.component.css']
|
||||||
|
})
|
||||||
|
export class ItemListItemHeightComponent extends AbstractItemListItemComponent implements OnInit {
|
||||||
|
@Input() item: IListItem;
|
||||||
|
selectedItem: Observable<IItem>;
|
||||||
|
|
||||||
|
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, private itemService$: ItemService) {
|
||||||
|
super(store, itemTypeService);
|
||||||
|
}
|
||||||
|
ngOnInit() {
|
||||||
|
this.selectedItem = this.itemService$.getItem(this.item.code);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
<div *ngIf="(selectedItem|async) as selectedItem">
|
||||||
|
<div class="widget d-flex flex-column p-1">
|
||||||
|
<div class="head" i18n>
|
||||||
|
Shadow index
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" [attr.fill]="sunColor" width="100" height="100">
|
||||||
|
<path
|
||||||
|
d="m234.3 139.4c-66.7 0-120.9 54.2-120.9 120.9 0 66.7 54.2 120.9 120.9 120.9 66.7 0 120.9-54.2 120.9-120.9 0-66.7-54.2-120.9-120.9-120.9z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m234.3 118.7c7.4 0 13.4-6 13.4-13.4V63.3c0-7.4-6-13.4-13.4-13.4-7.4 0-13.4 6-13.4 13.4v41.9c0 7.4 6 13.4 13.4 13.4z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m234.3 402c-7.4 0-13.4 6-13.4 13.4v41.9c0 7.4 6 13.4 13.4 13.4 7.4 0 13.4-6 13.4-13.4v-41.9c0-7.4-6-13.4-13.4-13.4z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m115.2 160.2c5.2 5.2 13.8 5.2 19 0 5.2-5.2 5.2-13.8 0-19l-29.7-29.7c-5.2-5.2-13.8-5.2-19 0-5.2 5.2-5.2 13.8 0 19z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m353.4 360.5c-5.2-5.2-13.8-5.2-19 0-5.2 5.2-5.2 13.8 0 19l29.7 29.7c5.2 5.2 13.8 5.2 19 0 5.2-5.2 5.2-13.8 0-19z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m92.7 260.3c0-7.4-6-13.4-13.4-13.4H37.3c-7.4 0-13.4 6-13.4 13.4 0 7.4 6 13.4 13.4 13.4h41.9c7.4 0 13.4-6 13.4-13.4z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m431.3 246.9h-41.9c-7.4 0-13.4 6-13.4 13.4 0 7.4 6 13.4 13.4 13.4h41.9c7.4 0 13.4-6 13.4-13.4 0-7.4-6-13.4-13.4-13.4z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m115.2 360.5-29.7 29.7c-5.2 5.2-5.2 13.8 0 19 5.2 5.2 13.8 5.2 19 0l29.7-29.7c5.2-5.2 5.2-13.8 0-19-5.2-5.2-13.8-5.2-19 0z"
|
||||||
|
class="a"/>
|
||||||
|
<path
|
||||||
|
d="m353.4 160.2 29.7-29.7c5.2-5.2 5.2-13.8 0-19-5.2-5.2-13.8-5.2-19 0l-29.7 29.7c-5.2 5.2-5.2 13.8 0 19 5.2 5.2 13.8 5.2 19 0z"
|
||||||
|
class="a"/>
|
||||||
|
<path [attr.d]="getSunShadowPath()" class="a" [attr.fill]="'black'"/>
|
||||||
|
</svg>
|
||||||
|
<div class="mean align-self-end">{{getMeanShadowValue(selectedItem) | number:'0.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,17 @@
|
|||||||
|
.head {
|
||||||
|
color: grey;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mean {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.9rem;
|
||||||
|
color: deeppink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
import {Observable} from 'rxjs';
|
||||||
|
import {Component, Injectable, Input, OnInit} from '@angular/core';
|
||||||
|
import {Store} from '@ngrx/store';
|
||||||
|
import * as mapReducers from '../../reducers/map.reducer';
|
||||||
|
import {commonReducers, IItem, IListItem, ItemService, ItemTypeService} from '@farmmaps/common';
|
||||||
|
import {ForItemType} from '../for-item/for-itemtype.decorator';
|
||||||
|
import {ForSourceTask} from '../for-item/for-sourcetask.decorator';
|
||||||
|
import {AbstractItemListItemComponent} from '../item-list-item/item-list-item.component'
|
||||||
|
import {map} from "rxjs/operators";
|
||||||
|
|
||||||
|
@ForItemType("vnd.farmmaps.itemtype.geotiff.processed")
|
||||||
|
@ForSourceTask("vnd.farmmaps.task.shadow")
|
||||||
|
@Injectable()
|
||||||
|
@Component({
|
||||||
|
selector: 'fm-map-item-list-item-shadow',
|
||||||
|
templateUrl: './item-list-item-shadow.component.html',
|
||||||
|
styleUrls: ['./item-list-item-shadow.component.scss']
|
||||||
|
})
|
||||||
|
export class ItemListItemShadowComponent extends AbstractItemListItemComponent implements OnInit {
|
||||||
|
@Input() item: IListItem;
|
||||||
|
selectedItem: Observable<IItem>;
|
||||||
|
|
||||||
|
public sunCenter = {x: 235.9, y: 259.4};
|
||||||
|
public sunStart = {x: 0, y: 0};
|
||||||
|
public sunEndRelative = {x: 0, y: 0};
|
||||||
|
public largeArc = 0;
|
||||||
|
public radius = 120;
|
||||||
|
|
||||||
|
public sunColor = '#ffcc00';
|
||||||
|
|
||||||
|
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService,
|
||||||
|
private itemService$: ItemService) {
|
||||||
|
super(store, itemTypeService);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.selectedItem = this.itemService$.getItem(this.item.code)
|
||||||
|
.pipe(map(item => {
|
||||||
|
const shadowIndex = this.getMeanShadowValue(item);
|
||||||
|
this.calculateSunValues(shadowIndex);
|
||||||
|
return item;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateSunValues(shadowIndex) {
|
||||||
|
const dotProduct = shadowIndex * 2 - 1;
|
||||||
|
this.largeArc = dotProduct > 0 ? 1 : 0;
|
||||||
|
|
||||||
|
const angle = Math.acos(dotProduct);
|
||||||
|
const yRadius = this.radius * Math.sin(-angle);
|
||||||
|
|
||||||
|
this.sunStart.x = this.sunCenter.x + this.radius * dotProduct;
|
||||||
|
this.sunStart.y = this.sunCenter.y + yRadius;
|
||||||
|
this.sunEndRelative.x = this.sunStart.x;
|
||||||
|
this.sunEndRelative.y = this.sunCenter.y - yRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSunShadowPath() {
|
||||||
|
return `M${this.sunStart.x} ${this.sunStart.y} A${this.radius},${this.radius} 0 ${this.largeArc},0 ${this.sunEndRelative.x} ${this.sunEndRelative.y}z`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMeanShadowValue(item): number {
|
||||||
|
return item.data.layers[0].renderer.band.histogram.mean;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
.head {
|
||||||
|
color: grey;
|
||||||
|
font-weight:bold;
|
||||||
|
/*border-bottom:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mean {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size:2rem;
|
||||||
|
line-height: 7.5rem;
|
||||||
|
color:deeppink;
|
||||||
|
/*border-right:1px solid black;*/
|
||||||
|
}
|
||||||
|
.min {
|
||||||
|
/*border-bottom:1px solid black;*/
|
||||||
|
}
|
||||||
|
.min, .max {
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 3.48rem;
|
||||||
|
color:gray;
|
||||||
|
font-size:1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size:0.8rem;
|
||||||
|
color:gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateformat {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
<div *ngIf="(lastTemporalItem$|async) as lastChildItem">
|
||||||
|
<div *ngIf="lastChildItem.data.layers[0].renderer.band.histogram;let histogram">
|
||||||
|
<div class="widget" (click)="onWidgetClicked()">
|
||||||
|
<div class="d-flex flex-column justify-content-center w-100 h-100">
|
||||||
|
<div class="head h-20 p-1">Soil moisture (<span class="unit">%</span>)</div>
|
||||||
|
<div class="dateformat p-1">{{lastChildItem.dataDate | date : 'shortDate'}}</div>
|
||||||
|
<div class="body d-flex flex-row h-100 w-100">
|
||||||
|
<div *ngIf="histogram.mean; else noMeanPresent">
|
||||||
|
<div class="mean flex-grow-1 pr-2 pl-2">{{histogram.mean/10 | number:'0.1-2'}}</div>
|
||||||
|
</div>
|
||||||
|
<ng-template #noMeanPresent>
|
||||||
|
<div class="mean flex-grow-1 pr-2 pl-2">{{(histogram.max+histogram.min)/2 | number:'0.1-2'}}</div>
|
||||||
|
</ng-template>
|
||||||
|
<div class="d-flex flex-column w-20">
|
||||||
|
<div class="justify-content-center pr-2 pl-2 min">{{histogram.min/10 | number:'0.1-2'}}</div>
|
||||||
|
<div class="justify-content-center pr-2 pl-2 max">{{histogram.max/10 | number:'0.1-2'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,42 @@
|
|||||||
|
import {Component, Injectable, Input, OnInit} from '@angular/core';
|
||||||
|
import {Store} from '@ngrx/store';
|
||||||
|
import * as mapReducers from '../../reducers/map.reducer';
|
||||||
|
import { commonReducers, ItemTypeService, IItem, ItemService, IListItem } from '@farmmaps/common';
|
||||||
|
import { ForItemType } from '../for-item/for-itemtype.decorator';
|
||||||
|
import { ForSourceTask } from '../for-item/for-sourcetask.decorator';
|
||||||
|
import { AbstractItemListItemComponent } from '../item-list-item/item-list-item.component'
|
||||||
|
import { map, mergeMap } from 'rxjs/operators';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
|
||||||
|
|
||||||
|
@ForItemType("vnd.farmmaps.itemtype.temporal")
|
||||||
|
@ForSourceTask("vnd.farmmaps.task.vandersat")
|
||||||
|
@Injectable()
|
||||||
|
@Component({
|
||||||
|
selector: 'fm-map-item-list-item-temporal',
|
||||||
|
templateUrl: './item-list-item-temporal.component.html',
|
||||||
|
styleUrls: ['./item-list-item-temporal.component.css']
|
||||||
|
})
|
||||||
|
export class ItemListItemTemporalComponent extends AbstractItemListItemComponent implements OnInit {
|
||||||
|
@Input() item: IListItem;
|
||||||
|
lastTemporalItem$: Observable<IItem>;
|
||||||
|
|
||||||
|
constructor(store: Store<mapReducers.State | commonReducers.State>,
|
||||||
|
itemTypeService: ItemTypeService, private itemService: ItemService,
|
||||||
|
private router: Router) {
|
||||||
|
super(store, itemTypeService);
|
||||||
|
}
|
||||||
|
ngOnInit() {
|
||||||
|
this.lastTemporalItem$ = this.itemService
|
||||||
|
.getChildItemList(this.item.code, "vnd.farmmaps.itemtype.geotiff.processed")
|
||||||
|
.pipe(
|
||||||
|
map(list => list.length>0? list.sort().slice(-1)[0]:null),
|
||||||
|
mergeMap(li => li==null?of(null):this.itemService.getItem(li.code)));
|
||||||
|
}
|
||||||
|
|
||||||
|
onWidgetClicked() {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.router.navigate(['viewer/vandersat/item', this.item.code]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
<div *ngIf="(item$|async) as item" class="widget d-flex flex-column p-1" (click)="onWidgetClicked($event)">
|
||||||
|
<ng-container *ngIf="getLastDailyOutput(item) as dailyOutput">
|
||||||
|
<div class="head" i18n>Yield forecast</div>
|
||||||
|
<div class="d-flex flex-row justify-content-between">
|
||||||
|
<div>(<span class="unit">ton/ha</span>)</div>
|
||||||
|
<div class="dateformat">{{dailyOutput.date | date : 'd/M/yy'}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<div class="fm fa-5x fm-potato"></div>
|
||||||
|
<div class="value align-self-end">{{dailyOutput.tuberwt[1] | number:'0.1-1'}}</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
@ -0,0 +1,36 @@
|
|||||||
|
.head {
|
||||||
|
color: grey;
|
||||||
|
font-weight: bold;
|
||||||
|
/*border-bottom:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.9rem;
|
||||||
|
color: deeppink;
|
||||||
|
/*border-right:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateformat {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fm-potato {
|
||||||
|
color: saddlebrown;
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import {Component, Injectable, Input, OnInit} from '@angular/core';
|
||||||
|
import {Store} from '@ngrx/store';
|
||||||
|
import * as mapReducers from '../../reducers/map.reducer';
|
||||||
|
import {commonReducers, IItem, IListItem, ItemService, ItemTypeService} from '@farmmaps/common';
|
||||||
|
import {ForItemType} from '../for-item/for-itemtype.decorator';
|
||||||
|
import {ForSourceTask} from '../for-item/for-sourcetask.decorator';
|
||||||
|
import {AbstractItemListItemComponent} from '../item-list-item/item-list-item.component'
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
|
||||||
|
@ForItemType("vnd.farmmaps.itemtype.tipstar")
|
||||||
|
@ForSourceTask("vnd.farmmaps.task.tipstar")
|
||||||
|
@Injectable()
|
||||||
|
@Component({
|
||||||
|
selector: 'fm-map-item-list-item-tipstar',
|
||||||
|
templateUrl: './item-list-item-tipstar.component.html',
|
||||||
|
styleUrls: ['./item-list-item-tipstar.component.scss']
|
||||||
|
})
|
||||||
|
export class ItemListItemTipstarComponent extends AbstractItemListItemComponent implements OnInit {
|
||||||
|
@Input() item: IListItem;
|
||||||
|
|
||||||
|
item$: Observable<IItem>;
|
||||||
|
|
||||||
|
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService,
|
||||||
|
private itemService$: ItemService, private router: Router) {
|
||||||
|
super(store, itemTypeService);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.item$ = this.itemService$.getItem(this.item.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
onWidgetClicked(event: MouseEvent) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.router.navigate(['viewer/tipstar/item', this.item.code]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastDailyOutput(item) {
|
||||||
|
if (item == null || item.data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemData = item.data;
|
||||||
|
if (itemData.dailyOutput == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemData.dailyOutput[itemData.dailyOutput.length - 1]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
.head {
|
||||||
|
color: grey;
|
||||||
|
font-weight: bold;
|
||||||
|
/*border-bottom:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tpvocmet {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.9rem;
|
||||||
|
line-height: 7.2rem;
|
||||||
|
color: deeppink;
|
||||||
|
/*border-right:1px solid black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateformat {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
<div class="widget">
|
||||||
|
<div class="d-flex flex-column justify-content-center w-100 h-100">
|
||||||
|
<div class="head h-20 p-1" i18n>WatBal (<span class="unit">kg/ha</span>)</div>
|
||||||
|
<div class="body d-flex flex-column h-100 w-100">
|
||||||
|
<small i18n>Date:{{TPVOCMET?.Datum | date : 'shortDate'}}</small>
|
||||||
|
<small i18n>Bedrijf/Perceel:{{TPVOCMET?.BedrijfID}}/{{TPVOCMET?.PerceelID}}</small>
|
||||||
|
<small i18n>GewichtZonder:{{TPVOCMET?.GewichtZonder | number:'0.1-2'}}</small>
|
||||||
|
<small i18n>GewichtGroDro:{{TPVOCMET?.GewichtGroDro | number:'0.1-2'}}</small>
|
||||||
|
<small i18n>GewichtGroNat:{{TPVOCMET?.GewichtGroNat | number:'0.1-2'}}</small>
|
||||||
|
</div>
|
||||||
|
<fm-map-widget-status [stage]="stage" [info]="'WatBal is expected in spring 2020.'" i18n></fm-map-widget-status>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,34 @@
|
|||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Input, Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import * as mapReducers from '../../reducers/map.reducer';
|
||||||
|
import { commonReducers, ItemTypeService, IItem, Item, ItemService, IListItem } from '@farmmaps/common';
|
||||||
|
import { ForItemType } from '../for-item/for-itemtype.decorator';
|
||||||
|
import { ForSourceTask } from '../for-item/for-sourcetask.decorator';
|
||||||
|
import { AbstractItemListItemComponent } from '../item-list-item/item-list-item.component'
|
||||||
|
import { Stage } from '../widget-status/widget-status.component';
|
||||||
|
|
||||||
|
@ForItemType("vnd.farmmaps.itemtype.watbal")
|
||||||
|
@ForSourceTask("vnd.farmmaps.task.watbal")
|
||||||
|
@Injectable()
|
||||||
|
@Component({
|
||||||
|
selector: 'fm-map-item-list-item-watbal',
|
||||||
|
templateUrl: './item-list-item-watbal.component.html',
|
||||||
|
styleUrls: ['./item-list-item-watbal.component.css']
|
||||||
|
})
|
||||||
|
export class ItemListItemWatBalComponent extends AbstractItemListItemComponent implements OnInit {
|
||||||
|
@Input() item: IListItem;
|
||||||
|
TPVOCMET;
|
||||||
|
stage = Stage.DevelopmentPreAlpha;
|
||||||
|
|
||||||
|
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, private itemService$: ItemService) {
|
||||||
|
super(store, itemTypeService);
|
||||||
|
}
|
||||||
|
ngOnInit() {
|
||||||
|
this.itemService$.getItem(this.item.code).subscribe(i => {
|
||||||
|
var data = i.data.HTAKKER_Input.TPVOCMET;
|
||||||
|
this.TPVOCMET = data[data.length - 1];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
<div *ngIf="(weather|async);let currentweather" style="padding: 10px;">
|
||||||
|
<div style="position:absolute">{{currentweather.temp}}°</div>
|
||||||
|
<img src="/images/weather/{{currentweather.icon_code}}.svg">
|
||||||
|
</div>
|
@ -0,0 +1,27 @@
|
|||||||
|
@import "../../_theme.scss";
|
||||||
|
@import "~bootstrap/scss/bootstrap.scss";
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
padding:0.8rem;
|
||||||
|
height:100%;
|
||||||
|
width:100%;
|
||||||
|
color:#ffffff;
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display:block;
|
||||||
|
font-size:6rem;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
display:block;
|
||||||
|
position:absolute;
|
||||||
|
width:calc(100% - 1.6rem );
|
||||||
|
padding-top:0.5rem;
|
||||||
|
bottom:0.8rem;
|
||||||
|
height:2rem;
|
||||||
|
overflow:hidden;
|
||||||
|
white-space:nowrap;
|
||||||
|
text-overflow:ellipsis;
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import { Component, Input, Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import * as mapReducers from '../../reducers/map.reducer';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { mergeMap } from 'rxjs/operators';
|
||||||
|
import { commonReducers, ItemTypeService, ItemService } from '@farmmaps/common';
|
||||||
|
import { AbstractItemWidgetComponent} from '../item-list-item/item-list-item.component';
|
||||||
|
import { ForItemType } from '../for-item/for-itemtype.decorator';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { GeoJSON } from 'ol/format';
|
||||||
|
import { getCenter, Extent, createEmpty, extend } from 'ol/extent';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@Component({
|
||||||
|
selector: 'fm-map-item-widget-weather',
|
||||||
|
templateUrl: './item-widget-weather.component.html',
|
||||||
|
styleUrls: ['./item-widget-weather.component.scss']
|
||||||
|
})
|
||||||
|
export class ItemWidgetWeatherComponent extends AbstractItemWidgetComponent {
|
||||||
|
|
||||||
|
private _format: GeoJSON;
|
||||||
|
|
||||||
|
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, public http: HttpClient, private itemService$: ItemService) {
|
||||||
|
super(store, itemTypeService);
|
||||||
|
this._format = new GeoJSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
public weather: Observable<any>;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.weather = this.itemService$.getItem(this.item.code).pipe(mergeMap(i => {
|
||||||
|
console.debug(i.geometry);
|
||||||
|
var geometry = this._format.readGeometry(i.geometry);
|
||||||
|
var centroid = getCenter(geometry.getExtent());
|
||||||
|
var url = 'https://weather.akkerweb.nl/v2/data/currentobservation/?c=' + centroid[0] + ',' + centroid[1] + '&key=5f17ef36283b49e9b099a1f4064fbf3d';
|
||||||
|
var cw = this.http.get(url);
|
||||||
|
return cw;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,6 @@ import { SessionClearedComponent } from './components/session-cleared/session-cl
|
|||||||
import { ResumableFileUploadService } from './components/resumable-file-upload/resumable-file-upload.service';
|
import { ResumableFileUploadService } from './components/resumable-file-upload/resumable-file-upload.service';
|
||||||
import { ResumableFileUploadComponent } from './components/resumable-file-upload/resumable-file-upload.component';
|
import { ResumableFileUploadComponent } from './components/resumable-file-upload/resumable-file-upload.component';
|
||||||
import { NotFoundComponent } from './components/not-found/not-found.component';
|
import { NotFoundComponent } from './components/not-found/not-found.component';
|
||||||
import { NotImplementedComponent } from './components/not-implemented/not-implemented.component';
|
|
||||||
import { SidePanelComponent } from './components/side-panel/side-panel.component';
|
import { SidePanelComponent } from './components/side-panel/side-panel.component';
|
||||||
import { TimespanComponent } from './components/timespan/timespan.component';
|
import { TimespanComponent } from './components/timespan/timespan.component';
|
||||||
import { TagInputComponent } from './components/tag-input/tag-input.component';
|
import { TagInputComponent } from './components/tag-input/tag-input.component';
|
||||||
@ -77,7 +76,6 @@ export {FolderService,
|
|||||||
ResumableFileUploadService,
|
ResumableFileUploadService,
|
||||||
ResumableFileUploadComponent,
|
ResumableFileUploadComponent,
|
||||||
NotFoundComponent,
|
NotFoundComponent,
|
||||||
NotImplementedComponent,
|
|
||||||
SidePanelComponent,
|
SidePanelComponent,
|
||||||
TimespanComponent,
|
TimespanComponent,
|
||||||
TagInputComponent,
|
TagInputComponent,
|
||||||
@ -117,7 +115,6 @@ export {FolderService,
|
|||||||
SidePanelComponent,
|
SidePanelComponent,
|
||||||
SafePipe,
|
SafePipe,
|
||||||
NotFoundComponent,
|
NotFoundComponent,
|
||||||
NotImplementedComponent,
|
|
||||||
ResumableFileUploadComponent,
|
ResumableFileUploadComponent,
|
||||||
TimespanComponent,
|
TimespanComponent,
|
||||||
TagInputComponent,
|
TagInputComponent,
|
||||||
@ -133,7 +130,6 @@ export {FolderService,
|
|||||||
SidePanelComponent,
|
SidePanelComponent,
|
||||||
SafePipe,
|
SafePipe,
|
||||||
NotFoundComponent,
|
NotFoundComponent,
|
||||||
NotImplementedComponent,
|
|
||||||
ResumableFileUploadComponent,
|
ResumableFileUploadComponent,
|
||||||
TimespanComponent,
|
TimespanComponent,
|
||||||
TagInputComponent,
|
TagInputComponent,
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
<div class="wrapper">
|
|
||||||
<header class="header header--large">
|
|
||||||
<h1 class="title">Function is not implemented in this code</h1>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
@ -1,11 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'fm-not-implemented',
|
|
||||||
templateUrl: './not-implemented.component.html'
|
|
||||||
})
|
|
||||||
export class NotImplementedComponent implements OnInit {
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit() { }
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user