Compare commits

..

2 Commits

390 changed files with 12571 additions and 99992 deletions

View File

@ -1,22 +0,0 @@
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"overrides": [
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
}
}

6
.gitignore vendored
View File

@ -33,7 +33,6 @@ speed-measure-plugin.json
.history/*
# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
@ -48,8 +47,3 @@ testem.log
Thumbs.db
projects/common/node_modules/
projects/common-map/node_modules/
.angular/*
projects/common-map3d/node_modules/
projects/common-map/node_modules/
projects/ng-openlayers/node_modules/
projects/common/node_modules/

1
.npmrc 100644
View File

@ -0,0 +1 @@
@FarmMaps:registry=https://repository.akkerweb.nl/repository/npm-group/

24
Jenkinsfile vendored
View File

@ -1,24 +0,0 @@
@Library('farmmaps-shared-library') _
pipeline {
agent any;
options {
copyArtifactPermission projectNames: env.allProjectsArtifactPermission;
disableConcurrentBuilds();
}
stages {
stage('FarmmapsLibBuildAll') {
steps {
stepFarmmapsLibBuildAll();
}
}
}
post {
success {
postSuccess();
}
always {
postAlways();
}
}
}

View File

@ -1,24 +1,47 @@
@Library('farmmaps-shared-library') _
pipeline {
agent any;
options {
copyArtifactPermission projectNames: env.allProjectsArtifactPermission;
disableConcurrentBuilds();
}
stages {
stage('FarmmapsLibBuildAll') {
steps {
stepFarmmapsLibBuildAll();
}
}
}
post {
success {
postSuccess();
}
always {
postAlways();
}
}
pipeline {
agent any
environment {
PACKAGE_VERSION_PREFIX=sh(script: 'jq .version package.json |sed "s/\\"//g"', returnStdout: true).trim()
PACKAGE_VERSION="${PACKAGE_VERSION_PREFIX + '-prerelease.' + env.BUILD_NUMBER}"
}
stages {
stage('npm install'){
steps {
sh '''npm install
cd projects/common
npm install
cd ../common-map
npm install
'''
}
}
stage('build'){
steps {
sh '''ng build common
ng build common-map'''
}
}
stage('npm publish'){
steps {
sh '''cd dist/common
npm version ${PACKAGE_VERSION}
npm publish
cd ../common-map
npm version ${PACKAGE_VERSION}
npm publish'''
}
}
}
post {
always {
emailext (
body: '${DEFAULT_CONTENT}',
mimeType: 'text/html',
replyTo: '${DEFAULT_REPLYTO}',
subject: '${DEFAULT_SUBJECT}',
to: emailextrecipients([[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider']])
)
}
}
}

124
README.md
View File

@ -1,65 +1,59 @@
# Farmmaps viewer
This is a sample FarmMaps client in Angular 7.x.
## Quick start
Use one of the two options below to get started.
## Option 1, Using docker
*Dependencies*
* docker desktop
*Setup*
```
docker pull node:12.13.1
docker run -t -i --entrypoint /bin/bash -p 4200:4200 node:12.13.1
```
Inside the running container
```
git clone https://git.akkerweb.nl/FarmMaps/FarmMapsLib.git
cd FarmMapsLib
npm config set @farmmaps:registry https://repository.akkerweb.nl/repository/npm-group/
npm install -g @angular/cli
npm install
ng serve --host 0.0.0.0
```
*Go*
Point your browser to http://localhost:4200
## Option 2, Using local machine
*Dependencies*
* npm 6.9.0
* nodejs 10.16.0
* git
*Setup*
```
git clone https://git.akkerweb.nl/FarmMaps/FarmMapsLib.git
cd FarmMapsLib
npm config set @farmmaps:registry https://repository.akkerweb.nl/repository/npm-group/
npm install -g @angular/cli
npm install
ng serve
```
*Go*`
Point your browser to http://localhost:4200
*ESLint*
```
npm run lint src
npm run lint projects/common/src
npm run lint projects/common-map/src
npm run lint projects/common-map3d/src
```
# Farmmaps viewer
This is a sample FarmMaps client in Angular 7.x.
## Quick start
Use one of the two options below to get started.
## Option 1, Using docker
*Dependencies*
* docker desktop
*Setup*
```
docker pull node:12.13.1
docker run -t -i --entrypoint /bin/bash -p 4200:4200 node:12.13.1
```
Inside the running container
```
git clone https://git.akkerweb.nl/FarmMaps/FarmMapsLib.git
cd FarmMapsLib
npm config set @farmmaps:registry https://repository.akkerweb.nl/repository/npm-group/
npm install -g @angular/cli
npm install
ng serve --host 0.0.0.0
```
*Go*
Point your browser to http://localhost:4200
## Option 2, Using local machine
*Dependencies*
* npm 6.9.0
* nodejs 10.16.0
* git
*Setup*
```
git clone https://git.akkerweb.nl/FarmMaps/FarmMapsLib.git
cd FarmMapsLib
npm config set @farmmaps:registry https://repository.akkerweb.nl/repository/npm-group/
npm install -g @angular/cli
npm install
ng serve
```
*Go*
Point your browser to http://localhost:4200

View File

@ -11,11 +11,8 @@
"schematics": {},
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"builder": "@angular-devkit/build-angular:browser",
"options": {
"customWebpackConfig": {
"path": "./custom-webpack.config.js"
},
"aot": true,
"outputPath": "dist/farmmaps-lib-app",
"index": "src/index.html",
@ -25,35 +22,29 @@
"assets": [
{
"glob": "**/*",
"input": "src/assets/images",
"output": "/images"
"input":"src/assets/images",
"output":"/images"
},
{
"glob": "silent-refresh.html",
"input": "src/assets",
"output": "/"
"input":"src/assets",
"output":"/"
},
{
"glob": "favicon.ico",
"input": "src/assets",
"output": "/"
},
{
"glob": "**/*",
"input": "node_modules/cesium/Build/Cesium",
"output": "/assets/cesium"
"input":"src/assets",
"output":"/"
},
"src/configuration.json"
],
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"fontawesome-6.2.1/css/all.min.css",
"fonts/FMIconFont/style.css",
"node_modules/cesium/Build/Cesium/Widgets/widgets.css",
"node_modules/ol/ol.css"
"node_modules/font-awesome/css/font-awesome.min.css",
"fonts/FMIconFont/style.css"
],
"scripts": []
"scripts": [],
"es5BrowserSupport": true
},
"configurations": {
"production": {
@ -83,48 +74,19 @@
"maximumWarning": "6kb"
}
]
},
"development": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": false,
"sourceMap": true,
"namedChunks": true,
"extractLicenses": false,
"vendorChunk": false,
"buildOptimizer": false,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "7mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
]
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "farmmaps-lib-app:build"
},
"configurations": {
"production": {
"browserTarget": "farmmaps-lib-app:build:production"
},
"development": {
"browserTarget": "farmmaps-lib-app:build:development"
}
},
"defaultConfiguration": "development"
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
@ -148,6 +110,18 @@
"src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
@ -167,6 +141,15 @@
"devServerTarget": "farmmaps-lib-app:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
},
@ -177,7 +160,7 @@
"prefix": "fm",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/common/tsconfig.lib.json",
"project": "projects/common/ng-package.json"
@ -195,6 +178,18 @@
"tsConfig": "projects/common/tsconfig.spec.json",
"karmaConfig": "projects/common/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/common/tsconfig.lib.json",
"projects/common/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
@ -205,7 +200,7 @@
"prefix": "fm-map",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/common-map/tsconfig.lib.json",
"project": "projects/common-map/ng-package.json"
@ -215,7 +210,7 @@
"tsConfig": "projects/common-map/tsconfig.lib.prod.json"
}
}
},
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
@ -223,39 +218,21 @@
"tsConfig": "projects/common-map/tsconfig.spec.json",
"karmaConfig": "projects/common-map/karma.conf.js"
}
}
}
},
"common-map3d": {
"projectType": "library",
"root": "projects/common-map3d",
"sourceRoot": "projects/common-map3d/src",
"prefix": "fm-map3d",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr:build",
"options": {
"tsConfig": "projects/common-map3d/tsconfig.lib.json",
"project": "projects/common-map3d/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/common-map3d/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"main": "projects/common-map3d/src/test.ts",
"tsConfig": "projects/common-map3d/tsconfig.spec.json",
"karmaConfig": "projects/common-map3d/karma.conf.js"
"tsConfig": [
"projects/common-map/tsconfig.lib.json",
"projects/common-map/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"cli": {
"analytics": false
}
"defaultProject": "farmmaps-lib-app"
}

View File

@ -1,16 +0,0 @@
module.exports = {
resolve: {
fallback: {
// Resolve node module use of fs
fs: "empty",
Buffer: false,
http: require.resolve("stream-http"),
https: require.resolve("https-browserify"),
url: require.resolve("url/"),
zlib: require.resolve('browserify-zlib'),
assert: require.resolve("assert/"),
util: require.resolve("util/"),
buffer: require.resolve("buffer/")
}
}
};

View File

@ -1,18 +0,0 @@
Font Awesome Pro License
------------------------
Font Awesome Pro is commercial software that requires a paid license. Full
Font Awesome Pro license: https://fontawesome.com/license.
# Commercial License
The Font Awesome Pro commercial license allows you to pay for FA Pro once, own
it, and use it just about everywhere you'd like.
# Attribution
Attribution is not required by the Font Awesome Pro commercial license.
# Brand Icons
All brand icons are trademarks of their respective owners. The use of these
trademarks does not indicate endorsement of the trademark holder by Font
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
to represent the company, product, or service to which they refer.**

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,19 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Pro';
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Pro'; }
@font-face {
font-family: 'Font Awesome 6 Pro';
font-style: normal;
font-weight: 300;
font-display: block;
src: url("../webfonts/fa-light-300.woff2") format("woff2"), url("../webfonts/fa-light-300.ttf") format("truetype"); }
.fal,
.fa-light {
font-weight: 300; }

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Pro";--fa-font-light:normal 300 1em/1 "Font Awesome 6 Pro"}@font-face{font-family:"Font Awesome 6 Pro";font-style:normal;font-weight:300;font-display:block;src:url(../webfonts/fa-light-300.woff2) format("woff2"),url(../webfonts/fa-light-300.ttf) format("truetype")}.fa-light,.fal{font-weight:300}

View File

@ -1,19 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Pro';
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Pro'; }
@font-face {
font-family: 'Font Awesome 6 Pro';
font-style: normal;
font-weight: 400;
font-display: block;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
.far,
.fa-regular {
font-weight: 400; }

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Pro";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Pro"}@font-face{font-family:"Font Awesome 6 Pro";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}

View File

@ -1,19 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-sharp: 'Font Awesome 6 Sharp';
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp'; }
@font-face {
font-family: 'Font Awesome 6 Sharp';
font-style: normal;
font-weight: 900;
font-display: block;
src: url("../webfonts/fa-sharp-solid-900.woff2") format("woff2"), url("../webfonts/fa-sharp-solid-900.ttf") format("truetype"); }
.fass,
.fa-sharp-solid {
font-weight: 900; }

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:host,:root{--fa-style-family-sharp:"Font Awesome 6 Sharp";--fa-font-sharp-solid:normal 900 1em/1 "Font Awesome 6 Sharp"}@font-face{font-family:"Font Awesome 6 Sharp";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-sharp-solid-900.woff2) format("woff2"),url(../webfonts/fa-sharp-solid-900.ttf) format("truetype")}.fa-sharp-solid,.fass{font-weight:900}

View File

@ -1,19 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Pro';
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Pro'; }
@font-face {
font-family: 'Font Awesome 6 Pro';
font-style: normal;
font-weight: 900;
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
.fas,
.fa-solid {
font-weight: 900; }

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Pro";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Pro"}@font-face{font-family:"Font Awesome 6 Pro";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}

View File

@ -1,635 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Solid';
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Regular';
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Light';
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Thin';
--fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone';
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp';
--fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; }
svg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {
overflow: visible;
box-sizing: content-box; }
.svg-inline--fa {
display: var(--fa-display, inline-block);
height: 1em;
overflow: visible;
vertical-align: -.125em; }
.svg-inline--fa.fa-2xs {
vertical-align: 0.1em; }
.svg-inline--fa.fa-xs {
vertical-align: 0em; }
.svg-inline--fa.fa-sm {
vertical-align: -0.07143em; }
.svg-inline--fa.fa-lg {
vertical-align: -0.2em; }
.svg-inline--fa.fa-xl {
vertical-align: -0.25em; }
.svg-inline--fa.fa-2xl {
vertical-align: -0.3125em; }
.svg-inline--fa.fa-pull-left {
margin-right: var(--fa-pull-margin, 0.3em);
width: auto; }
.svg-inline--fa.fa-pull-right {
margin-left: var(--fa-pull-margin, 0.3em);
width: auto; }
.svg-inline--fa.fa-li {
width: var(--fa-li-width, 2em);
top: 0.25em; }
.svg-inline--fa.fa-fw {
width: var(--fa-fw-width, 1.25em); }
.fa-layers svg.svg-inline--fa {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0; }
.fa-layers-text, .fa-layers-counter {
display: inline-block;
position: absolute;
text-align: center; }
.fa-layers {
display: inline-block;
height: 1em;
position: relative;
text-align: center;
vertical-align: -.125em;
width: 1em; }
.fa-layers svg.svg-inline--fa {
-webkit-transform-origin: center center;
transform-origin: center center; }
.fa-layers-text {
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transform-origin: center center;
transform-origin: center center; }
.fa-layers-counter {
background-color: var(--fa-counter-background-color, #ff253a);
border-radius: var(--fa-counter-border-radius, 1em);
box-sizing: border-box;
color: var(--fa-inverse, #fff);
line-height: var(--fa-counter-line-height, 1);
max-width: var(--fa-counter-max-width, 5em);
min-width: var(--fa-counter-min-width, 1.5em);
overflow: hidden;
padding: var(--fa-counter-padding, 0.25em 0.5em);
right: var(--fa-right, 0);
text-overflow: ellipsis;
top: var(--fa-top, 0);
-webkit-transform: scale(var(--fa-counter-scale, 0.25));
transform: scale(var(--fa-counter-scale, 0.25));
-webkit-transform-origin: top right;
transform-origin: top right; }
.fa-layers-bottom-right {
bottom: var(--fa-bottom, 0);
right: var(--fa-right, 0);
top: auto;
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: bottom right;
transform-origin: bottom right; }
.fa-layers-bottom-left {
bottom: var(--fa-bottom, 0);
left: var(--fa-left, 0);
right: auto;
top: auto;
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: bottom left;
transform-origin: bottom left; }
.fa-layers-top-right {
top: var(--fa-top, 0);
right: var(--fa-right, 0);
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: top right;
transform-origin: top right; }
.fa-layers-top-left {
left: var(--fa-left, 0);
right: auto;
top: var(--fa-top, 0);
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: top left;
transform-origin: top left; }
.fa-1x {
font-size: 1em; }
.fa-2x {
font-size: 2em; }
.fa-3x {
font-size: 3em; }
.fa-4x {
font-size: 4em; }
.fa-5x {
font-size: 5em; }
.fa-6x {
font-size: 6em; }
.fa-7x {
font-size: 7em; }
.fa-8x {
font-size: 8em; }
.fa-9x {
font-size: 9em; }
.fa-10x {
font-size: 10em; }
.fa-2xs {
font-size: 0.625em;
line-height: 0.1em;
vertical-align: 0.225em; }
.fa-xs {
font-size: 0.75em;
line-height: 0.08333em;
vertical-align: 0.125em; }
.fa-sm {
font-size: 0.875em;
line-height: 0.07143em;
vertical-align: 0.05357em; }
.fa-lg {
font-size: 1.25em;
line-height: 0.05em;
vertical-align: -0.075em; }
.fa-xl {
font-size: 1.5em;
line-height: 0.04167em;
vertical-align: -0.125em; }
.fa-2xl {
font-size: 2em;
line-height: 0.03125em;
vertical-align: -0.1875em; }
.fa-fw {
text-align: center;
width: 1.25em; }
.fa-ul {
list-style-type: none;
margin-left: var(--fa-li-margin, 2.5em);
padding-left: 0; }
.fa-ul > li {
position: relative; }
.fa-li {
left: calc(var(--fa-li-width, 2em) * -1);
position: absolute;
text-align: center;
width: var(--fa-li-width, 2em);
line-height: inherit; }
.fa-border {
border-color: var(--fa-border-color, #eee);
border-radius: var(--fa-border-radius, 0.1em);
border-style: var(--fa-border-style, solid);
border-width: var(--fa-border-width, 0.08em);
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
.fa-pull-left {
float: left;
margin-right: var(--fa-pull-margin, 0.3em); }
.fa-pull-right {
float: right;
margin-left: var(--fa-pull-margin, 0.3em); }
.fa-beat {
-webkit-animation-name: fa-beat;
animation-name: fa-beat;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
.fa-bounce {
-webkit-animation-name: fa-bounce;
animation-name: fa-bounce;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
.fa-fade {
-webkit-animation-name: fa-fade;
animation-name: fa-fade;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
.fa-beat-fade {
-webkit-animation-name: fa-beat-fade;
animation-name: fa-beat-fade;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
.fa-flip {
-webkit-animation-name: fa-flip;
animation-name: fa-flip;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
.fa-shake {
-webkit-animation-name: fa-shake;
animation-name: fa-shake;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
animation-timing-function: var(--fa-animation-timing, linear); }
.fa-spin {
-webkit-animation-name: fa-spin;
animation-name: fa-spin;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 2s);
animation-duration: var(--fa-animation-duration, 2s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
animation-timing-function: var(--fa-animation-timing, linear); }
.fa-spin-reverse {
--fa-animation-direction: reverse; }
.fa-pulse,
.fa-spin-pulse {
-webkit-animation-name: fa-spin;
animation-name: fa-spin;
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, steps(8));
animation-timing-function: var(--fa-animation-timing, steps(8)); }
@media (prefers-reduced-motion: reduce) {
.fa-beat,
.fa-bounce,
.fa-fade,
.fa-beat-fade,
.fa-flip,
.fa-pulse,
.fa-shake,
.fa-spin,
.fa-spin-pulse {
-webkit-animation-delay: -1ms;
animation-delay: -1ms;
-webkit-animation-duration: 1ms;
animation-duration: 1ms;
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
transition-delay: 0s;
transition-duration: 0s; } }
@-webkit-keyframes fa-beat {
0%, 90% {
-webkit-transform: scale(1);
transform: scale(1); }
45% {
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
transform: scale(var(--fa-beat-scale, 1.25)); } }
@keyframes fa-beat {
0%, 90% {
-webkit-transform: scale(1);
transform: scale(1); }
45% {
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
transform: scale(var(--fa-beat-scale, 1.25)); } }
@-webkit-keyframes fa-bounce {
0% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
10% {
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
30% {
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
50% {
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
57% {
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
64% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
100% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); } }
@keyframes fa-bounce {
0% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
10% {
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
30% {
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
50% {
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
57% {
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
64% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
100% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); } }
@-webkit-keyframes fa-fade {
50% {
opacity: var(--fa-fade-opacity, 0.4); } }
@keyframes fa-fade {
50% {
opacity: var(--fa-fade-opacity, 0.4); } }
@-webkit-keyframes fa-beat-fade {
0%, 100% {
opacity: var(--fa-beat-fade-opacity, 0.4);
-webkit-transform: scale(1);
transform: scale(1); }
50% {
opacity: 1;
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
@keyframes fa-beat-fade {
0%, 100% {
opacity: var(--fa-beat-fade-opacity, 0.4);
-webkit-transform: scale(1);
transform: scale(1); }
50% {
opacity: 1;
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
@-webkit-keyframes fa-flip {
50% {
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
@keyframes fa-flip {
50% {
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
@-webkit-keyframes fa-shake {
0% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg); }
4% {
-webkit-transform: rotate(15deg);
transform: rotate(15deg); }
8%, 24% {
-webkit-transform: rotate(-18deg);
transform: rotate(-18deg); }
12%, 28% {
-webkit-transform: rotate(18deg);
transform: rotate(18deg); }
16% {
-webkit-transform: rotate(-22deg);
transform: rotate(-22deg); }
20% {
-webkit-transform: rotate(22deg);
transform: rotate(22deg); }
32% {
-webkit-transform: rotate(-12deg);
transform: rotate(-12deg); }
36% {
-webkit-transform: rotate(12deg);
transform: rotate(12deg); }
40%, 100% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); } }
@keyframes fa-shake {
0% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg); }
4% {
-webkit-transform: rotate(15deg);
transform: rotate(15deg); }
8%, 24% {
-webkit-transform: rotate(-18deg);
transform: rotate(-18deg); }
12%, 28% {
-webkit-transform: rotate(18deg);
transform: rotate(18deg); }
16% {
-webkit-transform: rotate(-22deg);
transform: rotate(-22deg); }
20% {
-webkit-transform: rotate(22deg);
transform: rotate(22deg); }
32% {
-webkit-transform: rotate(-12deg);
transform: rotate(-12deg); }
36% {
-webkit-transform: rotate(12deg);
transform: rotate(12deg); }
40%, 100% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); } }
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
.fa-rotate-90 {
-webkit-transform: rotate(90deg);
transform: rotate(90deg); }
.fa-rotate-180 {
-webkit-transform: rotate(180deg);
transform: rotate(180deg); }
.fa-rotate-270 {
-webkit-transform: rotate(270deg);
transform: rotate(270deg); }
.fa-flip-horizontal {
-webkit-transform: scale(-1, 1);
transform: scale(-1, 1); }
.fa-flip-vertical {
-webkit-transform: scale(1, -1);
transform: scale(1, -1); }
.fa-flip-both,
.fa-flip-horizontal.fa-flip-vertical {
-webkit-transform: scale(-1, -1);
transform: scale(-1, -1); }
.fa-rotate-by {
-webkit-transform: rotate(var(--fa-rotate-angle, none));
transform: rotate(var(--fa-rotate-angle, none)); }
.fa-stack {
display: inline-block;
vertical-align: middle;
height: 2em;
position: relative;
width: 2.5em; }
.fa-stack-1x,
.fa-stack-2x {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
z-index: var(--fa-stack-z-index, auto); }
.svg-inline--fa.fa-stack-1x {
height: 1em;
width: 1.25em; }
.svg-inline--fa.fa-stack-2x {
height: 2em;
width: 2.5em; }
.fa-inverse {
color: var(--fa-inverse, #fff); }
.sr-only,
.fa-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0; }
.sr-only-focusable:not(:focus),
.fa-sr-only-focusable:not(:focus) {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0; }
.svg-inline--fa .fa-primary {
fill: var(--fa-primary-color, currentColor);
opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa .fa-secondary {
fill: var(--fa-secondary-color, currentColor);
opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-primary {
opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-secondary {
opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa mask .fa-primary,
.svg-inline--fa mask .fa-secondary {
fill: black; }
.fad.fa-inverse,
.fa-duotone.fa-inverse {
color: var(--fa-inverse, #fff); }

File diff suppressed because one or more lines are too long

View File

@ -1,19 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Pro';
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Pro'; }
@font-face {
font-family: 'Font Awesome 6 Pro';
font-style: normal;
font-weight: 100;
font-display: block;
src: url("../webfonts/fa-thin-100.woff2") format("woff2"), url("../webfonts/fa-thin-100.ttf") format("truetype"); }
.fat,
.fa-thin {
font-weight: 100; }

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Pro";--fa-font-thin:normal 100 1em/1 "Font Awesome 6 Pro"}@font-face{font-family:"Font Awesome 6 Pro";font-style:normal;font-weight:100;font-display:block;src:url(../webfonts/fa-thin-100.woff2) format("woff2"),url(../webfonts/fa-thin-100.ttf) format("truetype")}.fa-thin,.fat{font-weight:100}

View File

@ -1,26 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,34 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
@font-face {
font-family: 'Font Awesome 5 Brands';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Pro';
font-display: block;
font-weight: 900;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Pro';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Pro';
font-display: block;
font-weight: 300;
src: url("../webfonts/fa-light-300.woff2") format("woff2"), url("../webfonts/fa-light-300.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Duotone';
font-display: block;
font-weight: 900;
src: url("../webfonts/fa-duotone-900.woff2") format("woff2"), url("../webfonts/fa-duotone-900.ttf") format("truetype"); }

View File

@ -1,6 +0,0 @@
/*!
* Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
* Copyright 2022 Fonticons, Inc.
*/
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Pro";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Pro";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Pro";font-display:block;font-weight:300;src:url(../webfonts/fa-light-300.woff2) format("woff2"),url(../webfonts/fa-light-300.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Duotone";font-display:block;font-weight:900;src:url(../webfonts/fa-duotone-900.woff2) format("woff2"),url(../webfonts/fa-duotone-900.ttf) format("truetype")}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -23,46 +23,6 @@
content: "b";
}
.fm-trijntje:before {
content: "c";
}
.fm-satellite:before {
content: "d";
}
.fm-sensoterra:before {
content: "e";
}
.fm-blight:before {
content: "f";
}
.fm-agrodatacube:before {
content: "g";
}
.fm-app-menu:before {
content: "h";
}
.fm-blight-holes:before {
content: "i";
}
.fm-carbon:before {
content: "j";
}
.fm-bo-akkerbouw:before {
content: "k";
}
.fm-grass:before {
content: "l";
}
@font-face {
font-family: "FarmMaps";
src: url("./FMIconFont.woff") format("woff"), /* Modern Browsers */

38684
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +1,66 @@
{
"name": "farmmaps-lib-app",
"version": "4.5.0",
"version": "0.0.1",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "eslint -c .eslintrc.js --ext .ts",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^17.3.3",
"@angular/common": "^17.3.3",
"@angular/compiler": "^17.3.3",
"@angular/core": "^17.3.3",
"@angular-eslint/eslint-plugin": "^15.2.1",
"@angular/forms": "^17.3.3",
"@angular/platform-browser": "^17.3.3",
"@angular/platform-browser-dynamic": "^17.3.3",
"@angular/router": "^17.3.3",
"@farmmaps/common": "file:dist/common",
"@farmmaps/common-map": "file:dist/common-map",
"@farmmaps/common-map3d": "file:dist/common-map3d",
"ng-openlayers": "17.1.3",
"@microsoft/signalr": "^3.1.16",
"@ng-bootstrap/ng-bootstrap": "^16.0.0",
"@ngrx/effects": "^17",
"@ngrx/router-store": "^17",
"@ngrx/store": "^17",
"@popperjs/core": "^2.11.6",
"angular-oauth2-oidc": "^13",
"assert": "^2.0.0",
"bootstrap": "^5.2.0",
"browserify-zlib": "^0.2.0",
"buffer": "^6.0.3",
"cesium": "^1.97.0",
"core-js": "^2.6.12",
"https-browserify": "^1.0.0",
"moment": "^2.29.4",
"ngrx-store-localstorage": "17.0.0",
"ngx-avatars": "1.7.0",
"ngx-clipboard": "16.0.0",
"ngx-image-cropper": "^7.2.1",
"ngx-uploadx": "^6.2.0",
"ol": "^8.2.0",
"olcs": "^2.13.1",
"@angular/animations": "~9.1.10",
"@angular/common": "~9.1.10",
"@angular/compiler": "~9.1.10",
"@angular/core": "~9.1.10",
"@angular/forms": "~9.1.10",
"@angular/platform-browser": "~9.1.10",
"@angular/platform-browser-dynamic": "~9.1.10",
"@angular/router": "~9.1.10",
"@microsoft/signalr": "^3.1.3",
"@farmmaps/common": ">=0.0.1-prerelease.267 <0.0.1",
"@farmmaps/common-map": ">=0.0.1-prerelease.267 <0.0.1",
"@ng-bootstrap/ng-bootstrap": "^6.0",
"@ngrx/effects": "^9.0",
"@ngrx/router-store": "^9.0",
"@ngrx/store": "^9.0",
"ngx-uploadx": "^3.3.4",
"angular-oauth2-oidc": "^9.1",
"bootstrap": "^4.4.1",
"core-js": "^2.6.11",
"font-awesome": "^4.7.0",
"ngrx-store-localstorage": "^9.0",
"resumablejs": "^1.1.0",
"rxjs": "^7.8.1",
"stream": "^0.0.2",
"stream-http": "^3.2.0",
"rxjs": "^6.5.4",
"tassign": "^1.0.0",
"tslib": "^2.4.0",
"url": "^0.11.0",
"util": "^0.12.4",
"zone.js": "~0.14.4"
"tslib": "^1.10.0",
"zone.js": "~0.10.2",
"ngx-openlayers": "1.0.0-next.13",
"ol": "6.1.1"
},
"devDependencies": {
"@angular-builders/custom-webpack": "^17",
"@angular-devkit/build-angular": "^17.3.3",
"@angular/cli": "^17.3.3",
"@angular/compiler-cli": "^17.3.3",
"@angular/language-service": "^17.3.3",
"@angular/localize": "^17.3.3",
"@types/arcgis-rest-api": "^10.4.5",
"@angular-devkit/build-angular": "~0.901.7",
"@angular-devkit/build-ng-packagr": "~0.901.7",
"@angular/cli": "^9.1.7",
"@angular/compiler-cli": "~9.1.10",
"@angular/language-service": "~9.1.10",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "^2.0.9",
"@types/node": "^12.20.15",
"@typescript-eslint/eslint-plugin": "^6.18.0",
"@typescript-eslint/eslint-plugin-tslint": "^6.18.0",
"@typescript-eslint/parser": "^6.18.0",
"codelyzer": "^0.0.28",
"eslint": "^8.35.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"jasmine-core": "^4.3.0",
"jasmine-spec-reporter": "^7.0.0",
"karma": "^6.3.20",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"ng-packagr": "^17.3.0",
"protractor": "~7.0.0",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1",
"codelyzer": "^5.1.2",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "^5.0.2",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"ng-packagr": "^9.0.0",
"protractor": "^5.4.4",
"ts-node": "^8.8.1",
"typescript": "~5.4.4"
"tslint": "~5.11.0",
"typescript": "~3.8.3"
}
}
}

View File

@ -1,22 +0,0 @@
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"overrides": [
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
}
}

View File

@ -1,24 +0,0 @@
# CommonMap
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.0.
## Code scaffolding
Run `ng generate component component-name --project common-map` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project common-map`.
> Note: Don't forget to add `--project common-map` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build common-map` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build common-map`, go to the dist folder `cd dist/common-map` and run `npm publish`.
## Running unit tests
Run `ng test common-map` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -1,10 +0,0 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/common-map",
"lib": {
"entryFile": "src/public-api.ts"
},
"allowedNonPeerDependencies": [
"."
]
}

View File

@ -1,30 +0,0 @@
{
"name": "@farmmaps/common-map",
"version": "2.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@farmmaps/common-map",
"version": "2.0.0",
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/core": "^17.3.3",
"@ngrx/effects": "^17",
"@ngrx/router-store": "^17",
"@ngrx/store": "^17",
"ng-openlayers": "17.1.3",
"ngrx-store-localstorage": "^17",
"ol": "^8.2.0",
"tassign": "^1.0.0"
}
},
"node_modules/tslib": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz",
"integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ=="
}
}
}

View File

@ -1,20 +0,0 @@
{
"name": "@farmmaps/common-map",
"version": "2.0.0",
"publishConfig": {
"registry": "https://repository.akkerweb.nl/repository/npm-hosted/"
},
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/core": "^17.3.3",
"ngrx-store-localstorage": "^17",
"@ngrx/effects": "^17",
"@ngrx/router-store": "^17",
"@ngrx/store": "^17",
"tassign": "^1.0.0",
"ng-openlayers": "17.1.3",
"ol": "^8.2.0"
}
}

View File

@ -1,399 +0,0 @@
import { Action } from '@ngrx/store';
import { IMapState } from '../models/map.state';
import { IItemLayer } from '../models/item.layer';
import { ILayervalue } from '../models/layer.value';
import { IQueryState } from '@farmmaps/common';
import { IItem } from '@farmmaps/common';
import { Feature } from 'ol';
import { Style } from 'ol/style';
import { Geometry } from 'ol/geom';
import { IPeriodState } from '../models/period.state';
export const SETSTATE = '[Map] SetState';
export const SETMAPSTATE = '[Map] MapState';
export const SETVIEWEXTENT = '[Map] SetViewExtent';
export const INIT = '[Map] Init';
export const SETPARENT = '[Map] SetParent';
export const SETPERIOD = '[Map] SetPeriod';
export const STARTSEARCH = '[Map] StartSearch';
export const STARTSEARCHSUCCESS = '[Map] StartSearchSuccess';
export const CLICKFEATURE = '[Map] ClickFeature';
export const SELECTFEATURE = '[Map] SelectFeature';
export const SELECTITEM = '[Map] SelectItem';
export const SELECTITEMSUCCESS = '[Map] SelectItemSuccess';
export const SETSELECTEDITEMLAYER = '[Map] SetSelectedItemLayer';
export const SELECTTEMPORALITEMSSUCCESS = '[Map] SelectTemporalItemsSuccess';
export const NEXTTEMPORAL = '[Map] NextTemporal';
export const PREVIOUSTEMPORAL = '[Map] PreviousTemporal';
export const SELECTTEMPORAL = '[Map] SelectTemporal';
export const ADDFEATURESUCCESS = '[Map] AddFeatureSuccess';
export const UPDATEFEATURESUCCESS = '[Map] UpdateFeatureSuccess';
export const EXPANDSEARCH = '[Map] ExpandSearch';
export const COLLAPSESEARCH = '[Map] CollapseSearch';
export const SETEXTENT = '[Map] SetExtent';
export const SETQUERYSTATE = '[Map] SetQueryState';
export const SETTIMESPAN = '[Map] SetTimeSpan';
export const ADDLAYER = '[Map] AddLayer';
export const SETVISIBILITY = '[Map] SetVisibility';
export const SETOPACITY = '[Map] SetOpacity';
export const SETLAYERINDEX = '[Map] SetLayerIndex';
export const REMOVELAYER = '[Map] RemoveLayer';
export const CLEARLAYERS = '[Map] ClearLayers';
export const LOADBASELAYERS = '[Map] LoadLayers';
export const LOADBASELAYERSSUCCESS = '[Map] LoadLayersSuccess';
export const SELECTBASELAYER = '[Map] SelectBaseLayers';
export const SELECTOVERLAYLAYER = '[Map] SelectOverlayLayers';
export const ZOOMTOEXTENT = '[Map] ZoomToExtent';
export const DOQUERY = '[Map] DoQuery';
export const SETSTYLE = '[Map] SetStyle';
export const SHOWLAYERSWITCHER = '[Map] ShowLayerSwitcher';
export const CLEAR = '[Map] Clear';
export const SETREPLACEURL = '[Map] SetReplaceUrl';
export const SETFEATURES = '[Map] SetFeatures'
export const SETLAYERVALUESLOCATION = '[Map] SetLayerValuesLocation'
export const TOGGLELAYERVALUESENABLED = '[Map] ToggleLayerValuesEnabled'
export const GETLAYERVALUE = '[Map] GetLayerValue'
export const GETLAYERVALUESUCCESS = '[Map] GetLayerValueSuccess'
export const TOGGLESHOWDATALAYERSLIDE = '[Map] ToggleShowDataLayerSlide'
export const SETVIEWSTATE = '[Map] SetViewState'
export const CLEARFEATURES = '[Map] ClearFeatures';
export const SETPANELEXTRAWIDE = '[Map] SetPanelExtraWide';
export class Clear implements Action {
readonly type = CLEAR;
constructor() {}
}
export class SetState implements Action {
readonly type = SETSTATE;
constructor(public mapState: IMapState,public queryState:IQueryState) { }
}
export class SetMapState implements Action {
readonly type = SETMAPSTATE;
constructor(public mapState: IMapState) { }
}
export class SetViewExtent implements Action {
readonly type = SETVIEWEXTENT;
constructor(public extent:number[]) { }
}
export class Init implements Action {
readonly type = INIT;
constructor() { }
}
export class SetParent implements Action {
readonly type = SETPARENT;
constructor(public parentCode:string) { }
}
export class SetPeriod implements Action {
readonly type = SETPERIOD;
constructor(public period:IPeriodState) { }
}
export class StartSearch implements Action {
readonly type = STARTSEARCH;
constructor(public queryState: IQueryState) { }
}
export class StartSearchSuccess implements Action {
readonly type = STARTSEARCHSUCCESS;
constructor(public features: Array<Feature<Geometry>>, public query:IQueryState) { }
}
export class ClickFeature implements Action {
readonly type = CLICKFEATURE;
constructor(public feature:Feature<Geometry>) { }
}
export class SelectFeature implements Action {
readonly type = SELECTFEATURE;
constructor(public feature:Feature<Geometry>) { }
}
export class SelectItem implements Action {
readonly type = SELECTITEM;
constructor(public itemCode:string) { }
}
export class SelectItemSuccess implements Action {
readonly type = SELECTITEMSUCCESS;
constructor(public item: IItem, public parentItem: IItem) { }
}
export class SelectTemporalItemsSuccess implements Action {
readonly type = SELECTTEMPORALITEMSSUCCESS;
constructor(public temporalItems: IItem[]) { }
}
export class NextTemporal implements Action {
readonly type = NEXTTEMPORAL;
constructor() { }
}
export class PreviousTemporal implements Action {
readonly type = PREVIOUSTEMPORAL;
constructor() { }
}
export class SelectTemporal implements Action {
readonly type = SELECTTEMPORAL;
constructor(item:IItem) { }
}
export class AddFeatureSuccess implements Action {
readonly type = ADDFEATURESUCCESS;
constructor(public feature: Feature<Geometry>) { }
}
export class UpdateFeatureSuccess implements Action {
readonly type = UPDATEFEATURESUCCESS;
constructor(public feature: Feature<Geometry>) { }
}
export class ExpandSearch implements Action {
readonly type = EXPANDSEARCH;
constructor() { }
}
export class CollapseSearch implements Action {
readonly type = COLLAPSESEARCH;
constructor() { }
}
export class SetExtent implements Action {
readonly type = SETEXTENT;
constructor(public extent:number[]) { }
}
export class SetQueryState implements Action {
readonly type = SETQUERYSTATE;
constructor(public queryState: IQueryState,public replaceUrl:boolean = true) { }
}
export class SetTimeSpan implements Action {
readonly type = SETTIMESPAN;
constructor(public startDate: Date, public endDate: Date) { }
}
export class AddLayer implements Action {
readonly type = ADDLAYER;
constructor(public item:IItem,public layerIndex=-1) { }
}
export class SetSelectedItemLayer implements Action {
readonly type = SETSELECTEDITEMLAYER;
constructor(public item:IItem,public layerIndex=-1) { }
}
export class SetVisibility implements Action {
readonly type = SETVISIBILITY;
constructor(public itemLayer:IItemLayer,public visibility:boolean) { }
}
export class SetOpacity implements Action {
readonly type = SETOPACITY;
constructor(public itemLayer: IItemLayer, public opacity: number) { }
}
export class SetLayerIndex implements Action {
readonly type = SETLAYERINDEX;
constructor(public layerIndex: number, public itemLayer: IItemLayer = null) { }
}
export class RemoveLayer implements Action {
readonly type = REMOVELAYER;
constructor(public itemLayer: IItemLayer) { }
}
export class ClearLayers implements Action {
readonly type = CLEARLAYERS;
constructor() { }
}
export class LoadBaseLayers implements Action {
readonly type = LOADBASELAYERS;
constructor(public projection: string) { }
}
export class LoadBaseLayersSuccess implements Action {
readonly type = LOADBASELAYERSSUCCESS;
constructor(public items: IItem[] ) { }
}
export class SelectBaseLayer implements Action {
readonly type = SELECTBASELAYER;
constructor(public itemLayer: IItemLayer) { }
}
export class SelectOverlayLayer implements Action {
readonly type = SELECTOVERLAYLAYER;
constructor(public itemLayer: IItemLayer) { }
}
export class ZoomToExtent implements Action {
readonly type = ZOOMTOEXTENT;
constructor(public itemLayer: IItemLayer) { }
}
export class DoQuery implements Action {
readonly type = DOQUERY;
constructor(public query:IQueryState,public replace:boolean = false) { }
}
export class SetStyle implements Action {
readonly type = SETSTYLE;
constructor(public itemType:string,public style: Style | ((feature:Feature<Geometry>) => Style )) { }
}
export class ShowLayerSwitcher implements Action {
readonly type = SHOWLAYERSWITCHER;
constructor(public show:boolean) {}
}
export class SetReplaceUrl implements Action {
readonly type = SETREPLACEURL;
constructor(public replaceUrl:boolean) {}
}
export class SetFeatures implements Action {
readonly type = SETFEATURES;
constructor(public features: Array<Feature<Geometry>>) { }
}
export class SetLayerValuesLocation implements Action {
readonly type = SETLAYERVALUESLOCATION;
constructor(public x:number, public y:number) { }
}
export class ToggleLayerValuesEnabled implements Action {
readonly type = TOGGLELAYERVALUESENABLED;
constructor() { }
}
export class GetLayerValue implements Action {
readonly type = GETLAYERVALUE;
constructor(public itemLayer:IItemLayer,public x:number,public y:number) { }
}
export class GetLayerValueSuccess implements Action {
readonly type = GETLAYERVALUESUCCESS;
constructor(public layervalue:ILayervalue) { }
}
export class ToggleShowDataLayerSlide implements Action {
readonly type = TOGGLESHOWDATALAYERSLIDE;
constructor() {}
}
export class SetViewState implements Action {
readonly type = SETVIEWSTATE;
constructor(public enabled:boolean) {}
}
export class ClearFeatures implements Action {
readonly type = CLEARFEATURES;
constructor() {}
}
export class SetPanelExtraWide implements Action {
readonly type = SETPANELEXTRAWIDE;
constructor(public panelExtraWide:boolean) {}
}
export type Actions = SetMapState
| Init
| Clear
| SetParent
| StartSearch
| StartSearchSuccess
| ClickFeature
| SelectFeature
| SelectItem
| SelectItemSuccess
| SelectTemporalItemsSuccess
| NextTemporal
| PreviousTemporal
| SelectTemporal
| AddFeatureSuccess
| UpdateFeatureSuccess
| ExpandSearch
| CollapseSearch
| SetExtent
| SetQueryState
| SetTimeSpan
| AddLayer
| RemoveLayer
| ClearLayers
| SetVisibility
| SetOpacity
| SetLayerIndex
| LoadBaseLayers
| LoadBaseLayersSuccess
| SelectBaseLayer
| SelectOverlayLayer
| ZoomToExtent
| SetState
| SetViewExtent
| DoQuery
| SetStyle
| ShowLayerSwitcher
| SetReplaceUrl
| SetFeatures
| SetSelectedItemLayer
| SetLayerValuesLocation
| ToggleLayerValuesEnabled
| GetLayerValueSuccess
| GetLayerValue
| SetPeriod
| ToggleShowDataLayerSlide
| SetViewState
| ClearFeatures
| SetPanelExtraWide;

View File

@ -1,29 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MapComponent } from './components/map/map.component';
import { AuthGuard } from '@farmmaps/common';
const routes = [
{
path: '',
component: MapComponent
},
{
path: ':xCenter/:yCenter/:zoom/:rotation/:baseLayer',
component: MapComponent
},
{
path: ':xCenter/:yCenter/:zoom/:rotation/:baseLayer/:queryState',
component: MapComponent
},
{
path: ':queryState',
component: MapComponent
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class MapRoutingModule { }

View File

@ -1,289 +0,0 @@
import { NgModule ,ModuleWithProviders} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
//external modules
import { AngularOpenlayersModule } from 'ng-openlayers';
import { StoreModule, ActionReducer, MetaReducer } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
//common modules
import { AppCommonModule } from '@farmmaps/common';
import { MODULE_NAME } from './module-name';
import * as mapReducers from './reducers/map.reducer';
import * as mapActions from './actions/map.actions';
import * as mapEffects from './effects/map.effects';
import { IMapState} from './models/map.state';
import { ISelectedFeatures } from './models/selected.features';
import { IItemLayer,ItemLayer,ITemporalItemLayer,TemporalItemLayer } from './models/item.layer';
import { IClickedFeature } from './models/clicked.feature';
import { IPeriodState } from './models/period.state';
// components
import { GpsLocation} from './components/aol/gps-location/gps-location.component';
import {FeatureListFeatureCropfieldComponent } from './components/feature-list-feature-cropfield/feature-list-feature-cropfield.component';
import { FeatureListFeatureCroppingschemeComponent} from './components/feature-list-feature-croppingscheme/feature-list-feature-croppingscheme.component';
import { ItemWidgetListComponent} from './components/item-widget-list/item-widget-list.component';
import { AbstractItemListItemComponent, ItemListItemComponent, AbstractItemWidgetComponent } from './components/item-list-item/item-list-item.component';
import { ItemListItemContainerComponent } from './components/item-list-item-container/item-list-item-container.component';
import { AbstractItemListComponent,ItemListComponent} from './components/item-list/item-list.component';
import { AbstractSelectedItemComponent, SelectedItemComponent } from './components/selected-item/selected-item.component';
import { SelectedItemCropfieldComponent } from './components/selected-item-cropfield/selected-item-cropfield.component';
import { SelectedItemGeotiffComponent } from './components/selected-item-geotiff/selected-item-geotiff.component';
import { SelectedItemTemporalComponent} from './components/selected-item-temporal/selected-item-temporal.component';
import {SelectedItemShapeComponent } from './components/selected-item-shape/selected-item-shape.component';
import { SelectedItemContainerComponent } from './components/selected-item-container/selected-item-container.component';
import { AbstractFeatureListFeatureComponent, FeatureListFeatureComponent } from './components/feature-list-feature/feature-list-feature.component';
import {FeatureListFeatureContainerComponent } from './components/feature-list-feature-container/feature-list-feature-container.component';
import { FeatureListCroppingschemeComponent } from './components/feature-list-croppingscheme/feature-list-croppingscheme.component';
import {FeatureListCropfieldComponent } from './components/feature-list-cropfield/feature-list-cropfield.component';
import {FeatureListContainerComponent } from './components/feature-list-container/feature-list-container.component';
import { WidgetHostDirective} from './components/widget-host/widget-host.directive';
import { FeatureListComponent,AbstractFeatureListComponent} from './components/feature-list/feature-list.component';
import { FileDropTargetComponent } from './components/aol/file-drop-target/file-drop-target.component';
import { ItemVectorSourceComponent } from './components/aol/item-vector-source/item-vector-source.component';
import { ItemLayersComponent } from './components/aol/item-layers/item-layers.component';
import { ZoomToExtentComponent } from './components/aol/zoom-to-extent/zoom-to-extent.component';
import { RotationResetComponent } from './components/aol/rotation-reset/rotation-reset.component';
import { LayerListComponent } from './components/aol/layer-list/layer-list.component';
import { MetaDataModalComponent } from './components/meta-data-modal/meta-data-modal.component';
import { SelectPeriodModalComponent } from './components/select-period-modal/select-period-modal.component';
import { MapComponent } from './components/map/map.component';
import { MapSearchComponent } from './components/map-search/map-search.component';
import { MapRoutingModule } from './common-map-routing.module';
import { LegendComponent } from './components/legend/legend.component';
import { LayerVectorImageComponent } from './components/aol/layer-vector-image/layer-vector-image.component';
import {FeatureIconService} from './services/feature-icon.service';
import { GeolocationService } from './services/geolocation.service';
import {DeviceOrientationService} from './services/device-orientation.service';
import { TemporalService} from './services/temporal.service';
import { WidgetStatusComponent } from './components/widget-status/widget-status.component';
import { ForChild} from './components/for-item/for-child.decorator';
import {ForItemType } from './components/for-item/for-itemtype.decorator';
import { ForSourceTask} from './components/for-item/for-sourcetask.decorator';
import { ForPackage } from './components/for-item/for-package.decorator';
import { PanToLocation} from './components/aol/pan-to-location/pan-to-location.component';
import {LayerSwitcher} from './components/layer-switcher/layer-switcher.component';
import {HistogramDetailsComponent} from './components/legend/histogram-details/histogram-details.component';
import {StatisticsDetailsComponent} from './components/legend/statistics-details/statistics-details.component';
import { ifZoomToShowDirective} from './components/if-zoom-to-show/if-zoom-to-show.directive';
import { ZoomToShowAlert} from './components/zoom-to-show-alert/zoom-to-show-alert.component';
import { LayerValuesComponent } from './components/aol/layer-values/layer-values.component';
import { GeometryThumbnailComponent } from './components/feature-thumbnail/feature-thumbnail.component';
export function LocalStorageSync(reducer: ActionReducer<any>): ActionReducer<any> {
const r = function(state, action) {
const r2 = reducer(state, action);
if(action.type == "@ngrx/store/update-reducers") {
const ms = window.localStorage.getItem(MODULE_NAME+"_mapState");
if(ms) {
r2["mapState"] = JSON.parse(ms);
}
const sp = window.localStorage.getItem(MODULE_NAME+"_searchPeriod");
if(sp) {
const p = JSON.parse(sp);
r2["period"] = { startDate: new Date(Date.parse(p.startDate)),endDate:new Date(Date.parse(p.endDate))};
}
}
if(action.type == "[Map] MapState" || action.type == "[Map] SetState") {
window.localStorage.setItem(MODULE_NAME + "_mapState",JSON.stringify(r2["mapState"]));
}
if(action.type == "[Map] SetPeriod" ) {
window.localStorage.setItem(MODULE_NAME + "_searchPeriod",JSON.stringify(r2["period"]));
}
return r2;
};
return r;
}
const metaReducers: Array<MetaReducer<any, any>> = [LocalStorageSync];
export {
mapEffects,
mapReducers,
mapActions,
ZoomToExtentComponent,
ItemVectorSourceComponent,
ItemLayersComponent,
FileDropTargetComponent,
MapComponent,
MetaDataModalComponent,
RotationResetComponent,
MapSearchComponent,
SelectPeriodModalComponent,
LayerListComponent,
LegendComponent,
LayerVectorImageComponent,
FeatureListComponent,
WidgetHostDirective,
FeatureListContainerComponent,
FeatureListCroppingschemeComponent,
FeatureListCropfieldComponent,
FeatureListFeatureContainerComponent,
FeatureListFeatureComponent,
FeatureListFeatureCroppingschemeComponent,
FeatureListFeatureCropfieldComponent,
SelectedItemContainerComponent,
SelectedItemComponent,
SelectedItemCropfieldComponent,
SelectedItemGeotiffComponent,
SelectedItemTemporalComponent,
SelectedItemShapeComponent,
ItemListItemComponent,
ItemListItemContainerComponent,
ItemListComponent,
ItemWidgetListComponent,
WidgetStatusComponent,
GpsLocation,
PanToLocation,
LayerSwitcher,
AbstractFeatureListComponent,
AbstractFeatureListFeatureComponent,
AbstractSelectedItemComponent,
AbstractItemWidgetComponent,
AbstractItemListItemComponent,
AbstractItemListComponent,
FeatureIconService,
GeolocationService,
DeviceOrientationService,
TemporalService,
IMapState,
ISelectedFeatures,
IItemLayer,
ItemLayer,
IPeriodState,
ForChild,
ForItemType,
ForSourceTask,
ForPackage ,
ITemporalItemLayer,
TemporalItemLayer,
ifZoomToShowDirective,
ZoomToShowAlert,
IClickedFeature,
GeometryThumbnailComponent
}
@NgModule({
imports: [
CommonModule,
AngularOpenlayersModule,
MapRoutingModule,
StoreModule.forFeature(MODULE_NAME, mapReducers.reducer, { metaReducers: metaReducers }),
EffectsModule.forFeature([mapEffects.MapEffects]),
NgbModule,
FormsModule,
ReactiveFormsModule,
AppCommonModule
],
declarations: [
ZoomToExtentComponent,
ItemVectorSourceComponent,
ItemLayersComponent,
FileDropTargetComponent,
MapComponent,
MetaDataModalComponent,
RotationResetComponent,
MapSearchComponent,
SelectPeriodModalComponent,
LayerListComponent,
LegendComponent,
LayerVectorImageComponent,
FeatureListComponent,
WidgetHostDirective,
FeatureListContainerComponent,
FeatureListCroppingschemeComponent,
FeatureListCropfieldComponent,
FeatureListFeatureContainerComponent,
FeatureListFeatureComponent,
FeatureListFeatureCroppingschemeComponent,
FeatureListFeatureCropfieldComponent,
SelectedItemContainerComponent,
SelectedItemComponent,
SelectedItemCropfieldComponent,
SelectedItemGeotiffComponent,
SelectedItemTemporalComponent,
SelectedItemShapeComponent,
ItemListItemComponent,
ItemListItemContainerComponent,
ItemListComponent,
ItemWidgetListComponent,
WidgetStatusComponent,
GpsLocation,
PanToLocation,
LayerSwitcher,
HistogramDetailsComponent,
StatisticsDetailsComponent,
ifZoomToShowDirective,
ZoomToShowAlert,
LayerValuesComponent,
GeometryThumbnailComponent
],
exports: [
ItemVectorSourceComponent,
ItemLayersComponent,
FileDropTargetComponent,
MetaDataModalComponent,
MapComponent,
GpsLocation,
PanToLocation,
LayerSwitcher,
FeatureListFeatureComponent,
FeatureListFeatureCropfieldComponent,
FeatureListFeatureCroppingschemeComponent,
SelectedItemContainerComponent,
SelectedItemComponent,
SelectedItemCropfieldComponent,
SelectedItemGeotiffComponent,
SelectedItemTemporalComponent,
SelectedItemShapeComponent,
ItemListItemComponent,
ItemListItemContainerComponent,
ItemListComponent,
ItemWidgetListComponent,
WidgetStatusComponent,
RotationResetComponent,
MapSearchComponent,
SelectPeriodModalComponent,
LayerListComponent,
LegendComponent,
LayerVectorImageComponent,
FeatureListComponent,
WidgetHostDirective,
FeatureListContainerComponent,
FeatureListCroppingschemeComponent,
FeatureListCropfieldComponent,
FeatureListFeatureContainerComponent,
ZoomToExtentComponent,
ifZoomToShowDirective,
ZoomToShowAlert,
GeometryThumbnailComponent
],
providers: [
FeatureIconService,
GeolocationService,
DeviceOrientationService,
TemporalService,
{ provide: AbstractFeatureListComponent, useClass: FeatureListCroppingschemeComponent, multi: true },
{ provide: AbstractFeatureListComponent, useClass: FeatureListCropfieldComponent, multi: true },
{ provide: AbstractFeatureListFeatureComponent, useClass: FeatureListFeatureComponent, multi: true },
{ provide: AbstractFeatureListFeatureComponent, useClass: FeatureListFeatureCroppingschemeComponent, multi: true },
{ provide: AbstractFeatureListFeatureComponent, useClass: FeatureListFeatureCropfieldComponent, multi: true },
{ provide: AbstractSelectedItemComponent, useClass: SelectedItemComponent, multi: true },
{ provide: AbstractSelectedItemComponent, useClass: SelectedItemCropfieldComponent, multi: true },
{ provide: AbstractSelectedItemComponent, useClass: SelectedItemGeotiffComponent, multi: true },
{ provide: AbstractSelectedItemComponent, useClass: SelectedItemTemporalComponent, multi: true },
{ provide: AbstractSelectedItemComponent, useClass: SelectedItemShapeComponent, multi: true },
{ provide: AbstractItemListItemComponent, useClass: ItemListItemComponent, multi: true },
{ provide: AbstractItemListComponent, useClass: ItemListComponent, multi: true }
]
})
export class AppCommonMapModule {
}

View File

@ -1,73 +0,0 @@
import { Component, Input, OnDestroy, OnInit, EventEmitter, Output, Inject } from '@angular/core';
import { MapComponent } from 'ng-openlayers';
import * as proj from 'ol/proj';
import {Point,Geometry} from 'ol/geom';
import { GeoJSON } from 'ol/format';
import { Feature} from 'ol';
export interface IDroppedFile {
files: any,
event: any,
geometry: any
parentCode: string;
}
@Component({
selector: 'fm-map-file-drop-target',
template: ''
})
export class FileDropTargetComponent implements OnInit, OnDestroy {
element: Element;
@Output() onFileDropped = new EventEmitter<IDroppedFile>();
@Input() parentCode: string;
@Input() features: Array<Feature<Geometry>>;
constructor(private map: MapComponent) {
}
ngOnInit() {
this.element = this.map.instance.getViewport();
const other = this;
this.element.addEventListener('drop', this.onDrop, false);
this.element.addEventListener('dragover', this.preventDefault, false);
this.element.addEventListener('dragenter', this.preventDefault, false);
}
private onDrop = (event: DragEvent) => {
this.stopEvent(event);
const geojsonFormat = new GeoJSON();
let parentCode = this.parentCode;
const coordinate = this.map.instance.getEventCoordinate(event);
//coordinate = proj.transform(coordinate, this.map.instance.getView().getProjection(), 'EPSG:4326');
let geometry:Geometry = new Point(coordinate);
const hitFeatures = this.map.instance.getFeaturesAtPixel([event.pageX, event.pageY]);
const hitFeature = hitFeatures && hitFeatures.length > 0 ? hitFeatures[0] : null;
if (hitFeature) {
if (hitFeature.get("code")) {
parentCode = hitFeature.get("code");
}
geometry = geojsonFormat.readGeometry(geojsonFormat.writeGeometry(geometry)); // create copy instead of reference
}
const projectedGeometry = geometry.transform(this.map.instance.getView().getProjection(), 'EPSG:4326');
if (event.dataTransfer && event.dataTransfer.files) {
this.onFileDropped.emit({ files: event.dataTransfer.files, event: event, geometry: JSON.parse(geojsonFormat.writeGeometry(projectedGeometry)),parentCode:parentCode})
}
}
private preventDefault(event) {
event.preventDefault();
}
private stopEvent(event) {
event.stopPropagation();
event.preventDefault();
}
ngOnDestroy() {
this.element.removeEventListener('drop', this.onDrop);
this.element.removeEventListener('dragover', this.preventDefault);
this.element.removeEventListener('dragenter', this.preventDefault);
}
}

View File

@ -1,15 +0,0 @@
<div class="gps-location">
<svg #location height="1000" width="1000">
<defs>
<linearGradient id="grad1" x1="0%" y1="100%" x2="0%" y2="0%">
<stop offset="0%" class="stop1" />
<stop offset="100%" class="stop2" />
</linearGradient>
</defs>
<circle class="tolerance hidden" [ngClass]="{'hidden':!showTolerance}" cx="500" cy="500" stroke="none" [attr.r]="locTolerancePixels" />
<path class="heading hidden" [ngClass]="{'hidden': !showHeading }" stroke="none" [attr.d]="path" fill="url(#grad1)" [attr.transform]="rotate"></path>
<circle class="border" cx="500" cy="500" r="7" stroke="none" />
<circle class="center" cx="500" cy="500" r="6" stroke="none" />
</svg>
</div>

View File

@ -1,40 +0,0 @@
.gps-location {
display:none;
}
.center, .tolerance, .border {
stroke-width: 0;
}
.heading.hidden {
display: none;
}
.tolerance {
fill: var(--bs-primary);
fill-opacity:0.4;
}
.tolerance.hidden {
display: none
}
.border {
fill: var(--bs-white);
}
.center {
fill: var(--bs-primary);
}
.stop1 {
stop-color: var(--bs-primary);
stop-opacity:1;
}
.stop2 {
stop-color:var(--bs-primary);
stop-opacity: 0;
}

View File

@ -1,75 +0,0 @@
import { Component, OnInit, Input, ViewChild, ElementRef, OnChanges, SimpleChanges ,Host} from '@angular/core';
import { MapComponent } from 'ng-openlayers';
import Overlay from 'ol/Overlay';
import { fromLonLat, toLonLat } from 'ol/proj';
@Component({
selector: 'fm-map-gps-location',
templateUrl: './gps-location.component.html',
styleUrls: ['./gps-location.component.scss']
})
export class GpsLocation implements OnInit,OnChanges{
@Input() enable:boolean;
public instance: Overlay;
@Input() position: GeolocationPosition;
@Input() location: number[]=[0,0];
@Input() locationTolerance = 0;
@Input() showHeading = false;
@Input() showTolerance = false;
@Input() heading = 0;
@Input() headingTolerance = 0;
public locTolerancePixels = 0;
public path = "";
public rotate = "";
private resolution = 0;
initialized = false;
@ViewChild('location', { static: true }) locationElement: ElementRef;
constructor(private map: MapComponent) {
}
recalcLocationTolerance() {
this.locTolerancePixels = this.resolution >0? this.locationTolerance / this.resolution:0;
}
ngOnInit() {
this.instance = new Overlay({
stopEvent:false,
positioning: 'center-center',
position: fromLonLat( this.location),
element: this.locationElement.nativeElement
});
const x = Math.tan(this.headingTolerance * Math.PI / 180)*40;
const y = Math.cos(this.headingTolerance * Math.PI / 180) * 40;
const y1 = Math.round(500 - y);
const x1 = Math.round(500 - x);
const y2 = Math.round(y1);
const x2 = Math.round(500 + x);
this.path = "M " + x2 + " " + y2 + " A 45 45,0,0,0, " + x1 + " " + y1 + " L 493 500 L 507 500 Z";
this.rotate = "rotate(" + Math.round(this.heading) + " 500 500)";
this.locTolerancePixels = this.locationTolerance;
this.map.instance.addOverlay(this.instance);
this.map.instance.getView().on('change:resolution', (evt:any) => {
this.resolution = evt.target.get('resolution');
this.recalcLocationTolerance();
});
this.initialized = true;
}
ngOnChanges(changes: SimpleChanges) {
if (changes.position && this.instance) {
const p = changes.position.currentValue as GeolocationPosition;
if(p && this.initialized) {
this.instance.setPosition(fromLonLat([p.coords.longitude, p.coords.latitude]));
this.locationTolerance = p.coords.accuracy;
this.recalcLocationTolerance();
}
}
if(changes.heading && this.instance) {
this.rotate = "rotate(" + Math.round(changes.heading.currentValue) + " 500 500)";
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,529 +0,0 @@
import { Component, Host, Input, Output, EventEmitter,OnDestroy, OnInit, OnChanges, SimpleChanges, forwardRef } from '@angular/core';
import { LayerGroupComponent, MapComponent } from 'ng-openlayers';
import { ItemService,IItem,AppConfig } from '@farmmaps/common';
import { IItemLayer, ITemporalItemLayer} from '../../../models/item.layer';
import { ILayerData} from '../../../models/layer.data';
import { IRenderoutputTiles,IRenderoutputImage,IGradientstop,ILayer,IHistogram,IColor} from '../../../models/color.map';
import {Extent} from 'ol/extent';
import Projection from 'ol/proj/Projection';
import * as proj from 'ol/proj';
import * as loadingstrategy from 'ol/loadingstrategy';
import * as style from 'ol/style';
import {Tile,Layer,Image} from 'ol/layer';
import {XYZ,ImageStatic,OSM,BingMaps,TileWMS,TileArcGISRest,TileJSON,Source} from 'ol/source';
import {Vector as VectorSource} from 'ol/source';
import { Vector as VectorLayer } from 'ol/layer';
import { VectorImage as VectorImageLayer } from 'ol/layer';
import VectorTileSource from 'ol/source/VectorTile';
import VectorTileLayer from 'ol/layer/VectorTile';
import {GeoJSON,MVT} from 'ol/format';
import { Geometry } from 'ol/geom';
import BaseLayer from 'ol/layer/Base';
import Feature from 'ol/Feature';
@Component({
selector: 'fm-map-item-layers',
template: `<ng-content></ng-content>`,
providers: [
{ provide: LayerGroupComponent, useExisting: forwardRef(() => ItemLayersComponent) }
]
})
export class ItemLayersComponent extends LayerGroupComponent implements OnChanges, OnInit,OnDestroy {
@Input() itemLayers: IItemLayer[];
@Input() itemLayer: IItemLayer;
@Output() onFeatureSelected: EventEmitter<any> = new EventEmitter<any>();
@Output() onFeatureHover: EventEmitter<any> = new EventEmitter<any>();
@Output() onPrerender: EventEmitter<any> = new EventEmitter<any>();
private _apiEndPoint: string;
private initialized = false;
private mapEventHandlerInstalled = false;
private topLayerPrerenderEventhandlerInstalled = false;
private selectedFeatures = {};
private selectionLayer:Layer<Source> = null;
constructor(private itemService: ItemService, private map: MapComponent, public appConfig: AppConfig) {
super(map);
this._apiEndPoint = appConfig.getConfig("apiEndPoint");
}
private styleCache = {}
componentToHex(c) {
const hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
rgbaToHex(r, g, b,a) {
return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b) + this.componentToHex(a);
}
getColorFromGradient(layer: ILayer, value: number): IColor {
const gradient: IGradientstop[] = layer.renderer.colorMap.gradient;
const histogram: IHistogram = layer.renderer.band.histogram;
const index = (value - histogram.min) / histogram.max;
let min = gradient[0];
let max = gradient[gradient.length - 1];
for (let n = 0; n < gradient.length; n++) {
const s = gradient[n];
if (s.relativestop <= index && min.relativestop < s.relativestop && n < gradient.length - 1) min = s;
if (s.relativestop >= index && max.relativestop > s.relativestop && n > 0) max = s;
}
const i = index - min.relativestop;
const size = max.relativestop - min.relativestop;
const alpha = Math.round(min.color.alpha + ((max.color.alpha - min.color.alpha) * i / size));
const red = Math.round(min.color.red + ((max.color.red - min.color.red) * i / size));
const green = Math.round(min.color.green + ((max.color.green - min.color.green) * i / size));
const blue = Math.round(min.color.blue + ((max.color.blue - min.color.blue) * i / size));
return { alpha: alpha, red: red, green: green, blue: blue };
}
getColorForValue(layer: ILayer, value: number): IColor {
let color: IColor = { alpha:0,red:0,green:0,blue:0};
if(layer.renderer.colorMap.entries.length>0) {
color=layer.renderer.colorMap.noValue;
}
layer.renderer.colorMap.entries.forEach((entry) => {
if(entry.value==value) {
color =entry.color;
return;
}
});
return color;
}
getColor(item: IItem, layer: ILayer, feature): style.Style {
const value = layer.indexKey ? feature.get(layer.indexKey) : feature.get(layer.name);
const key = item.code + "_" + value;
if (!this.styleCache[key]) {
let color: IColor;
if(layer.renderer.colorMap.colormapType == "manual") {
color = this.getColorForValue(layer, value);
} else {
color = this.getColorFromGradient(layer, value);
}
this.styleCache[key] = new style.Style(
{
image: new style.Circle({
fill: new style.Fill({
color: this.rgbaToHex(color.red, color.green, color.blue, color.alpha)
}),
radius: 3
}),
fill: new style.Fill({
color: this.rgbaToHex(color.red, color.green, color.blue, color.alpha)
}),
stroke: new style.Stroke({
color: this.rgbaToHex(color.red, color.green, color.blue, 255),
width: 1.25
}),
});
}
return this.styleCache[key];
}
createGeotiffLayer(item:IItem,itemLayer:IItemLayer):Layer<Source> {
let layerIndex = -1;
let layer: Layer<Source> = null;
layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : item.data.layers[0].index;
const source = new XYZ({ maxZoom: 19, minZoom: 1, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${Date.parse(item.updated)}` });
layer = new Tile({ source: source });
const data = item.data;
const l = (data && data.layers && data.layers.length > 0) ? data.layers[0] : null;
if (l && l.rendering && l.rendering.renderoutputType == "Tiles") {
const rt = l.rendering as IRenderoutputTiles;
const source = new XYZ({crossOrigin: 'use-credentials', maxZoom: rt.maxzoom, minZoom: rt.minzoom, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${Date.parse(item.updated)}` });
layer = new Tile({ source: source });
}
if (l && l.rendering && l.rendering.renderoutputType == "Image") {
const ri = l.rendering as IRenderoutputImage;
const source = new ImageStatic({ imageExtent:ri.extent,projection:'EPSG:3857', crossOrigin: 'use-credentials', url: `${this._apiEndPoint}/api/v1/items/${item.code}/mapimage/${layerIndex}?v=${Date.parse(item.updated)}` });
layer = new Image({ source: source });
}
return layer;
}
createShapeLayer(item:IItem,itemLayer:IItemLayer):Layer<Source> {
let layerIndex = -1;
let layer: Layer<Source> = null;
layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : item.data.layers[0].index;
const data = item.data;
const l:ILayer = (data && data.layers && data.layers.length > 0) ? data.layers[layerIndex] : null;
if (l && l.rendering && l.rendering.renderoutputType == "VectorTiles") {
var rt = l.rendering as IRenderoutputTiles;
layer = new VectorTileLayer({
declutter: true,
source: new VectorTileSource({
maxZoom: rt.maxzoom,
minZoom: rt.minzoom,
format: new MVT(),
url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/{z}/{x}/{y}.pbf?v=${Date.parse(item.updated)}`
}),
style: (feature) => {
return this.getColor(item,l, feature);
}
})
} else if (l && l.rendering && l.rendering.renderoutputType == "Tiles") {
var rt = l.rendering as IRenderoutputTiles;
layer = new Tile({
source: new XYZ({
maxZoom: rt.maxzoom,
minZoom: rt.minzoom,
url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/image_tiles/${layerIndex}/{z}/{x}/{y}.png?v=${Date.parse(item.updated)}`
})
});
} else {
const __this = this;
const format = new GeoJSON();
const source = new VectorSource({
strategy: loadingstrategy.bbox,
loader: function (extent: Extent, resolution: number, projection: Projection) {
const source = this as VectorSource<Feature<Geometry>>;
__this.itemService.getItemFeatures(item.code, extent, projection.getCode(), layerIndex).subscribe(function (data) {
const features = format.readFeatures(data).filter(feature => feature instanceof Feature) as Feature[];
for (const f of features) {
if (f.get("code")) {
f.setId(f.get("code"));
}
}
source.addFeatures(features);
});
}
});
layer = new VectorImageLayer({
declutter: true,
source: source,
style: (feature) => {
const key =feature.get("code") + "_" + feature.get("color");
if (!this.styleCache[key]) {
const color = feature.get("color");
this.styleCache[key] = new style.Style(
{
fill: new style.Fill({
color: color
}),
stroke: new style.Stroke({
color: color,
width: 1.25
}),
image: new style.Circle({
fill: new style.Fill({
color: color
}),
stroke: new style.Stroke({
color: color,
width: 1.25
}),
radius: 5
}),
}
)
}
return this.styleCache[key];
}
});
}
if(l.minzoom) {
layer.setMinZoom(l.minzoom);
}
if(l.maxzoom) {
layer.setMaxZoom(l.maxzoom);
}
return layer;
}
createSelectionLayer(itemLayer:IItemLayer):Layer<Source> {
let layerIndex = -1;
const layer: Layer<Source> = null;
layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : itemLayer.item.data.layers[0].index;
const data = itemLayer.item.data;
const l:ILayer = (data && data.layers && data.layers.length > 0) ? data.layers[layerIndex] : null;
if (l && l.rendering && l.rendering.renderoutputType == "VectorTiles") {
return new VectorTileLayer({
renderMode: 'vector',
source: (itemLayer.layer as VectorTileLayer).getSource(),
style: (feature) => {
if (feature.getId() in this.selectedFeatures) {
return new style.Style(
{
stroke: new style.Stroke({
color: '#0d6efd',
width: 3
})
}
);
}
},
minZoom: itemLayer.layer.getMinZoom(),
maxZoom: itemLayer.layer.getMaxZoom()
});
}
return null;
}
createExternalLayer(item:IItem,itemLayer:IItemLayer):Layer<Source> {
const data = item.data as ILayerData;
let layer: Layer<Source> = null;
switch (data.interfaceType) {
case 'OSM': {
const source = new OSM();
layer = new Tile({ source: source });
break;
}
case 'BingMaps': {
const source = new BingMaps(data.options);
layer = new Tile({ source: source });
break;
}
case 'TileWMS': {
const source = new TileWMS(data.options);
layer = new Tile({ source: source });
break;
}
case 'TileJSON': {
const source = new TileJSON(data.options);
layer = new Tile({ source: source });
break;
}
case 'TileArcGISRest': {
const source = new TileArcGISRest(data.options);
layer = new Tile({ source: source });
break;
}
case 'VectorWFSJson': {
const source = new VectorSource({
format: new GeoJSON(),
url: function (extent) {
return (
data.options.url + '&srsname=' + data.projection +
'&bbox=' +
extent.join(',') +
',EPSG:3857'
);
},
strategy: loadingstrategy.bbox,
});
layer = new VectorLayer({ source: source });
break;
}
default: {
break;
}
}
return layer;
}
createLayer(itemLayer: IItemLayer): Layer<Source> {
let layer: Layer<Source> = null;
const layerIndex = -1;
if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.geotiff.processed') {
layer = this.createGeotiffLayer(itemLayer.item,itemLayer);
} else if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.shape.processed') {
layer = this.createShapeLayer(itemLayer.item,itemLayer);
} else if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.layer') {
layer = this.createExternalLayer(itemLayer.item,itemLayer);
}
if (layer) {
const geometry = new GeoJSON().readGeometry(itemLayer.item.geometry);
const extent = geometry ? proj.transformExtent(geometry.getExtent(), 'EPSG:4326', 'EPSG:3857') : null;
if (extent) layer.setExtent(extent);
}
return layer;
}
ngOnInit() {
super.ngOnInit();
if(this.itemLayers) {
this.updateLayers(this.itemLayers);
} else if(this.itemLayer) {
if(this.getItemlayer(this.itemLayer).item.itemType == 'vnd.farmmaps.itemtype.shape.processed') {
this.installMapEventHandler();
}
this.updateLayers([this.itemLayer])
} else {
this.updateLayers([]);
}
this.initialized=true;
}
installMapEventHandler() {
if(!this.mapEventHandlerInstalled) {
this.map.instance.on(['click', 'pointermove'],this.mapEventHandler);
this.mapEventHandlerInstalled=true;
}
}
unInstallMapEventHandler() {
if(this.mapEventHandlerInstalled) {
this.map.instance.un(['click', 'pointermove'],this.mapEventHandler);
this.mapEventHandlerInstalled=false;
}
}
installTopLayerPrerenderEventhandler(olLayer : Layer<Source>) {
if(!this.topLayerPrerenderEventhandlerInstalled && this.onPrerender.observers.length > 0 && olLayer) {
if(this.instance.getVisible()) {
olLayer.on('prerender',this.topLayerPrerenderEventhandler);
olLayer.on('postrender',this.topLayerPostrenderEventhandler);
this.topLayerPrerenderEventhandlerInstalled = true;
}
}
}
unInstallTopLayerPrerenderEventhandler() {
if(this.topLayerPrerenderEventhandlerInstalled && this.onPrerender.observers.length > 0 )
{
if(this.instance.getVisible()) {
const olLayers = this.instance.getLayers().getArray().forEach((l:any) => {
l.un('prerender',this.topLayerPrerenderEventhandler);
l.un('postrender',this.topLayerPostrenderEventhandler);
});
this.topLayerPrerenderEventhandlerInstalled = false;
}
}
}
addOrUpdateOlLayer(itemLayer:IItemLayer,index:number):Layer<Source> {
if(!itemLayer) return null;
const olLayers = this.instance.getLayers();
let layer = itemLayer.layer;
const olIndex = olLayers.getArray().indexOf(layer);
if (olIndex < 0) {
// New layer: we add it to the map
layer = this.createLayer(itemLayer);
if (layer) {
olLayers.insertAt(index, layer);
}
} else if (index !== olIndex) {
// layer has moved inside the layers list
olLayers.removeAt(olIndex);
olLayers.insertAt(index, layer);
}
if(layer) {
itemLayer.layer = layer;
layer.setOpacity(itemLayer.opacity);
layer.setVisible(itemLayer.visible);
}
return layer;
}
updateLayers(itemLayers: IItemLayer[] | IItemLayer) {
this.unInstallTopLayerPrerenderEventhandler();
let dataLayer = false;
let ils:IItemLayer[] = [];
if(Array.isArray(itemLayers)) {
ils = itemLayers;
} else {
dataLayer=true;
ils=[itemLayers];
}
const newLayers: Layer<Source>[] = [];
if (ils) {
ils.forEach((itemLayer, index) => {
if(itemLayer.item.itemType == 'vnd.farmmaps.itemtype.temporal') {
const il = itemLayer as ITemporalItemLayer;
const previousLayer = this.addOrUpdateOlLayer(il.previousItemLayer,newLayers.length);
if(previousLayer) newLayers.push(previousLayer);
const selectedLayer = this.addOrUpdateOlLayer(il.selectedItemLayer,newLayers.length);
if(selectedLayer) newLayers.push(selectedLayer);
const nextLayer = this.addOrUpdateOlLayer(il.nextItemLayer,newLayers.length);
if(nextLayer) newLayers.push(nextLayer);
this.installTopLayerPrerenderEventhandler(selectedLayer);
} else {
const layer = this.addOrUpdateOlLayer(itemLayer,newLayers.length);
if(layer) newLayers.push(layer);
this.installTopLayerPrerenderEventhandler(layer);
}
});
// Remove the layers that have disapeared from childrenLayers
const olLayers = this.instance.getLayers();
while(olLayers.getLength() > newLayers.length) {
olLayers.removeAt(newLayers.length);
}
this.selectionLayer=null;
if(this.mapEventHandlerInstalled && ils.length==1 && this.getItemlayer(itemLayers[0]).item.itemType == 'vnd.farmmaps.itemtype.shape.processed') {
this.selectionLayer = this.createSelectionLayer(this.getItemlayer(itemLayers[0]));
if(this.selectionLayer) olLayers.push(this.selectionLayer)
}
}
}
topLayerPrerenderEventhandler = (event) => {
this.onPrerender.emit(event);
}
topLayerPostrenderEventhandler = (event) => {
const ctx = event.context;
ctx.restore();
}
mapEventHandler = (event) => {
// select only when having observers
if(event.type === 'click' && !this.onFeatureSelected.observers.length) return;
if(event.type === 'pointermove' && !this.onFeatureHover.observers.length) return;
const itemLayer= this.getItemlayer(this.itemLayer);
if(itemLayer && itemLayer.layer) {
this.selectedFeatures = {};
if(itemLayer.layer ) {
const minZoom = itemLayer.layer.getMinZoom();
const currentZoom = this.map.instance.getView().getZoom();
if(currentZoom>minZoom) {
itemLayer.layer.getFeatures(event.pixel).then((features) => {
if(!features.length) {
this.onFeatureHover.emit(null);
return;
}
const fid = features[0].getId();
const feature = features[0];
if(event.type === 'pointermove') {
this.selectedFeatures[fid] = features[0];
this.onFeatureHover.emit({ "feature": feature,"itemCode":itemLayer.item.code });
} else {
this.onFeatureSelected.emit({ "feature": feature,"itemCode":itemLayer.item.code });
}
})
if(this.selectionLayer) this.selectionLayer.changed();
}
}
}
}
getItemlayer(itemLayer:IItemLayer):IItemLayer {
if((itemLayer as ITemporalItemLayer).selectedItemLayer) return (itemLayer as ITemporalItemLayer).selectedItemLayer;
return itemLayer;
}
ngOnChanges(changes: SimpleChanges) {
if (this.instance && this.initialized) {
if (changes['itemLayers']) {
const itemLayers = changes['itemLayers'].currentValue as IItemLayer[];
this.updateLayers(itemLayers);
}
if (changes['itemLayer']) {
const itemLayer = changes['itemLayer'].currentValue as IItemLayer;
this.itemLayer = itemLayer
if(itemLayer) {
if(this.getItemlayer(this.itemLayer).item.itemType == 'vnd.farmmaps.itemtype.shape.processed') {
this.installMapEventHandler();
}
this.updateLayers([itemLayer]);
} else {
this.unInstallMapEventHandler();
this.updateLayers([]);
}
}
}
}
ngOnDestroy() {
this.unInstallMapEventHandler();
super.ngOnDestroy();
}
}

View File

@ -1,260 +0,0 @@
import { Component, Host, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges, forwardRef, Inject, InjectionToken, OnDestroy, LOCALE_ID } from '@angular/core';
import { LayerVectorComponent, SourceVectorComponent, MapComponent } from 'ng-openlayers';
import { ItemService, ItemTypeService, IItem, IItemType, FolderService } from '@farmmaps/common';
import { Feature } from 'ol';
import { Point, Geometry } from 'ol/geom';
import { MapBrowserEvent } from 'ol';
import { Types } from 'ol/MapBrowserEventType';
import * as style from 'ol/style';
import * as color from 'ol/color';
import * as loadingstrategy from 'ol/loadingstrategy';
import * as condition from 'ol/events/condition';
import * as extent from 'ol/extent';
import { Vector, Cluster, Source } from 'ol/source';
import { Layer } from 'ol/layer';
import { GeoJSON } from 'ol/format';
import { Select } from 'ol/interaction';
import { IStyles } from '../../../models/style.cache';
import { FeatureIconService } from '../../../services/feature-icon.service';
import { Subscription } from 'rxjs';
import { getCenter } from 'ol/extent';
import { formatNumber } from '@angular/common';
@Component({
selector: 'fm-map-item-source-vector',
template: `<ng-content></ng-content>`,
providers: [
{ provide: SourceVectorComponent, useExisting: forwardRef(() => ItemVectorSourceComponent) }
]
})
export class ItemVectorSourceComponent extends SourceVectorComponent implements OnInit, OnDestroy, OnChanges {
instance: Vector<Feature<Geometry>>;
private _format: GeoJSON;
private _select: Select;
private _hoverSelect: Select;
private _iconScale = 0.05;
@Input() features: Array<Feature<Geometry>>;
@Input() selectedFeature: Feature<Geometry>;
@Input() selectedItem: IItem;
@Input() styles: IStyles;
@Output() onFeatureSelected: EventEmitter<Feature<Geometry>> = new EventEmitter<Feature<Geometry>>();
@Output() onFeatureHover: EventEmitter<Feature<Geometry>> = new EventEmitter<Feature<Geometry>>();
private stylesCache: IStyles = {};
private sub: Subscription;
private displayMapFeatureSettings: { [code: string]: string[] } = defaultDisplayMapFeatureSettings();
constructor(@Host() private layer: LayerVectorComponent, private itemService: ItemService, private map: MapComponent, private itemTypeService: ItemTypeService, private featureIconService$: FeatureIconService, private folderService: FolderService, @Inject(LOCALE_ID) private locale: string) {
super(layer);
this._format = new GeoJSON();
}
geometry(feature: Feature<Geometry>) {
const view = this.map.instance.getView();
const resolution = view.getResolution();
let geometry = feature.getGeometry();
const e = geometry.getExtent();
//var size = Math.max((e[2] - e[0]) / resolution, (e[3] - e[1]) / resolution);
if (resolution > 12) {
geometry = new Point(extent.getCenter(e));
}
return geometry;
}
getSelectedStyle(feature: Feature<Geometry>): style.Style {
const key = feature.get('itemType') + "_selected";
let evaluatedStyle: style.Style = undefined;
const styleEntry = this.stylesCache[key];
if (styleEntry) {
if (typeof styleEntry === 'function') {
evaluatedStyle = styleEntry(feature);
} else {
evaluatedStyle = styleEntry;
}
} else {
evaluatedStyle = this.stylesCache["selected"] as style.Style;
}
if (evaluatedStyle) {
evaluatedStyle.setGeometry((feature: Feature<Geometry>) => this.geometry(feature));
}
return evaluatedStyle as style.Style
}
ngOnInit() {
this.sub = this.folderService.getFolder('my_settings').subscribe(
userSettingsRoot => {
if (userSettingsRoot == undefined) return;
this.itemService.getChildItemList(userSettingsRoot.code, 'vnd.farmmaps.itemtype.settings.general').subscribe(
items => {
if (items && items.length > 0 && items[0].data?.displayMapFeatureSettings) {
this.displayMapFeatureSettings = items[0].data?.displayMapFeatureSettings;
}
}
)
}
);
this.strategy = loadingstrategy.bbox;
this.format = new GeoJSON();
this._select = new Select({
style: null,
hitTolerance: 10,
layers: [this.layer.instance as Layer<Source>]
});
this._hoverSelect = new Select({
style: (feature: Feature<Geometry>) => {
return this.getSelectedStyle(feature);
},
hitTolerance: 10,
condition: (e: MapBrowserEvent<UIEvent>) => {
return e.type == 'pointermove';
},
layers: [this.layer.instance as Layer<Source>]
});
this.map.instance.addInteraction(this._select);
this.map.instance.addInteraction(this._hoverSelect);
this._select.on('select', (e) => {
if (e.selected.length > 0 && e.selected[0]) {
this.onFeatureSelected.emit(e.selected[0]);
} else {
this.onFeatureSelected.emit(null);
}
});
this._hoverSelect.on('select', (e) => {
if (e.selected.length > 0 && e.selected[0]) {
this.onFeatureHover.emit(e.selected[0]);
} else {
this.onFeatureHover.emit(null);
}
});
this.instance = new Vector(this);
this.host.instance.setSource(this.instance);
this.host.instance.setStyle((feature) => {
const itemType = feature.get('itemType');
let key = itemType + (this.selectedItem ? "_I" : "");
if (!this.stylesCache[key]) {
if (this.itemTypeService.itemTypes[itemType]) {
const itemTypeEntry = this.itemTypeService.itemTypes[itemType];
const fillColor = color.asArray(itemTypeEntry.iconColor);
fillColor[3] = 0;
this.stylesCache[key] = new style.Style({
image: itemTypeEntry.icon ? new style.Icon({
anchor: [0.5, 1],
scale: 0.05,
src: this.featureIconService$.getIconImageDataUrl(itemTypeEntry.icon)
}) : null,
stroke: new style.Stroke({
color: 'red',
width: 1
}),
fill: new style.Fill({
color: fillColor
}),
geometry: (feature: Feature<Geometry>) => this.geometry(feature),
text: this.getDisplayTextForFeature(feature, this.map.instance.getView().getZoom())
});
} else {
key = 'file';
}
}
let evaluatedStyle = null;
const styleEntry = this.stylesCache[key];
if (typeof styleEntry === 'function') {
evaluatedStyle = styleEntry(feature);
} else {
evaluatedStyle = styleEntry;
}
if (evaluatedStyle && evaluatedStyle.geometry_ == null && !Array.isArray(evaluatedStyle)) {
evaluatedStyle.setGeometry((feature) => this.geometry(feature));
}
return evaluatedStyle;
});
}
ngOnDestroy(): void {
if (this.sub) this.sub.unsubscribe();
}
ngOnChanges(changes: SimpleChanges) {
if (changes["features"] && this.instance) {
this.instance.clear(true);
this._select.getFeatures().clear();
this.instance.addFeatures(changes["features"].currentValue);
}
if (changes["selectedFeature"] && this.instance) {
const features = this._hoverSelect.getFeatures();
const feature = changes["selectedFeature"].currentValue
//this.instance.clear(false);
//this.instance.addFeatures(features.getArray());
features.clear();
if (feature) {
//this.instance.removeFeature(feature);
features.push(feature)
}
}
if (changes["selectedItem"] && this.instance) {
const item = changes["selectedItem"].currentValue
if (item) {
this.map.instance.removeInteraction(this._hoverSelect);
} else {
this.map.instance.addInteraction(this._hoverSelect);
}
}
if (changes["styles"]) {
const styles = changes["styles"].currentValue;
for (const key in styles) {
if (styles.hasOwnProperty(key)) {
this.stylesCache[key] = styles[key];
}
}
}
}
getDisplayTextForFeature(feature: Feature<Geometry>, zoom: number, overrule?: style.Text) {
if (!feature) return null;
const propertiesToShow: string[] = this.displayMapFeatureSettings[feature.get('itemType')];
if (!propertiesToShow) return null;
if (propertiesToShow.length <= 0) return null;
if (zoom < 14) return null;
let displayText = '';
for (let i = 0; i < propertiesToShow.length; i++) {
let value = feature.get(propertiesToShow[i]);
switch (propertiesToShow[i]) {
case "area": value = formatNumber(value, this.locale, '0.1-2') + ' ha'; break;
case "centroid": {
if (feature.getGeometry()) {
const centroid = getCenter(feature.getGeometry().getExtent());
value = Math.round(centroid[0]) + ',' + Math.round(centroid[1]);
}
}
if (value) {
displayText += value + (i < propertiesToShow.length ? '\n' : '');
}
}
const styleText = new style.Text({
font: '13px Calibri,sans-serif',
fill: new style.Fill({ color: '#ffffff' }),
stroke: new style.Stroke({ color: '#000000', width: 2 }),
text: displayText
});
if (overrule) {
if (overrule.getFont()) styleText.setFont(overrule.getFont());
if (overrule.getFill()) styleText.setFill(overrule.getFill());
if (overrule.getStroke()) styleText.setStroke(overrule.getStroke());
}
return styleText;
}
}
}
function defaultDisplayMapFeatureSettings() {
return {
'vnd.farmmaps.itemtype.cropfield': ['name', 'cropTypeName', 'area']
};
}

View File

@ -1,31 +0,0 @@
<div>
<div class="layerlist" *ngIf="itemLayers.length > 0;else noLayers">
<div class="list-group">
<div *ngFor="let itemLayer of itemLayers" class="list-group-item list-group-item-action p-2 text-truncate" [ngClass]="{'active' : selectedLayer==itemLayer}">
<div (click)="handleSelectLayer($event,itemLayer)" [title]="itemLayer.item.name">{{itemLayer.item.name}}</div>
<div class="mt-1" *ngIf="selectedLayer==itemLayer && !baseLayers">
<span class="btn-group">
<a title="Toggle visibility"href="#" class="btn btn-light btn-sm" (click)="handleToggleVisibility($event,itemLayer)"><i class="fa" aria-hidden="true" [ngClass]="{'fa-eye':!itemLayer.visible,'fa-eye-slash':itemLayer.visible}"></i></a>
<a title="Transparency 25%" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.25)">25%</a>
<a title="Transparency 50%" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.5)">50%</a>
<a title="Transparency 75%" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.75)">75%</a>
<a title="No transparency" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,1)">100%</a>
</span>
<a href="#" title="Zoom to extent" class="btn btn-light btn-sm" (click)="handleZoomToExtent($event,itemLayer)"><i class="far fa-search-plus" aria-hidden="true"></i></a>
<span *ngIf="firstLayer(itemLayer)"><a href="#" title="Toggle legend" class="btn btn-light btn-sm" (click)="itemLayer.legendVisible=toggleLegend($event,itemLayer.legendVisible)"><i class="far fa-chart-bar" aria-hidden="true"></i></a></span>
<span *ngIf="!dataLayers" class="float-end"><a href="#" title="Remove overlay" class="btn btn-light btn-sm" (click)="handleDelete($event,itemLayer)"><i class="fas fa-layer-minus" aria-hidden="true"></i></a></span>
</div>
<div *ngIf="itemLayer.legendVisible">
<div class="card legend">
<fm-map-layer-legend [layer]="firstLayer(itemLayer)" (click)="handleLegendClick($event,itemLayer);" [histogramenabled]="true"></fm-map-layer-legend>
</div>
</div>
</div>
</div>
</div>
</div>
<ng-template #noLayers>
<div class="list-group">
<div class="list-group-item" i18n>No layers</div>
</div>
</ng-template>

View File

@ -1,18 +0,0 @@
.layerlist ul {
list-style:none;
padding:0;
}
.active span.btn.btn-lnk.p-0.border-0 {
color:white;
}
.btn-sm {
padding:0.25rem 0.3rem;
}
.legend {
margin-top:0.5rem;
color:black;
padding:0.25rem;
}

View File

@ -1,65 +0,0 @@
import { Component,Input,Output,EventEmitter } from '@angular/core';
import { IItemLayer } from '../../../models/item.layer';
@Component({
selector: 'fm-map-layer-list',
templateUrl: './layer-list.component.html',
styleUrls: ['./layer-list.component.scss']
})
export class LayerListComponent {
@Input() itemLayers: IItemLayer[] = [];
@Input() baseLayers = false;
@Input() dataLayers = false;
@Output() onToggleVisibility = new EventEmitter<IItemLayer>();
@Output() onSetOpacity = new EventEmitter<{layer: IItemLayer,opacity:number }>();
@Output() onDelete = new EventEmitter<IItemLayer>();
@Output() onZoomToExtent = new EventEmitter<IItemLayer>();
@Output() onSelectLayer = new EventEmitter<IItemLayer>();
@Input() selectedLayer: IItemLayer;
constructor( ) {
}
handleDelete(event:MouseEvent, item:IItemLayer) {
this.onDelete.emit(item);
event.preventDefault();
}
handleToggleVisibility(event:MouseEvent, item: IItemLayer) {
this.onToggleVisibility.emit(item);
item.legendVisible = item.visible && item.legendVisible;
event.preventDefault();
}
handleSetOpacity(event: MouseEvent, layer: IItemLayer,opacity:number) {
this.onSetOpacity.emit({ layer,opacity });
event.preventDefault();
}
handleZoomToExtent(event: MouseEvent, item: IItemLayer) {
this.onZoomToExtent.emit(item);
event.preventDefault();
}
handleSelectLayer(event: MouseEvent, item: IItemLayer) {
this.onSelectLayer.emit(item);
event.preventDefault();
}
firstLayer(item: IItemLayer): any {
if (item && item.item && item.item.data && item.item.data.layers && item.item.data.layers.length > 0) return item.item.data.layers[0];
return null;
}
toggleLegend(event: MouseEvent, lg: boolean) {
event.preventDefault();
return !lg;
}
handleLegendClick(event: MouseEvent, item: IItemLayer) {
this.onSelectLayer.emit(item);
this.onZoomToExtent.emit(item);
event.preventDefault();
}
}

View File

@ -1,18 +0,0 @@
<div #layerValues class="layer-values">
<div class="cross" *ngIf="enabled$ | async">
<div class="pointer"></div>
<div class="values-container border border-dark rounded p-2" *ngIf="(layerValues$ | async ) as layers">
<div class="lonlat pb-2 "><span class="font-weight-bold">{{lonlat$}}</span><i class="ms-2 fal fa-copy" (click)="copyToClipboard()"></i> </div>
<ul class="value-list p-0 mb-0" *ngIf="layers.length>0 ;else no_data">
<li class="border-top pt-1 pb-1 value" *ngFor="let layerValue of layers">
<div>{{layerValue.layerName}}</div>
<div>{{layerValue.date|date}}</div>
<div><span *ngIf="layerValue.quantity"><span class="me-1">{{layerValue.quantity}}</span> </span><span class="me-1 font-weight-bold">{{getScaledValue(layerValue)}}</span><span>{{layerValue.unit}}</span></div>
</li>
</ul>
<ng-template #no_data>
<div i18n class="border-top pt-1 pb-1">No data at location</div>
</ng-template>
</div>
</div>
</div>

View File

@ -1,37 +0,0 @@
.layer-values {
position: absolute;
left: 50%;
top: 30%;
}
.cross {
display: block;
position: relative;
width: 1em;
height: 1em;
left: -0.5em;
top: -0.5em;
}
.values-container {
position: relative;
background-color: white;
left: calc( 1em - 1px);
top: -1.3em;
min-width: 15em;
}
.value-list {
list-style: none;
}
.pointer {
position: relative;
width: 0px;
height: 0px;
left: 0.5em;
border-top: 0.5em solid transparent;
border-bottom: 0.5em solid transparent;
border-right: 0.5em solid black;
}

View File

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LayerValuesComponent } from './layer-values.component';
describe('LayerValuesComponent', () => {
let component: LayerValuesComponent;
let fixture: ComponentFixture<LayerValuesComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LayerValuesComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LayerValuesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,70 +0,0 @@
import { Component, OnInit, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { IItemLayer } from '../../../models/item.layer';
import { Store } from '@ngrx/store';
import * as mapReducers from '../../../reducers/map.reducer';
import * as mapActions from '../../../actions/map.actions';
import { MapComponent } from 'ng-openlayers';
import { ILayervalue } from '../../../models/layer.value';
import { Observable, interval, Subject } from 'rxjs';
import { debounce, throttle } from 'rxjs/operators';
import { toLonLat } from 'ol/proj';
import { toStringHDMS } from 'ol/coordinate';
import { ClipboardService } from 'ngx-clipboard'
import { GeoJSON, WKT } from 'ol/format';
import { Point } from 'ol/geom';
@Component({
selector: 'fm-map-layer-values',
templateUrl: './layer-values.component.html',
styleUrls: ['./layer-values.component.scss']
})
export class LayerValuesComponent implements OnInit, AfterViewInit {
@ViewChild('layerValues') containerRef: ElementRef;
offsetX$ = 0;
offsetY$ = 0;
lonlat$ = "";
wkt$ = "";
layerValues$: Observable<Array<ILayervalue>> = this.store.select(mapReducers.selectGetLayerValues);
enabled$: Observable<boolean> = this.store.select(mapReducers.selectGetLayerValuesEnabled);
wktFormat$: WKT;
constructor(private store: Store<mapReducers.State>, private map: MapComponent, private clipboardService$: ClipboardService) {
this.wktFormat$ = new WKT();
}
ngOnInit(): void {
}
moveEndSubject = new Subject<any>();
ngAfterViewInit(): void {
this.offsetY$ = this.containerRef.nativeElement.offsetTop;
this.offsetX$ = this.containerRef.nativeElement.offsetLeft;
this.map.instance.on('moveend', () => {
this.moveEndSubject.next({});
});
this.moveEndSubject.pipe(throttle(ev => interval(100))).subscribe(() => this.updateValuesLocation());
}
updateValuesLocation() {
const xy = this.map.instance.getCoordinateFromPixel([this.offsetX$, this.offsetY$])
const lonlat = toLonLat(xy);
this.wkt$ = this.wktFormat$.writeGeometry(new Point(lonlat))
this.lonlat$ = toStringHDMS(lonlat);
this.store.dispatch(new mapActions.SetLayerValuesLocation(xy[0], xy[1]));
}
copyToClipboard() {
this.clipboardService$.copy(this.wkt$);
}
public getScaledValue(layerValue: ILayervalue): number {
let v = layerValue.value;
if (layerValue.scale && layerValue.scale != 0) {
v = layerValue.scale * layerValue.value;
}
return v;
}
}

View File

@ -1,31 +0,0 @@
import { Component, OnDestroy, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { LayerVectorComponent, MapComponent } from 'ng-openlayers';
import RenderType from 'ol/layer/Vector';
import { Vector as VectorSource } from 'ol/source';
import { Geometry } from 'ol/geom';
import Feature from 'ol/Feature';
@Component({
selector: 'fm-map-aol-layer-vector-image',
template: `
<ng-content></ng-content>
`,
})
export class LayerVectorImageComponent extends LayerVectorComponent implements OnInit, OnDestroy, OnChanges {
//public source: Vector;
@Input()
renderMode: RenderType<VectorSource<Feature<Geometry>>> | string = "image";
constructor(map: MapComponent) {
super(map);
}
ngOnInit() {
super.ngOnInit();
}
ngOnChanges(changes: SimpleChanges) {
super.ngOnChanges(changes);
}
}

View File

@ -1,13 +0,0 @@
<div (click)="handleClick($event)" class="btn btn-outline-primary gps-location">
<svg height="100%" width="100%" viewBox="0 0 96 96">
<g
id="XMLID_1_"><circle
class="pan-to" [ngClass]="{'pan-to-centered':centered(),'pan-to-disabled':disabled()}"
cx="48"
cy="48"
r="9.8000002"/><path
class="pan-to" [ngClass]="{'pan-to-centered':centered(),'pan-to-disabled':disabled()}"
d="M 80.5,44.8 H 73.8 C 72.3,33 63,23.7 51.3,22.2 v -6.7 h -6.5 v 6.7 C 33,23.7 23.7,33 22.2,44.8 h -6.7 v 6.5 h 6.7 C 23.7,63 33,72.3 44.8,73.8 v 6.7 h 6.5 V 73.8 C 63,72.3 72.3,63 73.8,51.3 h 6.7 z M 48,67.5 C 37.2,67.5 28.5,58.8 28.5,48 28.5,37.2 37.2,28.5 48,28.5 c 10.8,0 19.5,8.7 19.5,19.5 0,10.8 -8.7,19.5 -19.5,19.5 z"
inkscape:connector-curvature="0"/></g>
</svg>
</div>

View File

@ -1,34 +0,0 @@
.gps-location {
display:block;
width:2.5em;
height:2.5em;
background-color: var(--bs-body-bg);
background-size: contain;
margin-top:0.5em;
border-radius: 1.75em;
padding:0
}
.center, .tolerance, .border {
stroke-width: 0;
}
.pan-to {
fill: var(--bs-secondary);
}
div.gps-location:hover .pan-to {
fill: var(--bs-white);
}
.pan-to-centered {
fill: var(--bs-primary);
}
div.gps-location:hover .pan-to-centered {
fill: theme-color-level(primary, -10)
}
.pan-to.pan-to-disabled {
fill: var(--bs-gray-300);
}

View File

@ -1,84 +0,0 @@
import { Component, OnInit, Input, Host, OnChanges, SimpleChanges,ChangeDetectorRef } from '@angular/core';
import { MapComponent } from 'ng-openlayers';
import {IMapState} from '../../../models/map.state'
import {View} from 'ol';
import { fromLonLat } from 'ol/proj';
@Component({
selector: 'fm-map-pan-to-location',
templateUrl: './pan-to-location.component.html',
styleUrls: ['./pan-to-location.component.scss']
})
export class PanToLocation implements OnInit,OnChanges{
view: View;
map: MapComponent;
@Input() position: GeolocationPosition;
@Input() mapState: IMapState;
@Input() animate: boolean;
constructor(@Host() map: MapComponent,private changeDetectorRef$: ChangeDetectorRef ) {
this.map = map;
}
ngOnInit() {
this.view = this.map.instance.getView();
this.view.on('change:center', () => {
this.changeDetectorRef$.detectChanges();
});
}
ngOnChanges(changes: SimpleChanges) {
// if (changes.position && this.instance) {
// var p = changes.position.currentValue as Position;
// this.instance.setPosition(fromLonLat([p.coords.longitude, p.coords.latitude]));
// this.locationTolerance = p.coords.accuracy;
// this.recalcLocationTolerance();
// this.heading = p.coords.heading;
// }
}
p
public centered():boolean {
if(this.position && this.mapState) {
const center = this.view.getCenter();
const newCenter = fromLonLat([this.position.coords.longitude,this.position.coords.latitude]);
const x1 = newCenter[0].toFixed(0);
const x2 = center[0].toFixed(0);
const y1 = newCenter[1].toFixed(0);
const y2 = center[1].toFixed(0);
return x1==x2 && y1==y2;
}
return false;
}
public disabled():boolean {
return !this.position;
}
handleClick(event:Event) {
if(this.position) {
const view = this.map.instance.getView();
const newCenter = fromLonLat([this.position.coords.longitude,this.position.coords.latitude]);
const extent = [newCenter[0]-500,newCenter[1]-500,newCenter[0]+500,newCenter[1]+500];
const options = { padding: [0, 0, 0, 0],minResolution:1 };
const size = this.map.instance.getSize();
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
const threshold = 44 * rem;
let left = 1 * rem;
const right = 1 * rem;
let bottom = Math.round(size[1] / 2);
const top = 1 * rem;
if (size[0] > threshold) {
bottom = 1 * rem;
left = 23 * rem;
}
//options.padding = [top, right, bottom, left];
if (this.animate) options["duration"] = 2000;
view.fit(extent, options);
}
event.preventDefault();
}
}

View File

@ -1,35 +0,0 @@
<div (click)="handleClick($event)" class="btn btn-outline-primary compass" [style.transform]="Rotation()" [ngClass]="{'compass-n':IsNorth()}">
<svg height="100%" width="100%" viewBox="0 0 132.29166 132.29167">
<g
inkscape:label="Laag 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-164.70832)">
<g
id="g4550"
transform="translate(2.3213753,-1.8555167)">
<path
id="top-r"
d="m 63.824458,179.82737 v 52.8823 H 48.380953 Z"
style="stroke:none;stroke-width:0.15389842px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="top-l"
d="m 63.824458,179.82737 v 52.8823 h 15.443505 z"
style="stroke:none;stroke-width:0.15389842px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="bottom-l"
d="m 63.824458,285.59197 v -52.8823 h -15.4435 z"
style="stroke:none;stroke-width:0.15389842px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="bottom-r"
d="m 63.824458,285.59197 v -52.8823 h 15.443505 z"
style="stroke:none;stroke-width:0.15389842px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="north"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:2.95481014"
d="m 50.702335,239.32724 h 9.926315 l 12.534859,23.63848 v -23.63848 h 8.425825 v 34.46509 H 71.663019 L 59.12816,250.15385 v 23.63848 h -8.425825 z" />
</g>
</g>
</svg>
</div>

View File

@ -1,66 +0,0 @@
.compass {
width:2.5em;
height:2.5em;
background-color: white;
opacity: 1;
border-radius:1.75em;
padding:0;
margin-top:0.5em;
display: block;
}
#north {
display: none;
fill:var(--bs-black);
}
#top-l {
fill:#d40000;
}
#top-r {
fill:#ff0000;
}
#bottom-l {
fill:#000000;
}
#bottom-r {
fill:#666666;
}
div.compass:hover #top-l {
fill:var(--bs-white);
}
div.compass:hover #top-r {
fill:var(--bs-gray-300);
}
div.compass:hover #bottom-l {
fill:var(--bs-gray-300);
}
div.compass:hover #bottom-r {
fill:var(--bs-white);
}
div.compass:hover #north {
fill:var(--bs-white);
}
.compass-n {
transition: opacity 1s ease-out 2s,height 1s ease-out 3s,margin-top 1s ease-out 3s;
opacity:0;
height:0;
margin-top:0;
}
.compass-n #bottom-l, .compass-n #bottom-r {
display: none;
}
.compass-n #north {
display: inline;
}

View File

@ -1,39 +0,0 @@
import { Component, Host, Input, OnInit, ChangeDetectorRef } from '@angular/core';
import { ViewComponent, MapComponent } from 'ng-openlayers';
import {View} from 'ol';
@Component({
selector: 'fm-map-rotation-reset',
templateUrl: './rotation-reset.component.html',
styleUrls: ['./rotation-reset.component.scss']
})
export class RotationResetComponent implements OnInit {
view: View;
public Rotation() {
const rotation = this.view ? this.view.getRotation() : 0;
return `rotate(${rotation}rad)`;
}
public IsNorth() {
return this.view ? this.view.getRotation() == 0 : true;
}
ngOnInit(): void {
this.view = this.map.instance.getView();
this.view.on('change:rotation', () => {
this.changeDetectorRef$.detectChanges();
});
}
constructor( private map: MapComponent, private changeDetectorRef$: ChangeDetectorRef ) {
}
handleClick(event:Event) {
this.view.animate({ rotation: 0 });
event.preventDefault();
}
}

View File

@ -1,52 +0,0 @@
import { Component, Host, Input, OnInit, OnChanges, SimpleChanges, forwardRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ViewComponent, MapComponent } from 'ng-openlayers';
@Component({
selector: 'fm-map-zoom-to-extent',
template: `<ng-content></ng-content>`
})
export class ZoomToExtentComponent implements OnChanges {
view: ViewComponent;
map: MapComponent;
paddingTop = 0;
paddingLeft = 0;
paddingBottom = 0;
paddingRight = 0;
@Input() extent: number[];
@Input() animate = false;
constructor(@Host() view: ViewComponent, @Host() map: MapComponent,route: ActivatedRoute ) {
this.view = view;
this.map = map;
if(route && route.snapshot && route.snapshot.data && route.snapshot.data["fm-map-zoom-to-extent"]) {
const params = route.snapshot.data["fm-map-zoom-to-extent"];
this.paddingTop = params["padding-top"] ? params["padding-top"] : 0;
this.paddingBottom = params["padding-bottom"] ? params["padding-bottom"] : 0;
this.paddingLeft = params["padding-left"] ? params["padding-left"] : 0;
this.paddingRight = params["padding-right"] ? params["padding-right"] : 0;
}
}
ngOnChanges(changes: SimpleChanges) {
if (this.extent) {
const options = { padding: [0, 0, 0, 0],minResolution:1 };
const size = this.map.instance.getSize();
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
const threshold = 40 * rem;
let left = 1 * rem;
const right = 1 * rem;
let bottom = Math.round((size[1] / 2) + (4*rem));
const top = 1 * rem;
if (size[0] > threshold) {
bottom = 5 * rem;
left = 23 * rem;
}
options.padding = [top + (this.paddingTop*rem), right+ (this.paddingRight*rem), bottom + (this.paddingBottom*rem), left+ (this.paddingLeft*rem)];
if (this.animate) options["duration"] = 1000;
this.view.instance.fit(this.extent, options);
}
}
}

View File

@ -1,3 +0,0 @@
<div class="feature-list-container">
<ng-template fm-map-widget-host></ng-template>
</div>

View File

@ -1,14 +0,0 @@
.row {
border-bottom: 1px solid var(--bs-gray-500);
user-select: none;
}
.row.selected {
background-color: var(--bs-gray-100);
}
@media screen and (min-width: 44rem) {
.feature-list-container {
margin-top: 4rem;
}
}

View File

@ -1,92 +0,0 @@
import { Component, Input, OnInit, ComponentFactoryResolver, ViewChild, SimpleChanges, ComponentFactory, Inject} from '@angular/core';
import { Feature } from 'ol';
import { Geometry} from 'ol/geom';
import { FeatureListComponent,AbstractFeatureListComponent } from '../feature-list/feature-list.component';
import { WidgetHostDirective } from '../widget-host/widget-host.directive';
import {IQueryState,PackageService } from '@farmmaps/common';
import * as mapReducers from '../../reducers/map.reducer';
import * as mapActions from '../../actions/map.actions';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
@Component({
selector: 'fm-map-feature-list-container',
templateUrl: './feature-list-container.component.html',
styleUrls: ['./feature-list-container.component.scss']
})
export class FeatureListContainerComponent {
constructor(private store: Store<mapReducers.State>,private componentFactoryResolver: ComponentFactoryResolver, @Inject(AbstractFeatureListComponent) public featureLists: AbstractFeatureListComponent[],private packageService:PackageService ) {
this.featureLists = [...this.featureLists].reverse();
}
@Input() features: Array<Feature<Geometry>>
@Input() queryState: IQueryState;
@Input() selectedFeature: Feature<Geometry>;
@Input() clickedFeature:Observable<Feature<Geometry>>;
@ViewChild(WidgetHostDirective, { static: true }) widgetHost: WidgetHostDirective;
componentRef:any;
loadComponent(queryState:IQueryState) {
let componentFactory: ComponentFactory<AbstractFeatureListComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListComponent); // default
let selected = -1;
let maxMatches =0;
const showItem = true;
for (let i = 0; i < this.featureLists.length; i++) {
let matches=0;
let criteria=0;
if (this.featureLists[i]['forItemType']) {
criteria++;
if( this.featureLists[i]['forItemType'].split(",").filter(part => part == queryState.itemType).length == 1) {
matches++;
}
}
if(this.featureLists[i]['forChild'] ) {
criteria++;
if(queryState.parentCode && queryState.parentCode != "") {
matches++;
}
}
if(criteria == matches && matches > maxMatches) {
selected=i;
maxMatches = matches;
}
}
if (selected >= 0) {
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[selected]['constructor'] as any);
if (this.featureLists[selected]['collapseSearch'] === true) {
this.store.dispatch(new mapActions.CollapseSearch());
}
}
const viewContainerRef = this.widgetHost.viewContainerRef;
viewContainerRef.clear();
if(showItem) {
this.componentRef = viewContainerRef.createComponent(componentFactory);
(<AbstractFeatureListComponent>this.componentRef.instance).features = this.features;
(<AbstractFeatureListComponent>this.componentRef.instance).queryState = this.queryState;
(<AbstractFeatureListComponent>this.componentRef.instance).selectedFeature = this.selectedFeature;
}
}
ngOnInit() {
this.clickedFeature.subscribe((feature => {
(<AbstractFeatureListComponent>this.componentRef.instance).handleFeatureClick(feature);
}));
}
ngOnChanges(changes: SimpleChanges) {
if ((changes["queryState"] && changes["queryState"].currentValue)) {
this.loadComponent(changes["queryState"].currentValue);
}
if ((changes["features"] && changes["features"].currentValue)) {
(<AbstractFeatureListComponent>this.componentRef.instance).features = changes["features"].currentValue;
this.componentRef.changeDetectorRef.detectChanges();
}
if(changes["selectedFeature"]) {
(<AbstractFeatureListComponent>this.componentRef.instance).selectedFeature = changes["selectedFeature"].currentValue;
this.componentRef.changeDetectorRef.detectChanges();
}
}
}

View File

@ -1,14 +0,0 @@
<div class="card border-0">
<div class="card-body" *ngIf="(schemeItem|async);let schemeItem">
<fm-back-button></fm-back-button>
<h4 i18n>Farm</h4>
<h3>{{schemeItem.name}}</h3>
<div *ngIf="features;let features">
<div class="cropfields">
<div class="row m-0 ps-3 pe-3" *ngFor="let feature of features" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)">
<fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,20 +0,0 @@
fm-map-feature-list-feature-container {
width:100%;
pointer-events:none;
}
.row {
border-bottom: 1px solid var(--bs-gray-500);
user-select: none;
padding-left:1.5rem;
}
.row.selected {
background-color: var(--bs-gray-100);
}
.cropfields {
border-top: 1px solid var(--bs-gray-500);
margin-left: -1.25rem;
margin-right: -1.25rem;
}

View File

@ -1,30 +0,0 @@
import { Component, Injectable,AfterViewInit, OnInit,SimpleChanges, ChangeDetectorRef} from '@angular/core';
import { Location } from '@angular/common';
import { AbstractFeatureListComponent } from '../feature-list/feature-list.component';
import {ForItemType } from '../for-item/for-itemtype.decorator';
import {ForChild } from '../for-item/for-child.decorator';
import { Store } from '@ngrx/store';
import * as mapReducers from '../../reducers/map.reducer';
import { commonReducers, ItemTypeService, IItem,ItemService } from '@farmmaps/common';
import { Observable } from 'rxjs';
@ForChild()
@ForItemType("vnd.farmmaps.itemtype.cropfield")
@Injectable()
@Component({
selector: 'fm-map-feature-list-cropfield',
templateUrl: './feature-list-cropfield.component.html',
styleUrls: ['./feature-list-cropfield.component.scss']
})
export class FeatureListCropfieldComponent extends AbstractFeatureListComponent implements OnInit {
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, private itemService: ItemService) {
super(store, itemTypeService,location);
}
public schemeItem: Observable<IItem>
ngOnInit() {
this.schemeItem = this.itemService.getItem(this.queryState.parentCode);
}
}

View File

@ -1,13 +0,0 @@
<div class="card border-0">
<div class="card-body">
<fm-back-button></fm-back-button>
<h3><i class="far fa-farm"></i>&nbsp;<span i18n>Farms</span></h3>
<div *ngIf="features;let features">
<div class="farms">
<div class="row m-0 ps-3 pe-3" *ngFor="let feature of features"[ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)">
<fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,20 +0,0 @@
fm-map-feature-list-feature-container {
width:100%;
pointer-events:none;
}
.row {
border-bottom: 1px solid var(--bs-gray-500);
user-select: none;
padding-left:1.5rem;
}
.row.selected {
background-color: var(--bs-gray-100);
}
.farms {
border-top: 1px solid var(--bs-gray-500);
margin-left: -1.25rem;
margin-right: -1.25rem;
}

View File

@ -1,31 +0,0 @@
import { Component, Injectable } from '@angular/core';
import { Location } from '@angular/common';
import { AbstractFeatureListComponent } from '../feature-list/feature-list.component';
import { ForItemType } from '../for-item/for-itemtype.decorator';
import { Store,Action } from '@ngrx/store';
import * as mapReducers from '../../reducers/map.reducer';
import { commonReducers, ItemTypeService } from '@farmmaps/common';
import * as mapActions from '../../actions/map.actions';
import { tassign } from 'tassign';
import { Router } from '@angular/router';
import { Feature } from 'ol';
import { Geometry} from 'ol/geom';
@ForItemType("vnd.farmmaps.itemtype.croppingscheme")
@Injectable()
@Component({
selector: 'fm-map-feature-list-croppingscheme',
templateUrl: './feature-list-croppingscheme.component.html',
styleUrls: ['./feature-list-croppingscheme.component.scss']
})
export class FeatureListCroppingschemeComponent extends AbstractFeatureListComponent {
constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, private router: Router) {
super(store, itemTypeService, location);
}
getAction(feature:Feature<Geometry>):Action {
const queryState = tassign(mapReducers.initialState.queryState, { parentCode: feature.get('code'), itemType: "vnd.farmmaps.itemtype.cropfield" });
return new mapActions.DoQuery(queryState);
}
}

View File

@ -1,61 +0,0 @@
import { Component, Input, OnInit, ComponentFactoryResolver, ViewChild, SimpleChanges, ComponentFactory, Inject, Type} from '@angular/core';
import { Feature } from 'ol';
import { Geometry } from 'ol/geom';
import { AbstractFeatureListFeatureComponent,FeatureListFeatureComponent } from '../feature-list-feature/feature-list-feature.component';
import { WidgetHostDirective } from '../widget-host/widget-host.directive';
@Component({
selector: 'fm-map-feature-list-feature-container',
template: `
<div>
<ng-template fm-map-widget-host></ng-template>
</div>
`
})
export class FeatureListFeatureContainerComponent {
constructor(private componentFactoryResolver: ComponentFactoryResolver, @Inject(AbstractFeatureListFeatureComponent) public featureLists: AbstractFeatureListFeatureComponent[] ) {
this.featureLists = [...this.featureLists].reverse();
}
@Input() feature: Feature<Geometry>;
@ViewChild(WidgetHostDirective, { static: true }) widgetHost: WidgetHostDirective;
loadComponent() {
let componentFactory: ComponentFactory<AbstractFeatureListFeatureComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListFeatureComponent); // default
let selected = -1;
let maxMatches =0;
for (let i = 0; i < this.featureLists.length; i++) {
let matches=0;
let criteria=0;
if (this.featureLists[i]['forItemType']) {
criteria++;
if(this.featureLists[i]['forItemType'].split(",").filter(part => part == this.feature.get("itemType")).length == 1) {
matches++;
}
}
if(criteria == matches && matches > maxMatches) {
selected=i;
maxMatches = matches;
}
}
if (selected >= 0) {
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[selected]['constructor'] as any);
}
const viewContainerRef = this.widgetHost.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent(componentFactory);
(<AbstractFeatureListFeatureComponent>componentRef.instance).feature = this.feature;
}
ngOnChanges(changes: SimpleChanges) {
if (changes["feature"] && changes["feature"].currentValue) {
this.loadComponent();
}
}
}

View File

@ -1,14 +0,0 @@
<div *ngIf="feature;let feature" class="d-flex m-0">
<div class="p-2">
<div class="thumbnail">
<fm-map-feature-thumbnail [feature]="feature"></fm-map-feature-thumbnail>
</div>
</div>
<div class="flex-grow p-2 overflow-hidden">
<h1 class="card-title" title="{{feature.get('name')}}">{{feature.get('name')}}</h1>
<div class="card-text"><span>{{areaInHa(feature)| number:'1.2-2'}}
ha</span>&nbsp;<span>{{feature.get('cropTypeName')}}</span> </div>
<div class="card-text"><span>{{feature.get('datadate')|date}}</span> -
<span>{{feature.get('dataenddate')|date}}</span> </div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More