diff --git a/package-lock.json b/package-lock.json index e549411b3..c68ef8082 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,7 +52,11 @@ "@ngx-translate/core": "^16.0.4", "@ngx-translate/http-loader": "^16.0.1", "@openid/appauth": "^1.3.1", + "@placemarkio/check-geojson": "^0.1.14", "@sentry/browser": "^7.37.2", + "@tmcw/togeojson": "^7.1.2", + "@turf/clean-coords": "^7.2.0", + "@turf/truncate": "^7.2.0", "@turf/turf": "^7.1.0", "@types/leaflet-draw": "^1.0.6", "angular-svg-icon": "^16.1.0", @@ -77,6 +81,7 @@ "ngx-file-drop": "^16.0.0", "ngx-logger": "^4.2.1", "ngx-markdown": "^20.0.0", + "nve-designsystem": "^2.16.0", "observable-webworker": "^3.4.0", "pouchdb-adapter-idb": "^7.2.2", "rxjs": "^7.8.1", @@ -4526,6 +4531,15 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.6.3", "dev": true, @@ -5090,6 +5104,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, "node_modules/@geoman-io/leaflet-geoman-free": { "version": "2.14.2", "license": "MIT", @@ -6196,6 +6235,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz", + "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/react": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@lit/react/-/react-1.0.8.tgz", + "integrity": "sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==", + "license": "BSD-3-Clause", + "peerDependencies": { + "@types/react": "17 || 18 || 19" + } + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.1.tgz", + "integrity": "sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.4.0" + } + }, "node_modules/@lmdb/lmdb-darwin-arm64": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.2.tgz", @@ -7599,6 +7662,15 @@ "node": ">=14" } }, + "node_modules/@placemarkio/check-geojson": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@placemarkio/check-geojson/-/check-geojson-0.1.14.tgz", + "integrity": "sha512-PZvNKzt6STytUw21TUkqU+TG6dbwTWb1ACosvInBYTBm37zsr8C74J6crBTQ3BWkyd6YeitYd4HibJzBEyk6Aw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.52.3", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz", @@ -8430,6 +8502,45 @@ "node": ">=10" } }, + "node_modules/@shoelace-style/animations": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@shoelace-style/animations/-/animations-1.2.0.tgz", + "integrity": "sha512-avvo1xxkLbv2dgtabdewBbqcJfV0e0zCwFqkPMnHFGbJbBHorRFfMAHh1NG9ymmXn0jW95ibUVH03E1NYXD6Gw==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/claviska" + } + }, + "node_modules/@shoelace-style/localize": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shoelace-style/localize/-/localize-3.2.1.tgz", + "integrity": "sha512-r4C9C/5kSfMBIr0D9imvpRdCNXtUNgyYThc4YlS6K5Hchv1UyxNQ9mxwj+BTRH2i1Neits260sR3OjKMnplsFA==", + "license": "MIT" + }, + "node_modules/@shoelace-style/shoelace": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/@shoelace-style/shoelace/-/shoelace-2.20.1.tgz", + "integrity": "sha512-FSghU95jZPGbwr/mybVvk66qRZYpx5FkXL+vLNpy1Vp8UsdwSxXjIHE3fsvMbKWTKi9UFfewHTkc5e7jAqRYoQ==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.1.0", + "@floating-ui/dom": "^1.6.12", + "@lit/react": "^1.0.6", + "@shoelace-style/animations": "^1.2.0", + "@shoelace-style/localize": "^3.2.1", + "composed-offset-position": "^0.0.6", + "lit": "^3.2.1", + "qr-creator": "^1.0.0" + }, + "engines": { + "node": ">=14.17.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/claviska" + } + }, "node_modules/@sigstore/bundle": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-3.1.0.tgz", @@ -8664,6 +8775,15 @@ "node": ">=10" } }, + "node_modules/@tmcw/togeojson": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@tmcw/togeojson/-/togeojson-7.1.2.tgz", + "integrity": "sha512-QKnFs9DAuqqBVj4d6c69tV1Dj2TspSBTqffivoN0YoBCVdP/JY1+WaYCJbzU49RkoU5NOSOJ3jtFHCdEUVh21A==", + "license": "BSD-2-Clause", + "engines": { + "node": "*" + } + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -10058,36 +10178,42 @@ } }, "node_modules/@turf/clean-coords": { - "version": "7.1.0", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-7.2.0.tgz", + "integrity": "sha512-+5+J1+D7wW7O/RDXn46IfCHuX1gIV1pIAQNSA7lcDbr3HQITZj334C4mOGZLEcGbsiXtlHWZiBtm785Vg8i+QQ==", "license": "MIT", "dependencies": { - "@turf/helpers": "^7.1.0", - "@turf/invariant": "^7.1.0", + "@turf/helpers": "^7.2.0", + "@turf/invariant": "^7.2.0", "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" + "tslib": "^2.8.1" }, "funding": { "url": "https://opencollective.com/turf" } }, "node_modules/@turf/clean-coords/node_modules/@turf/helpers": { - "version": "7.1.0", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.2.0.tgz", + "integrity": "sha512-cXo7bKNZoa7aC7ydLmUR02oB3IgDe7MxiPuRz3cCtYQHn+BJ6h1tihmamYDWWUlPHgSNF0i3ATc4WmDECZafKw==", "license": "MIT", "dependencies": { "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" + "tslib": "^2.8.1" }, "funding": { "url": "https://opencollective.com/turf" } }, "node_modules/@turf/clean-coords/node_modules/@turf/invariant": { - "version": "7.1.0", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.2.0.tgz", + "integrity": "sha512-kV4u8e7Gkpq+kPbAKNC21CmyrXzlbBgFjO1PhrHPgEdNqXqDawoZ3i6ivE3ULJj2rSesCjduUaC/wyvH/sNr2Q==", "license": "MIT", "dependencies": { - "@turf/helpers": "^7.1.0", + "@turf/helpers": "^7.2.0", "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" + "tslib": "^2.8.1" }, "funding": { "url": "https://opencollective.com/turf" @@ -11838,6 +11964,19 @@ "url": "https://opencollective.com/turf" } }, + "node_modules/@turf/line-split/node_modules/@turf/truncate": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-6.5.0.tgz", + "integrity": "sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, "node_modules/@turf/line-to-polygon": { "version": "7.1.0", "license": "MIT", @@ -13690,11 +13829,41 @@ } }, "node_modules/@turf/truncate": { - "version": "6.5.0", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-7.2.0.tgz", + "integrity": "sha512-jyFzxYbPugK4XjV5V/k6Xr3taBjjvo210IbPHJXw0Zh7Y6sF+hGxeRVtSuZ9VP/6oRyqAOHKUrze+OOkPqBgUg==", "license": "MIT", "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" + "@turf/helpers": "^7.2.0", + "@turf/meta": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/truncate/node_modules/@turf/helpers": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.2.0.tgz", + "integrity": "sha512-cXo7bKNZoa7aC7ydLmUR02oB3IgDe7MxiPuRz3cCtYQHn+BJ6h1tihmamYDWWUlPHgSNF0i3ATc4WmDECZafKw==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/truncate/node_modules/@turf/meta": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.2.0.tgz", + "integrity": "sha512-igzTdHsQc8TV1RhPuOLVo74Px/hyPrVgVOTgjWQZzt3J9BVseCdpfY/0cJBdlSRI4S/yTmmHl7gAqjhpYH5Yaw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@types/geojson": "^7946.0.10" }, "funding": { "url": "https://opencollective.com/turf" @@ -14042,19 +14211,6 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/turf/node_modules/@turf/truncate": { - "version": "7.1.0", - "license": "MIT", - "dependencies": { - "@turf/helpers": "^7.1.0", - "@turf/meta": "^7.1.0", - "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, "node_modules/@turf/union": { "version": "7.1.0", "license": "MIT", @@ -14785,6 +14941,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.0.2" + } + }, "node_modules/@types/responselike": { "version": "1.0.0", "dev": true, @@ -14871,8 +15037,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/@types/websql": { "version": "0.0.27", @@ -16572,6 +16737,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/composed-offset-position": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/composed-offset-position/-/composed-offset-position-0.0.6.tgz", + "integrity": "sha512-Q7dLompI6lUwd7LWyIcP66r4WcS9u7AL2h8HaeipiRfCRPLMWqRx8fYsjb4OHi6UQFifO7XtNC2IlEJ1ozIFxw==", + "license": "MIT", + "peerDependencies": { + "@floating-ui/utils": "^0.2.5" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -17162,6 +17336,13 @@ "node": ">=4" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT", + "peer": true + }, "node_modules/custom-event": { "version": "1.0.1", "dev": true, @@ -19794,6 +19975,12 @@ } } }, + "node_modules/fontfaceobserver": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", + "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==", + "license": "BSD-2-Clause" + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -22217,6 +22404,37 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/lit": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.1.tgz", + "integrity": "sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.1.tgz", + "integrity": "sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.4.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.1.tgz", + "integrity": "sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, "node_modules/lmdb": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.2.tgz", @@ -24269,6 +24487,20 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nve-designsystem": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nve-designsystem/-/nve-designsystem-2.16.0.tgz", + "integrity": "sha512-5GYYHtfBBQOLHZjN+r6jX9Fj76IKysuN312THUPc7U5nkzRi+Bl99DZIMejALUjj3xNCmOZBUn7erowxummfVQ==", + "license": "MIT", + "dependencies": { + "@shoelace-style/shoelace": "^2.20.1", + "fontfaceobserver": "^2.3.0", + "lit": "^3.3.0" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "^4.44.2" + } + }, "node_modules/object-assign": { "version": "4.1.1", "dev": true, @@ -25605,6 +25837,12 @@ "node": ">=0.9" } }, + "node_modules/qr-creator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/qr-creator/-/qr-creator-1.0.0.tgz", + "integrity": "sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==", + "license": "MIT" + }, "node_modules/qs": { "version": "6.13.0", "dev": true, diff --git a/package.json b/package.json index c72d3d8d1..5ac1b8496 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,11 @@ "@ngx-translate/core": "^16.0.4", "@ngx-translate/http-loader": "^16.0.1", "@openid/appauth": "^1.3.1", + "@placemarkio/check-geojson": "^0.1.14", "@sentry/browser": "^7.37.2", + "@tmcw/togeojson": "^7.1.2", + "@turf/clean-coords": "^7.2.0", + "@turf/truncate": "^7.2.0", "@turf/turf": "^7.1.0", "@types/leaflet-draw": "^1.0.6", "angular-svg-icon": "^16.1.0", @@ -106,6 +110,7 @@ "ngx-file-drop": "^16.0.0", "ngx-logger": "^4.2.1", "ngx-markdown": "^20.0.0", + "nve-designsystem": "^2.16.0", "observable-webworker": "^3.4.0", "pouchdb-adapter-idb": "^7.2.2", "rxjs": "^7.8.1", diff --git a/src/app/core/services/database/database.service.ts b/src/app/core/services/database/database.service.ts index 2b53a0df0..b6f10ca3f 100644 --- a/src/app/core/services/database/database.service.ts +++ b/src/app/core/services/database/database.service.ts @@ -55,6 +55,7 @@ export class DatabaseService { * @returns Returns a promise with the value of the given key */ async get(key: string): Promise { + // TODO: Legg til null på type await firstValueFrom(this.ready$); return this.database.get(key); } diff --git a/src/app/core/services/geojson/geojson-item.model.ts b/src/app/core/services/geojson/geojson-item.model.ts new file mode 100644 index 000000000..3144ac97e --- /dev/null +++ b/src/app/core/services/geojson/geojson-item.model.ts @@ -0,0 +1,8 @@ +export interface GeoJSONItem { + id: string; + name: string; + date?: number; + visibleOnMap?: boolean; + comment?: string; + lengthKm?: number; +} diff --git a/src/app/core/services/geojson/geojson.service.ts b/src/app/core/services/geojson/geojson.service.ts new file mode 100644 index 000000000..89f619f69 --- /dev/null +++ b/src/app/core/services/geojson/geojson.service.ts @@ -0,0 +1,127 @@ +import { Injectable, effect, inject, signal } from '@angular/core'; +import { DatabaseService } from '../database/database.service'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; +import { GeoJSONItem } from './geojson-item.model'; +import { LoggingService } from 'src/app/modules/shared/services/logging/logging.service'; +import { toObservable } from '@angular/core/rxjs-interop'; +import { cleanFeatureCollection } from 'src/app/pages/plans/geojson'; +import { length } from '@turf/turf'; + +const DEBUG_TAG = 'GeoJSON'; + +@Injectable({ + providedIn: 'root', +}) +export class GeoJSONService { + private db = inject(DatabaseService); + private logger = inject(LoggingService); + + metadata = signal([]); + readonly metadata$ = toObservable(this.metadata); + private initialized = false; + + constructor() { + this.init(); + + effect(() => { + const metadata = this.metadata(); + if (!this.initialized) return; + this.saveMetadata(metadata); + }); + } + + private async init() { + this.logger.debug('Init', DEBUG_TAG); + const items = await this.getMetadata(); + if (items && items.length > 0) { + this.metadata.set(items); + } + setTimeout(() => (this.initialized = true)); // For å unngå en første unødvendig lagring i effecten + } + + private async saveMetadata(items: GeoJSONItem[]) { + this.logger.debug('Saving metadata', DEBUG_TAG, { n: items.length }); + await this.db.set('geojson-metadata', items); + } + + private getMetadata() { + this.logger.debug('Reading metadata', DEBUG_TAG); + return this.db.get('geojson-metadata'); + } + + /** + * Kalkulerer lengden av LineString features i et GeoJSON objekt + * @param geojson + * @returns lengde i kilometer + */ + private calculateLengthKm(geojson: Feature[]): number { + return geojson.reduce((sum, feature) => sum + length(feature), 0); + } + + /** + * Updates metadata for a given item + * @param item the geojson item to update + */ + updateMetadata(item: GeoJSONItem) { + this.metadata.update((items) => { + const other = items.filter((x) => x.id !== item.id); + return [...other, item]; + }); + } + + /** + * Save a geojson object with a given id + * @param metadata metadata for the geojson + * @param geojson geojson object + */ + async save(metadata: GeoJSONItem, geojson: FeatureCollection): Promise { + this.logger.debug('Save', DEBUG_TAG, { metadata }); + try { + cleanFeatureCollection(geojson); + } catch (error) { + this.logger.error(error, DEBUG_TAG, 'Error in cleaning process, but object may be mutated - half cleaned'); + } + + try { + const lineFeatures = geojson.features.filter((f) => f.geometry.type === 'LineString'); + + if (lineFeatures.length) { + const lengthKm = this.calculateLengthKm(lineFeatures); + metadata.lengthKm = lengthKm; + } + + await this.db.set(`geojson:${metadata.id}`, geojson); + this.metadata.update((items) => [...items, metadata]); + } catch (error) { + this.logger.error(error, DEBUG_TAG, 'Could not save', { metadata, geojson }); + throw error; + } + } + + /** + * Get a geojson object by id + * @param id unique id for the geojson + */ + async get(id: GeoJSONItem['id']): Promise { + this.logger.debug('Get', DEBUG_TAG, { id }); + return this.db.get(`geojson:${id}`); + } + + /** + * Remove a geojson object by id + * @param id unique id for the geojson + */ + async remove(id: GeoJSONItem['id']): Promise { + this.logger.debug('Remove', DEBUG_TAG, { id }); + await this.db.remove(`geojson:${id}`); + this.metadata.update((items) => items.filter((item) => item.id !== id)); + } + + /** + * List all geojson ids + */ + // async listIds(): Promise { + // const keys = await this.db.keys(); + // return keys.filter((k) => k.startsWith('geojson:')).map((k) => k.replace('geojson:', '')); + // } +} diff --git a/src/app/modules/map-image/map-image.component.ts b/src/app/modules/map-image/map-image.component.ts index ef3775fc3..ec46766a4 100644 --- a/src/app/modules/map-image/map-image.component.ts +++ b/src/app/modules/map-image/map-image.component.ts @@ -50,6 +50,7 @@ export class MapImageComponent { ...x.layerConfig.options, }) ); + const mapSettings: L.MapOptions = { zoom: settings.map.tiles.zoomLevelObservationList, maxZoom: settings.map.tiles.maxZoom, diff --git a/src/app/modules/map/components/map/map.component.html b/src/app/modules/map/components/map/map.component.html index 6c76c5152..7363737d0 100644 --- a/src/app/modules/map/components/map/map.component.html +++ b/src/app/modules/map/components/map/map.component.html @@ -9,18 +9,14 @@ > } -@if (showObserverTrips()) { -