From 0ca0ce7105739f1e07aec70658dcdbabe9a8dd56 Mon Sep 17 00:00:00 2001
From: panaaj <38519157+panaaj@users.noreply.github.com>
Date: Sat, 6 Jul 2024 16:15:34 +0930
Subject: [PATCH] ng 18
---
CHANGELOG.md | 10 +
angular.json | 19 +-
package.json | 32 +-
src/app-theme.scss | 39 +-
src/app/app.component.css | 1 +
src/app/app.component.html | 51 +-
src/app/app.component.ts | 25 +-
src/app/app.info.ts | 39 +-
src/app/app.module.ts | 80 +-
.../dialogs/common/dialogs.component.ts | 4 +-
.../dialogs/{ => geojson}/geojson-dialog.css | 0
.../{ => geojson}/geojson-dialog.facade.ts | 0
.../dialogs/{ => geojson}/geojson-dialog.html | 0
.../dialogs/{ => geojson}/geojson-dialog.ts | 0
src/app/lib/components/dialogs/index.ts | 2 +-
src/app/lib/components/index.ts | 6 +-
src/app/lib/components/wakelock.component.ts | 1 +
src/app/modules/alarms/alarms.module.ts | 48 -
.../alarms/components/alarm.component.ts | 15 +
.../components/alarms-dialog.component.ts | 21 +-
.../components/anchor-watch.component.ts | 21 +
src/app/modules/alarms/index.ts | 5 +
.../autopilot}/autopilot.component.css | 0
.../autopilot}/autopilot.component.ts | 0
src/app/modules/autopilot/index.ts | 1 +
.../course}/course-settings.ts | 0
src/app/modules/course/index.ts | 1 +
.../experiments/experiments.component.ts | 15 +
.../modules/experiments/experiments.module.ts | 32 -
src/app/modules/experiments/index.ts | 1 +
.../experiments/weather/weather.module.ts | 46 -
src/app/modules/index.ts | 17 +-
.../map/components/navigation/index.ts | 1 -
.../modules/map/components/popover/index.ts | 3 -
.../components/popover/popover.component.ts | 427 -----
.../map/components/profiles/default/index.ts | 1 -
src/app/modules/map/fb-map.component.html | 18 +-
src/app/modules/map/fb-map.component.ts | 238 +--
src/app/modules/map/index.ts | 2 +
src/app/modules/map/map.module.ts | 75 -
src/app/modules/map/mapconfig.ts | 177 +-
src/app/modules/map/ol/index.ts | 3 +
.../lib/navigation/layer-layline.component.ts | 33 +-
.../layer-target-angle.component.ts | 140 ++
.../lib/resources/layer-charts.component.ts | 7 +-
.../resources/layer-skvessels.component.ts | 14 +-
.../map/ol/lib/vectorLayerStyleFactory.ts | 25 +-
.../popovers/aircraft-popover.component.ts | 132 ++
.../map/popovers/alarm-popover.component.ts | 117 ++
.../map/popovers/aton-popover.component.ts | 150 ++
.../compass.component.svg | 0
.../popover => popovers}/compass.component.ts | 3 +
.../popovers/featurelist-popover.component.ts | 68 +
src/app/modules/map/popovers/index.ts | 8 +
.../popover.component.scss | 0
.../modules/map/popovers/popover.component.ts | 68 +
.../resource-popover.component.ts | 24 +
.../vessel-popover.component.ts | 18 +
src/app/modules/map/vessel-calcs.types.ts | 23 +
src/app/modules/map/vessel-calcs.worker.ts | 165 ++
.../{ => components}/settings-dialog.css | 0
.../{ => components}/settings-dialog.html | 0
.../{ => components}/settings-dialog.ts | 48 +-
.../signalk-preferredpaths.component.ts | 5 +
.../settings/{settings.module.ts => index.ts} | 18 +-
.../components/active-resource-dialog.ts | 342 ++++
.../ais/aircraft-properties-modal.ts | 143 ++
.../components/ais/ais-properties-modal.ts | 261 +++
.../{lists => components/ais}/aislist.html | 47 +-
.../{lists => components/ais}/aislist.ts | 111 +-
.../components/ais/aton-properties-modal.ts | 195 ++
.../charts/chart-properties-dialog.ts | 169 ++
.../charts}/chartlist.html | 62 +-
.../{lists => components/charts}/chartlist.ts | 280 +--
.../{ => components}/notes/note-dialog.html | 9 +-
.../{ => components}/notes/note-dialog.ts | 0
.../{lists => components/notes}/notelist.html | 0
.../{lists => components/notes}/notelist.ts | 23 +-
.../{ => components}/notes/notes.css | 0
.../notes/relatednotes-dialog.html | 16 +-
.../notes/relatednotes-dialog.ts | 0
.../{ => components}/notes/safe.pipe.ts | 0
.../skresources/components/resource-dialog.ts | 217 +++
.../{lists => components}/resourcelist.css | 10 +-
.../resourcesets}/resource-upload-dialog.css | 0
.../resourcesets}/resource-upload-dialog.html | 0
.../resourcesets}/resource-upload-dialog.ts | 40 +-
.../resourceset-feature-properties-modal.ts | 119 ++
.../resourcesets/resourceset-list-modal.ts | 223 +++
.../routes}/build-route.component.css | 3 -
.../routes}/build-route.component.ts | 0
.../components/routes}/nextpoint.component.ts | 5 +
.../routes}/routelist.html | 0
.../{lists => components/routes}/routelist.ts | 23 +-
.../components/signalk-details.component.css | 0
.../components/signalk-details.component.ts | 2 +-
.../components/tracks/track-list-modal.ts | 239 +++
.../waypoints}/waypointlist.html | 0
.../waypoints}/waypointlist.ts | 23 +-
src/app/modules/skresources/index.ts | 32 +
src/app/modules/skresources/notes/index.ts | 2 -
.../modules/skresources/resource-dialogs.ts | 1689 -----------------
.../modules/skresources/resources.module.ts | 121 --
.../modules/skresources/resources.service.ts | 7 +-
.../resource-set.ts => resourceset-class.ts} | 0
...sets.service.ts => resourceset-service.ts} | 2 +-
src/app/modules/skstream/skstream.module.ts | 15 -
src/app/modules/weather/index.ts | 1 +
.../weather-data.component.ts | 26 +
.../weather-forecast-modal.ts} | 28 +-
src/app/types/index.d.ts | 2 +
src/assets/help/img/ais_shiptypes.png | Bin 0 -> 31928 bytes
src/assets/help/index.html | 51 +-
src/assets/img/ais_buddy.png | Bin 207 -> 286 bytes
src/assets/img/ais_cargo.png | Bin 286 -> 214 bytes
src/assets/img/ais_highspeed.png | Bin 0 -> 249 bytes
src/assets/img/ais_passenger.png | Bin 249 -> 269 bytes
src/assets/img/ais_tanker.png | Bin 269 -> 242 bytes
src/index.html | 6 -
tsconfig.json | 2 +-
120 files changed, 4032 insertions(+), 3057 deletions(-)
rename src/app/lib/components/dialogs/{ => geojson}/geojson-dialog.css (100%)
rename src/app/lib/components/dialogs/{ => geojson}/geojson-dialog.facade.ts (100%)
rename src/app/lib/components/dialogs/{ => geojson}/geojson-dialog.html (100%)
rename src/app/lib/components/dialogs/{ => geojson}/geojson-dialog.ts (100%)
delete mode 100644 src/app/modules/alarms/alarms.module.ts
create mode 100644 src/app/modules/alarms/index.ts
rename src/app/{lib/components => modules/autopilot}/autopilot.component.css (100%)
rename src/app/{lib/components => modules/autopilot}/autopilot.component.ts (100%)
create mode 100644 src/app/modules/autopilot/index.ts
rename src/app/{lib/components => modules/course}/course-settings.ts (100%)
create mode 100644 src/app/modules/course/index.ts
delete mode 100644 src/app/modules/experiments/experiments.module.ts
create mode 100644 src/app/modules/experiments/index.ts
delete mode 100644 src/app/modules/experiments/weather/weather.module.ts
delete mode 100644 src/app/modules/map/components/navigation/index.ts
delete mode 100644 src/app/modules/map/components/popover/index.ts
delete mode 100644 src/app/modules/map/components/popover/popover.component.ts
delete mode 100644 src/app/modules/map/components/profiles/default/index.ts
create mode 100644 src/app/modules/map/index.ts
delete mode 100644 src/app/modules/map/map.module.ts
create mode 100644 src/app/modules/map/ol/lib/navigation/layer-target-angle.component.ts
create mode 100644 src/app/modules/map/popovers/aircraft-popover.component.ts
create mode 100644 src/app/modules/map/popovers/alarm-popover.component.ts
create mode 100644 src/app/modules/map/popovers/aton-popover.component.ts
rename src/app/modules/map/{components/popover => popovers}/compass.component.svg (100%)
rename src/app/modules/map/{components/popover => popovers}/compass.component.ts (98%)
create mode 100644 src/app/modules/map/popovers/featurelist-popover.component.ts
create mode 100644 src/app/modules/map/popovers/index.ts
rename src/app/modules/map/{components/popover => popovers}/popover.component.scss (100%)
create mode 100644 src/app/modules/map/popovers/popover.component.ts
rename src/app/modules/map/{components/popover => popovers}/resource-popover.component.ts (96%)
rename src/app/modules/map/{components/profiles/default => popovers}/vessel-popover.component.ts (92%)
create mode 100644 src/app/modules/map/vessel-calcs.types.ts
create mode 100644 src/app/modules/map/vessel-calcs.worker.ts
rename src/app/modules/settings/{ => components}/settings-dialog.css (100%)
rename src/app/modules/settings/{ => components}/settings-dialog.html (100%)
rename src/app/modules/settings/{ => components}/settings-dialog.ts (67%)
rename src/app/modules/settings/{settings.module.ts => index.ts} (80%)
create mode 100644 src/app/modules/skresources/components/active-resource-dialog.ts
create mode 100644 src/app/modules/skresources/components/ais/aircraft-properties-modal.ts
create mode 100644 src/app/modules/skresources/components/ais/ais-properties-modal.ts
rename src/app/modules/skresources/{lists => components/ais}/aislist.html (74%)
rename src/app/modules/skresources/{lists => components/ais}/aislist.ts (56%)
create mode 100644 src/app/modules/skresources/components/ais/aton-properties-modal.ts
create mode 100644 src/app/modules/skresources/components/charts/chart-properties-dialog.ts
rename src/app/modules/skresources/{lists => components/charts}/chartlist.html (82%)
rename src/app/modules/skresources/{lists => components/charts}/chartlist.ts (86%)
rename src/app/modules/skresources/{ => components}/notes/note-dialog.html (98%)
rename src/app/modules/skresources/{ => components}/notes/note-dialog.ts (100%)
rename src/app/modules/skresources/{lists => components/notes}/notelist.html (100%)
rename src/app/modules/skresources/{lists => components/notes}/notelist.ts (79%)
rename src/app/modules/skresources/{ => components}/notes/notes.css (100%)
rename src/app/modules/skresources/{ => components}/notes/relatednotes-dialog.html (92%)
rename src/app/modules/skresources/{ => components}/notes/relatednotes-dialog.ts (100%)
rename src/app/modules/skresources/{ => components}/notes/safe.pipe.ts (100%)
create mode 100644 src/app/modules/skresources/components/resource-dialog.ts
rename src/app/modules/skresources/{lists => components}/resourcelist.css (76%)
rename src/app/modules/skresources/{sets => components/resourcesets}/resource-upload-dialog.css (100%)
rename src/app/modules/skresources/{sets => components/resourcesets}/resource-upload-dialog.html (100%)
rename src/app/modules/skresources/{sets => components/resourcesets}/resource-upload-dialog.ts (61%)
create mode 100644 src/app/modules/skresources/components/resourcesets/resourceset-feature-properties-modal.ts
create mode 100644 src/app/modules/skresources/components/resourcesets/resourceset-list-modal.ts
rename src/app/{lib/components => modules/skresources/components/routes}/build-route.component.css (98%)
rename src/app/{lib/components => modules/skresources/components/routes}/build-route.component.ts (100%)
rename src/app/modules/{map/components/navigation => skresources/components/routes}/nextpoint.component.ts (89%)
rename src/app/modules/skresources/{lists => components/routes}/routelist.html (100%)
rename src/app/modules/skresources/{lists => components/routes}/routelist.ts (83%)
rename src/app/{lib => modules/skresources}/components/signalk-details.component.css (100%)
rename src/app/{lib => modules/skresources}/components/signalk-details.component.ts (98%)
create mode 100644 src/app/modules/skresources/components/tracks/track-list-modal.ts
rename src/app/modules/skresources/{lists => components/waypoints}/waypointlist.html (100%)
rename src/app/modules/skresources/{lists => components/waypoints}/waypointlist.ts (84%)
create mode 100644 src/app/modules/skresources/index.ts
delete mode 100644 src/app/modules/skresources/notes/index.ts
delete mode 100644 src/app/modules/skresources/resource-dialogs.ts
delete mode 100644 src/app/modules/skresources/resources.module.ts
rename src/app/modules/skresources/{sets/resource-set.ts => resourceset-class.ts} (100%)
rename src/app/modules/skresources/{sets/resource-sets.service.ts => resourceset-service.ts} (98%)
delete mode 100644 src/app/modules/skstream/skstream.module.ts
create mode 100644 src/app/modules/weather/index.ts
rename src/app/modules/{experiments/weather/components => weather}/weather-data.component.ts (89%)
rename src/app/modules/{experiments/weather/weather-forecast.ts => weather/weather-forecast-modal.ts} (88%)
create mode 100644 src/assets/help/img/ais_shiptypes.png
create mode 100644 src/assets/img/ais_highspeed.png
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 542761f60..ae3d617d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
# CHANGELOG: Freeboard
+### v2.9.0
+
+- **Added**: Ability to filter vessels by `AIS Ship Type` (#163).
+- **Added**: Display `performance.beatAngle` vectors on the map.
+- **Fixed**: Meteo properties `environment.water.waves` display formatting.
+- **Fixed**: Anchor watch not available when plugin is installed and enabled.
+- **Fixed**: Laylines not displayed if performance paths do not contain values.
+- **Updated**: Don't show internet map service dialog in kiosk mode. (#166)
+- **Updated**: Angular framework to v18
+
### v2.8.4
- **Fixed**: shore.basestation popover & properties not displayed.
diff --git a/angular.json b/angular.json
index f02497b08..234f6ae87 100644
--- a/angular.json
+++ b/angular.json
@@ -15,12 +15,16 @@
"prefix": "app",
"architect": {
"build": {
- "builder": "@angular-devkit/build-angular:browser",
+ "builder": "@angular-devkit/build-angular:application",
"options": {
- "outputPath": "public",
+ "outputPath": {
+ "base": "public",
+ "browser": ""
+ },
"index": "src/index.html",
- "main": "src/main.ts",
- "polyfills": "src/polyfills.ts",
+ "polyfills": [
+ "src/polyfills.ts"
+ ],
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
@@ -33,9 +37,7 @@
"src/styles.scss"
],
"scripts": [],
- "vendorChunk": true,
"extractLicenses": false,
- "buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true,
@@ -43,7 +45,8 @@
"allowedCommonJsDependencies": [
"geolib",
"simplify-ts"
- ]
+ ],
+ "browser": "src/main.ts"
},
"configurations": {
"production": {
@@ -58,8 +61,6 @@
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
"budgets": [
{
"type": "initial",
diff --git a/package.json b/package.json
index ac31c5f32..e87a848fd 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@signalk/freeboard-sk",
- "version": "2.8.4",
+ "version": "2.9.0",
"description": "Openlayers chart plotter implementation for Signal K",
"keywords": [
"signalk-webapp",
@@ -43,19 +43,19 @@
"tslib": "^2.0.0"
},
"devDependencies": {
- "@angular-devkit/build-angular": "^17.3.0",
- "@angular/animations": "^17.3.0",
- "@angular/cdk": "^17.3.0",
- "@angular/cli": "^17.3.0",
- "@angular/common": "^17.3.0",
- "@angular/compiler": "^17.3.0",
- "@angular/compiler-cli": "^17.3.0",
- "@angular/core": "^17.3.0",
- "@angular/forms": "^17.3.0",
- "@angular/language-service": "^17.3.0",
- "@angular/material": "^17.3.0",
- "@angular/platform-browser": "^17.3.0",
- "@angular/platform-browser-dynamic": "^17.3.0",
+ "@angular-devkit/build-angular": "^18.0.5",
+ "@angular/animations": "^18.0.4",
+ "@angular/cdk": "^18.0.4",
+ "@angular/cli": "^18.0.5",
+ "@angular/common": "^18.0.4",
+ "@angular/compiler": "^18.0.4",
+ "@angular/compiler-cli": "^18.0.4",
+ "@angular/core": "^18.0.4",
+ "@angular/forms": "^18.0.4",
+ "@angular/language-service": "^18.0.4",
+ "@angular/material": "^18.0.4",
+ "@angular/platform-browser": "^18.0.4",
+ "@angular/platform-browser-dynamic": "^18.0.4",
"@kolkov/angular-editor": "^2.1.0",
"@types/arcgis-rest-api": "^10.4.5",
"@types/express": "^4.17.17",
@@ -77,7 +77,7 @@
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
- "ng-packagr": "^17.3.0",
+ "ng-packagr": "^18.0.0",
"ngeohash": "^0.6.3",
"ol": "^9.0.0",
"ol-mapbox-style": "^12.2.1",
@@ -98,4 +98,4 @@
"xml2js": "^0.6.2",
"zone.js": "~0.14.4"
}
-}
+}
\ No newline at end of file
diff --git a/src/app-theme.scss b/src/app-theme.scss
index bcffae9fa..146f9c463 100644
--- a/src/app-theme.scss
+++ b/src/app-theme.scss
@@ -4,33 +4,33 @@
@include mat.core();
// Define a theme.
-$my-primary: mat.define-palette(mat.$indigo-palette, 500,700,200);
-$my-accent: mat.define-palette(mat.$amber-palette, 500,700,200);
+$my-primary: mat.m2-define-palette(mat.$m2-indigo-palette, 500,700,200);
+$my-accent: mat.m2-define-palette(mat.$m2-amber-palette, 500,700,200);
// The "warn" palette is optional and defaults to red if not specified.
-$my-warn: mat.define-palette(mat.$red-palette, 500,700,200);
+$my-warn: mat.m2-define-palette(mat.$m2-red-palette, 500,700,200);
-$my-theme: mat.define-light-theme((
+$my-theme: mat.m2-define-light-theme((
color: (
primary: $my-primary,
accent: $my-accent,
warn: $my-warn,
),
- typography: mat.define-typography-config(),
+ typography: mat.m2-define-typography-config(),
density: 0,
));
// Define a dark theme.
-$my-dark-primary: mat.define-palette(mat.$light-blue-palette, 200,300,400);
-$my-dark-accent: mat.define-palette(mat.$amber-palette, A400, A100, A700);
-$my-dark-warn: mat.define-palette(mat.$deep-orange-palette, A400);
+$my-dark-primary: mat.m2-define-palette(mat.$m2-light-blue-palette, 200,300,400);
+$my-dark-accent: mat.m2-define-palette(mat.$m2-amber-palette, A400, A100, A700);
+$my-dark-warn: mat.m2-define-palette(mat.$m2-deep-orange-palette, A400);
-$my-dark-theme: mat.define-dark-theme((
+$my-dark-theme: mat.m2-define-dark-theme((
color: (
primary: $my-dark-primary,
accent: $my-dark-accent,
warn: $my-dark-warn,
),
- typography: mat.define-typography-config(),
+ typography: mat.m2-define-typography-config(),
density: 0,
));
@@ -38,11 +38,11 @@ $my-dark-theme: mat.define-dark-theme((
@include mat.all-component-colors($my-dark-theme);
.about-row .item a {
- color: mat.get-color-from-palette($my-dark-accent);
+ color: mat.m2-get-color-from-palette($my-dark-accent);
}
.welcome a {
- color: mat.get-color-from-palette($my-dark-accent);
+ color: mat.m2-get-color-from-palette($my-dark-accent);
}
.popover > .arrow:after {
@@ -55,12 +55,12 @@ $my-dark-theme: mat.define-dark-theme((
border-top-color: mat.get-theme-color($my-dark-theme, background, background);
}
- /* Track */
+
::-webkit-scrollbar-track {
background: rgba(0,0,0,.5);
}
- /* Handle on hover */
+
::-webkit-scrollbar-thumb:hover {
background: #999;
}
@@ -82,26 +82,26 @@ $my-dark-theme: mat.define-dark-theme((
// std elements
.about-row .item a {
- color: mat.get-color-from-palette($my-primary);
+ color: mat.m2-get-color-from-palette($my-primary);
}
-/* width */
+
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
-/* Track */
+
::-webkit-scrollbar-track {
background: #f1f1f1;
}
-/* Handle */
+
::-webkit-scrollbar-thumb {
background: #888;
}
-/* Handle on hover */
+
::-webkit-scrollbar-thumb:hover {
background: #555;
}
@@ -110,4 +110,3 @@ $my-dark-theme: mat.define-dark-theme((
// Include all theme styles for the components.
@include mat.all-component-themes($my-theme);
-
diff --git a/src/app/app.component.css b/src/app/app.component.css
index 4cbaee309..4e00c52d7 100644
--- a/src/app/app.component.css
+++ b/src/app/app.component.css
@@ -39,6 +39,7 @@ mat-nav-list {
padding-left: 0px;
z-index: 5000;
background-color: rgba(200,200,200,.4);
+ width: 315px;
}
.buttonPanel {
diff --git a/src/app/app.component.html b/src/app/app.component.html
index c8e7c0fa9..e0c9bf779 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -6,14 +6,14 @@
mat-menu-item
(click)="sidemenu.close(); displayLeftMenu('routeList', true)"
>
- directions
+ directions
Routes
} @default {
@@ -128,11 +128,11 @@
- directions
+ directions
Draw Route
- directions
+ directions
Build Route
@@ -143,24 +143,24 @@
skres.showWaypointEditor(null, app.data.vessels.active.position)
"
>
- add_location
+ add_location
Add Waypoint at Vessel
}
- edit_location
+ edit_location
Drop Waypoint
@if(this.app.config.map.zoomLevel >=
this.app.config.selections.notesMinZoom) {
- local_offer
+ local_offer
Add Note
}
- tab_unselected
+ tab_unselected
Draw Region
@@ -375,6 +375,7 @@
+
+ `,
+ styles: [
+ `
+ ._ap-dest {
+ font-family: arial;
+ min-width: 300px;
+ }
+ ._ap-dest .key-label {
+ width: 50px;
+ font-weight: bold;
+ }
+ ._ap-dest .selected {
+ background-color: silver;
+ }
+ .point-drop-placeholder {
+ background: #ccc;
+ border: dotted 3px #999;
+ min-height: 60px;
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+ }
+ .cdk-drag-preview {
+ box-sizing: border-box;
+ border-radius: 4px;
+ box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
+ 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
+ }
+ `
+ ]
+})
+export class ActiveResourcePropertiesModal implements OnInit {
+ protected points: Array = [];
+ protected pointMeta: Array<{ name: string; description: string }> = [];
+ protected legs: { bearing: string; distance: string }[] = [];
+ protected selIndex = -1;
+ protected clearButtonText = 'Clear';
+ protected showClearButton = false;
+
+ constructor(
+ public app: AppInfo,
+ public modalRef: MatBottomSheetRef,
+ @Inject(MAT_BOTTOM_SHEET_DATA)
+ public data: {
+ title: string;
+ type: string;
+ resource: SKWaypoint | SKRoute;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ skres: any;
+ }
+ ) {}
+
+ ngOnInit() {
+ if (
+ this.data.resource[1].feature &&
+ this.data.resource[1].feature.geometry.coordinates
+ ) {
+ if (this.data.type === 'route') {
+ this.points = [].concat(
+ this.data.resource[1].feature.geometry.coordinates
+ );
+ this.legs = this.getLegs();
+
+ this.data.title = this.data.resource[1].name
+ ? `${this.data.resource[1].name} Points`
+ : 'Route Points';
+
+ if (this.data.resource[0] === this.app.data.activeRoute) {
+ this.selIndex = this.app.data.navData.pointIndex;
+ this.showClearButton = true;
+ }
+ this.pointMeta = this.getPointMeta();
+ }
+ }
+ }
+
+ getLegs() {
+ const pos = this.app.data.vessels.self.position;
+ return GeoUtils.routeLegs(this.points, pos).map((l) => {
+ return {
+ bearing: this.app.formatValueForDisplay(l.bearing, 'deg'),
+ distance: this.app.formatValueForDisplay(l.distance, 'm')
+ };
+ });
+ }
+
+ getPointMeta() {
+ if (
+ this.data.resource[1].feature.properties.coordinatesMeta &&
+ Array.isArray(this.data.resource[1].feature.properties.coordinatesMeta)
+ ) {
+ const pointsMeta =
+ this.data.resource[1].feature.properties.coordinatesMeta;
+ let idx = 0;
+ return pointsMeta.map((pt) => {
+ idx++;
+ if (pt.href) {
+ const id = pt.href.split('/').slice(-1);
+ const wpt = this.data.skres.fromCache('waypoints', id[0]);
+ return wpt
+ ? {
+ name: `* ${wpt[1].name}`,
+ description: `* ${wpt[1].description}`
+ }
+ : {
+ name: '!wpt reference!',
+ description: ''
+ };
+ } else {
+ return {
+ name: pt.name ?? `RtePt-${('000' + String(idx)).slice(-3)}`,
+ description: pt.description ?? ``
+ };
+ }
+ });
+ } else {
+ let idx = 0;
+ return this.points.map(() => {
+ return {
+ name: `RtePt-${('000' + String(++idx)).slice(-3)}`,
+ description: ''
+ };
+ });
+ }
+ }
+
+ selectPoint(idx: number) {
+ if (this.points.length < 2 || this.selIndex < 0) {
+ return;
+ }
+ this.selIndex = idx;
+ if (this.data.skres) {
+ this.data.skres.coursePointIndex(this.selIndex);
+ }
+ }
+
+ drop(e: CdkDragDrop<{ previousIndex: number; currentIndex: number }>) {
+ if (this.data.type === 'route') {
+ const selPosition = this.points[this.selIndex];
+ moveItemInArray(this.points, e.previousIndex, e.currentIndex);
+ this.legs = this.getLegs();
+ if (this.data.resource[1].feature.properties.coordinatesMeta) {
+ moveItemInArray(
+ this.data.resource[1].feature.properties.coordinatesMeta,
+ e.previousIndex,
+ e.currentIndex
+ );
+ }
+ this.pointMeta = this.getPointMeta();
+
+ this.updateFlag(selPosition);
+ this.data.skres.updateRouteCoords(
+ this.data.resource[0],
+ this.points,
+ this.data.resource[1].feature.properties.coordinatesMeta
+ );
+ }
+ }
+
+ updateFlag(selPosition: Position) {
+ if (!selPosition) {
+ return;
+ }
+ let idx = 0;
+ this.points.forEach((p: Position) => {
+ if (p[0] === selPosition[0] && p[1] === selPosition[1]) {
+ this.selIndex = idx;
+ }
+ idx++;
+ });
+ }
+
+ close() {
+ this.modalRef.dismiss();
+ }
+
+ // ** deactivate route / clear destination
+ deactivate() {
+ this.modalRef.dismiss(true);
+ }
+}
diff --git a/src/app/modules/skresources/components/ais/aircraft-properties-modal.ts b/src/app/modules/skresources/components/ais/aircraft-properties-modal.ts
new file mode 100644
index 000000000..a28e40a03
--- /dev/null
+++ b/src/app/modules/skresources/components/ais/aircraft-properties-modal.ts
@@ -0,0 +1,143 @@
+import { Component, Inject } from '@angular/core';
+import {
+ MatBottomSheetRef,
+ MAT_BOTTOM_SHEET_DATA
+} from '@angular/material/bottom-sheet';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { MatIconModule } from '@angular/material/icon';
+import { MatCardModule } from '@angular/material/card';
+import { MatButtonModule } from '@angular/material/button';
+import { MatToolbarModule } from '@angular/material/toolbar';
+
+import { AppInfo } from 'src/app/app.info';
+import { SignalKClient } from 'signalk-client-angular';
+import { SKAircraft } from 'src/app/modules/skresources/resource-classes';
+import { SignalKDetailsComponent } from '../../components/signalk-details.component';
+
+/********* AircraftPropertiesModal **********
+ data: {
+ title: "" title text,
+ target: "" aid to navigation
+ }
+***********************************/
+@Component({
+ selector: 'ap-aircraft-modal',
+ standalone: true,
+ imports: [
+ MatTooltipModule,
+ MatIconModule,
+ MatCardModule,
+ MatButtonModule,
+ MatToolbarModule,
+ SignalKDetailsComponent
+ ],
+ template: `
+
+
+
+ airplanemode_active
+
+
+ {{ data.title }}
+
+
+
+
+
+
+
+
+
+
+
Name:
+
{{ data.target.name }}
+
+
+
MMSI:
+
{{ data.target.mmsi }}
+
+
+
Call sign:
+
{{ data.target.callsign }}
+
+
+ @if(showProperties) {
+
+ }
+
+
+
+
+ `,
+ styles: [
+ `
+ ._ap-aircraft {
+ font-family: arial;
+ min-width: 300px;
+ }
+ ._ap-aircraft .key-label {
+ width: 150px;
+ font-weight: bold;
+ }
+ `
+ ]
+})
+export class AircraftPropertiesModal {
+ protected showProperties = true;
+ protected properties: { [key: string]: string | number | null };
+
+ constructor(
+ private sk: SignalKClient,
+ private app: AppInfo,
+ public modalRef: MatBottomSheetRef,
+ @Inject(MAT_BOTTOM_SHEET_DATA)
+ public data: {
+ title: string;
+ target: SKAircraft;
+ id: string;
+ icon: string;
+ }
+ ) {}
+
+ ngOnInit() {
+ this.getAircraftInfo();
+ }
+
+ // fetch object information
+ private getAircraftInfo() {
+ if (!this.data.id) {
+ return;
+ }
+ const path = this.data.id.split('.').join('/');
+
+ this.sk.api.get(path).subscribe((v) => {
+ this.properties = this.parseAircraft(v);
+ });
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ private parseAircraft(data: any) {
+ const res = {};
+
+ if (data.navigation && data.navigation.position) {
+ res['navigation.position'] = data.navigation.position.value;
+ }
+ return res;
+ }
+
+ toggleProperties() {
+ this.showProperties = !this.showProperties;
+ }
+}
diff --git a/src/app/modules/skresources/components/ais/ais-properties-modal.ts b/src/app/modules/skresources/components/ais/ais-properties-modal.ts
new file mode 100644
index 000000000..1c44877bc
--- /dev/null
+++ b/src/app/modules/skresources/components/ais/ais-properties-modal.ts
@@ -0,0 +1,261 @@
+import { Component, OnInit, Inject } from '@angular/core';
+import {
+ MatBottomSheetRef,
+ MAT_BOTTOM_SHEET_DATA
+} from '@angular/material/bottom-sheet';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { MatIconModule } from '@angular/material/icon';
+import { MatCardModule } from '@angular/material/card';
+import { MatButtonModule } from '@angular/material/button';
+import { MatToolbarModule } from '@angular/material/toolbar';
+
+import { AppInfo } from 'src/app/app.info';
+import { SignalKClient } from 'signalk-client-angular';
+import { SKVessel } from 'src/app/modules/skresources/resource-classes';
+import { Convert } from 'src/app/lib/convert';
+
+/********* AISPropertiesModal **********
+ data: {
+ title: "" title text,
+ target: "" vessel,
+ id: vessel id
+ }
+***********************************/
+@Component({
+ selector: 'ap-ais-modal',
+ standalone: true,
+ imports: [
+ MatTooltipModule,
+ MatIconModule,
+ MatCardModule,
+ MatButtonModule,
+ MatToolbarModule
+ ],
+ template: `
+
+
+
+ directions_boat
+
+
+ {{ data.title }}
+
+
+
+
+
+
+
+
+
+
+
Name:
+
{{ vInfo.name }}
+
+
+
MMSI:
+
{{ vInfo.mmsi }}
+
+ @if(vInfo.shipType) {
+
+
Type:
+
{{ vInfo.shipType }}
+
+ } @if(vInfo.flag) {
+
+
Flag:
+
{{ vInfo.flag }}
+
+ } @if(vInfo.port) {
+
+
Port:
+
{{ vInfo.port }}
+
+ } @if(vInfo.callsign) {
+
+
Call sign:
+
{{ vInfo.callsign }}
+
+ } @if(vInfo.length) {
+
+
Dimensions:
+
+ {{ vInfo.length }} x {{ vInfo.beam }}
+
+
+ } @if(vInfo.draft) {
+
+
Draft:
+
{{ vInfo.draft }}
+
+ } @if(vInfo.height) {
+
+
Height:
+
{{ vInfo.height }}
+
+ } @if(vInfo.state) {
+
+
State:
+
{{ vInfo.state }}
+
+ } @if(vInfo.destination) {
+
+
Destination:
+
{{ vInfo.destination }}
+
+ } @if(vInfo.eta) {
+
+
ETA:
+
+ {{ vInfo.eta.toLocaleString() }}
+
+
+ }
+
+
+
+
+ `,
+ styles: [
+ `
+ ._ap-ais {
+ font-family: arial;
+ }
+ ._ap-ais .key-label {
+ width: 150px;
+ font-weight: bold;
+ }
+ `
+ ]
+})
+export class AISPropertiesModal implements OnInit {
+ public vInfo = {
+ name: null,
+ mmsi: null,
+ callsign: null,
+ length: null,
+ beam: null,
+ draft: null,
+ height: null,
+ shipType: null,
+ destination: null,
+ eta: null,
+ state: null,
+ flag: null,
+ port: null
+ };
+
+ constructor(
+ public app: AppInfo,
+ private sk: SignalKClient,
+ public modalRef: MatBottomSheetRef,
+ @Inject(MAT_BOTTOM_SHEET_DATA)
+ public data: {
+ title: string;
+ target: SKVessel;
+ id: string;
+ }
+ ) {}
+
+ ngOnInit() {
+ this.getVesselInfo();
+ }
+
+ formatDegrees(val: number) {
+ return val
+ ? `${Convert.radiansToDegrees(val).toFixed(1)} ${String.fromCharCode(
+ 186
+ )}`
+ : '0.0';
+ }
+
+ formatKnots(val: number) {
+ return val ? `${Convert.msecToKnots(val).toFixed(1)} kn` : '0.0';
+ }
+
+ private getVesselInfo() {
+ let path: string;
+ if (!this.data.id) {
+ path = 'vessels/self';
+ } else {
+ path = this.data.id.split('.').join('/');
+ }
+
+ this.sk.api.get(path).subscribe((v) => {
+ if (typeof v['name'] !== 'undefined') {
+ this.vInfo.name = v['name'];
+ }
+ if (typeof v['mmsi'] !== 'undefined') {
+ this.vInfo.mmsi = v['mmsi'];
+ }
+ if (typeof v['flag'] !== 'undefined') {
+ this.vInfo.flag = v['flag'];
+ }
+ if (typeof v['port'] !== 'undefined') {
+ this.vInfo.port = v['port'];
+ }
+ if (typeof v['communication'] !== 'undefined') {
+ if (typeof v['communication']['callsignVhf'] !== 'undefined') {
+ this.vInfo.callsign = v['communication']['callsignVhf'];
+ }
+ }
+ if (typeof v['navigation'] !== 'undefined') {
+ if (typeof v['navigation']['destination'] !== 'undefined') {
+ if (
+ typeof v['navigation']['destination']['commonName'] !== 'undefined'
+ ) {
+ this.vInfo.destination =
+ v['navigation']['destination']['commonName']['value'];
+ }
+ if (typeof v['navigation']['destination']['eta'] !== 'undefined') {
+ this.vInfo.eta = new Date(
+ v['navigation']['destination']['eta']['value']
+ ).toUTCString();
+ }
+ }
+ if (
+ typeof v['navigation']['state'] !== 'undefined' &&
+ typeof v['navigation']['state']['value'] !== 'undefined'
+ ) {
+ this.vInfo.state = v['navigation']['state']['value'];
+ }
+ }
+ if (typeof v['design'] !== 'undefined') {
+ if (
+ typeof v['design']['length'] !== 'undefined' &&
+ v['design']['length']['value']['overall']
+ ) {
+ this.vInfo.length = v['design']['length']['value']['overall'];
+ }
+ if (typeof v['design']['beam'] !== 'undefined') {
+ this.vInfo.beam = v['design']['beam']['value'];
+ }
+ if (
+ typeof v['design']['draft'] !== 'undefined' &&
+ v['design']['draft']['value']
+ ) {
+ if (typeof v['design']['draft']['value']['maximum'] !== 'undefined') {
+ this.vInfo.draft = `${v['design']['draft']['value']['maximum']} (max)`;
+ } else if (
+ typeof v['design']['draft']['value']['current'] !== 'undefined'
+ ) {
+ this.vInfo.draft = `${v['design']['draft']['value']['current']} (current)`;
+ }
+ }
+ if (typeof v['design']['airHeight'] !== 'undefined') {
+ this.vInfo.height = v['design']['airHeight']['value'];
+ }
+ if (typeof v['design']['aisShipType'] !== 'undefined') {
+ this.vInfo.shipType = v['design']['aisShipType']['value']['name'];
+ }
+ }
+ });
+ }
+}
diff --git a/src/app/modules/skresources/lists/aislist.html b/src/app/modules/skresources/components/ais/aislist.html
similarity index 74%
rename from src/app/modules/skresources/lists/aislist.html
rename to src/app/modules/skresources/components/ais/aislist.html
index b7aea59ac..7bacd2632 100644
--- a/src/app/modules/skresources/lists/aislist.html
+++ b/src/app/modules/skresources/components/ais/aislist.html
@@ -24,6 +24,7 @@
#ftext
type="text"
matInput
+ [disabled]="app.config.selections.aisFilterByShipType"
[value]="filterText"
(keyup)="filterKeyUp(ftext.value)"
/>
@@ -40,6 +41,7 @@
(click)="initItems()"
matTooltip="Reload Vessels"
matTooltipPosition="left"
+ [disabled]="app.config.selections.aisFilterByShipType"
>
refresh
@@ -49,6 +51,7 @@
#selall
color="primary"
[checked]="allSel"
+ [disabled]="app.config.selections.aisFilterByShipType"
[indeterminate]="someSel"
(change)="selectAll($event.checked)"
[matTooltip]="(!selall.checked || someSel) ? 'Select All' : 'Deselect All'"
@@ -58,9 +61,50 @@
+
+
+ Filter by Vessel type
+
+
-
+
+ @if (app.config.selections.aisFilterByShipType) {
+
+
+ @for (i of shipTypes; track i.id) {
+
+
+
+
+
+
+ {{i.description}}
+
+ @if(i.id !==0){ ({{i.id}}-{{i.id + 9}}) }
+
+
+
+
+
+
+
+
+ }
+
+
+
+ } @else {
+ }
diff --git a/src/app/modules/skresources/lists/aislist.ts b/src/app/modules/skresources/components/ais/aislist.ts
similarity index 56%
rename from src/app/modules/skresources/lists/aislist.ts
rename to src/app/modules/skresources/components/ais/aislist.ts
index 3bbe2e4b3..bf998a796 100644
--- a/src/app/modules/skresources/lists/aislist.ts
+++ b/src/app/modules/skresources/components/ais/aislist.ts
@@ -5,6 +5,17 @@ import {
EventEmitter,
ChangeDetectionStrategy
} from '@angular/core';
+
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { MatIconModule } from '@angular/material/icon';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatButtonModule } from '@angular/material/button';
+import { FormsModule } from '@angular/forms';
+import { MatInputModule } from '@angular/material/input';
+import { ScrollingModule } from '@angular/cdk/scrolling';
+import { MatSlideToggleModule } from '@angular/material/slide-toggle';
+
import { AppInfo } from 'src/app/app.info';
import { SKVessel } from 'src/app/modules';
import { Position } from 'src/app/types';
@@ -12,9 +23,21 @@ import { Position } from 'src/app/types';
//** AIS Dialog **
@Component({
selector: 'ais-list',
+ standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './aislist.html',
- styleUrls: ['./resourcelist.css']
+ styleUrls: ['../resourcelist.css'],
+ imports: [
+ MatTooltipModule,
+ MatIconModule,
+ MatCardModule,
+ MatCheckboxModule,
+ MatButtonModule,
+ FormsModule,
+ MatInputModule,
+ ScrollingModule,
+ MatSlideToggleModule
+ ]
})
export class AISListComponent {
@Input() aisTargets: Map;
@@ -31,11 +54,69 @@ export class AISListComponent {
filterText = '';
someSel = false;
allSel = false;
+ shipTypes = [
+ {
+ id: 10,
+ description: 'Unspecified',
+ selected: false,
+ icon: './assets/img/ais_active.png'
+ },
+ {
+ id: 20,
+ description: 'Wing in Ground',
+ selected: false,
+ icon: './assets/img/ais_active.png'
+ },
+ {
+ id: 30,
+ description: 'Pleasure',
+ selected: false,
+ icon: './assets/img/ais_active.png'
+ },
+ {
+ id: 40,
+ description: 'High Speed',
+ selected: false,
+ icon: './assets/img/ais_highspeed.png'
+ },
+ {
+ id: 50,
+ description: 'Special',
+ selected: false,
+ icon: './assets/img/ais_special.png'
+ },
+ {
+ id: 60,
+ description: 'Passenger',
+ selected: false,
+ icon: './assets/img/ais_passenger.png'
+ },
+ {
+ id: 70,
+ description: 'Cargo',
+ selected: false,
+ icon: './assets/img/ais_cargo.png'
+ },
+ {
+ id: 80,
+ description: 'Tanker',
+ selected: false,
+ icon: './assets/img/ais_tanker.png'
+ },
+ {
+ id: 90,
+ description: 'Other',
+ selected: false,
+ icon: './assets/img/ais_special.png'
+ }
+ ];
+ otherShiptypes = [10, 20, 30, 90];
constructor(public app: AppInfo) {}
ngOnInit() {
this.initItems();
+ this.alignSelections();
}
close() {
@@ -72,6 +153,34 @@ export class AISListComponent {
this.filterList = this.aisAvailable.slice(0);
}
+ alignSelections() {
+ this.shipTypes.forEach((i) => {
+ i.selected = this.app.config.selections.aisTargetTypes.includes(i.id);
+ });
+ }
+
+ toggleFilterType(e: boolean) {
+ this.app.config.selections.aisFilterByShipType = e;
+ if (e) {
+ this.alignSelections();
+ }
+ this.app.saveConfig();
+ }
+
+ shipTypeSelect(e: boolean, id: number) {
+ const t = [].concat(this.app.config.selections.aisTargetTypes);
+ if (e) {
+ t.push(id);
+ } else {
+ if (t.includes(id)) {
+ t.splice(t.indexOf(id), 1);
+ }
+ }
+ this.app.config.selections.aisTargetTypes = [].concat(t);
+ this.alignSelections();
+ this.app.saveConfig();
+ }
+
checkSelections() {
let c = false;
let u = false;
diff --git a/src/app/modules/skresources/components/ais/aton-properties-modal.ts b/src/app/modules/skresources/components/ais/aton-properties-modal.ts
new file mode 100644
index 000000000..b87792982
--- /dev/null
+++ b/src/app/modules/skresources/components/ais/aton-properties-modal.ts
@@ -0,0 +1,195 @@
+import { Component, OnInit, Inject } from '@angular/core';
+import {
+ MatBottomSheetRef,
+ MAT_BOTTOM_SHEET_DATA
+} from '@angular/material/bottom-sheet';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { MatIconModule } from '@angular/material/icon';
+import { MatCardModule } from '@angular/material/card';
+import { MatButtonModule } from '@angular/material/button';
+import { MatToolbarModule } from '@angular/material/toolbar';
+
+import { AppInfo } from 'src/app/app.info';
+import { SignalKClient } from 'signalk-client-angular';
+import { SKAtoN } from 'src/app/modules/skresources/resource-classes';
+import { SignalKDetailsComponent } from '../../components/signalk-details.component';
+
+/********* AtoNPropertiesModal **********
+ data: {
+ title: "" title text,
+ target: "" aid to navigation
+ icon:
+ }
+***********************************/
+@Component({
+ selector: 'ap-aton-modal',
+ standalone: true,
+ imports: [
+ MatTooltipModule,
+ MatIconModule,
+ MatCardModule,
+ MatButtonModule,
+ MatToolbarModule,
+ SignalKDetailsComponent
+ ],
+ template: `
+
+
+
+ {{ data.icon }}
+
+
+ {{ data.title }}
+
+
+
+
+
+
+
+
+
+
+
Name:
+
{{ data.target.name }}
+
+
+
MMSI:
+
{{ data.target.mmsi }}
+
+
+
Type:
+
{{ data.target.type.name }}
+
+
+ @if(showProperties) {
+
+ }
+
+
+
+
+ `,
+ styles: [
+ `
+ ._ap-aton {
+ font-family: arial;
+ min-width: 300px;
+ }
+ ._ap-aton .key-label {
+ width: 150px;
+ font-weight: bold;
+ }
+ `
+ ]
+})
+export class AtoNPropertiesModal implements OnInit {
+ protected showProperties = true;
+ protected properties: { [key: string]: string | number | null };
+
+ constructor(
+ private sk: SignalKClient,
+ private app: AppInfo,
+ public modalRef: MatBottomSheetRef,
+ @Inject(MAT_BOTTOM_SHEET_DATA)
+ public data: {
+ title: string;
+ target: SKAtoN;
+ id: string;
+ icon: string;
+ type: 'aton' | 'sar' | 'meteo';
+ }
+ ) {}
+
+ ngOnInit() {
+ this.getAtoNInfo();
+ }
+
+ toggleProperties() {
+ this.showProperties = !this.showProperties;
+ }
+
+ // fetch object information
+ private getAtoNInfo() {
+ if (!this.data.id) {
+ return;
+ }
+ const path = this.data.id.split('.').join('/');
+
+ this.sk.api.get(path).subscribe((v) => {
+ if (this.data.type === 'meteo') {
+ this.properties = this.parseMeteo(v);
+ } else {
+ this.properties = this.parseAtoN(v);
+ }
+ });
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ private parseMeteo(data: any) {
+ const res = {};
+
+ if (data.navigation && data.navigation.position) {
+ res['navigation.position'] = data.navigation.position.value;
+ }
+ const bk = data.environment.observation ?? data.environment;
+ const pk = data.environment.observation
+ ? 'environment.observation'
+ : 'environment';
+ if (bk) {
+ this.processPathObject(res, bk, pk);
+ }
+ return res;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ private processPathObject(res: any, bk: any, pk: string) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ Object.keys(bk).forEach((k: any) => {
+ const pathRoot = `${pk}.${k}`;
+ const g = bk[k];
+ if (k === 'water') {
+ this.processPathObject(res, g, pathRoot);
+ } else if (g.meta) {
+ res[pathRoot] = this.app.formatValueForDisplay(
+ g.value,
+ g.meta.units ? g.meta.units : '',
+ k.toLowerCase().includes('level') ||
+ k.toLowerCase().includes('height') // depth values
+ );
+ } else {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ Object.entries(g).forEach((i: any) => {
+ const key = `${pathRoot}.${i[0]}`;
+ res[key] = this.app.formatValueForDisplay(
+ i[1].value,
+ i[1].meta && i[1].meta.units ? i[1].meta.units : '',
+ i[0].toLowerCase().includes('level') ||
+ i[0].toLowerCase().includes('height') // depth values
+ );
+ });
+ }
+ });
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ private parseAtoN(data: any) {
+ const res = {};
+ if (data.navigation && data.navigation.position) {
+ res['navigation.position'] = data.navigation.position.value;
+ }
+ return Object.assign(res, this.data.target.properties);
+ }
+}
diff --git a/src/app/modules/skresources/components/charts/chart-properties-dialog.ts b/src/app/modules/skresources/components/charts/chart-properties-dialog.ts
new file mode 100644
index 000000000..85b7980a0
--- /dev/null
+++ b/src/app/modules/skresources/components/charts/chart-properties-dialog.ts
@@ -0,0 +1,169 @@
+import { Component, Inject } from '@angular/core';
+import {
+ MatDialogModule,
+ MatDialogRef,
+ MAT_DIALOG_DATA
+} from '@angular/material/dialog';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { MatIconModule } from '@angular/material/icon';
+import { MatCardModule } from '@angular/material/card';
+import { MatButtonModule } from '@angular/material/button';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { AppInfo } from 'src/app/app.info';
+import { SKChart } from 'src/app/modules/skresources/resource-classes';
+import { PipesModule } from 'src/app/lib/pipes';
+
+/********* ChartPropertiesDialog **********
+ data:
+***********************************/
+@Component({
+ selector: 'ap-chartproperties',
+ standalone: true,
+ imports: [
+ MatTooltipModule,
+ MatIconModule,
+ MatCardModule,
+ MatButtonModule,
+ MatToolbarModule,
+ MatDialogModule,
+ PipesModule
+ ],
+ template: `
+
+
+ {{ isLocal(data['url']) }}
+ Chart Properties
+
+
+
+
+
+
+
+
Name:
+
{{ data['name'] }}
+
+
+
Description:
+
{{ data['description'] }}
+
+
+
Scale:
+
{{ data['scale'] }}
+
+
+
Zoom:
+
+
+ Min:
+ {{ data['minZoom'] }},
+ Max:
+ {{ data['maxZoom'] }}
+
+
+
+ @if(data['bounds']) {
+
+
Bounds:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+
Format:
+
{{ data['format'] }}
+
+
+
Type:
+
+ {{ data['type'] }}
+
+
+
+
Layers:
+
{{ data['layers'] }}
+
+
+
URL:
+
+ {{ data['url'] }}
+
+
+
+
+
+ `,
+ styles: [
+ `
+ ._ap-chartinfo {
+ font-family: arial;
+ min-width: 300px;
+ }
+ .ap-confirm-icon {
+ min-width: 35px;
+ max-width: 35px;
+ color: darkorange;
+ text-align: left;
+ }
+
+ ._ap-chartinfo .key-label {
+ width: 150px;
+ font-weight: 500;
+ }
+
+ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px),
+ only screen and (min-width: 800px) {
+ .ap-confirm-icon {
+ min-width: 25%;
+ max-width: 25%;
+ }
+ }
+ `
+ ]
+})
+export class ChartPropertiesDialog {
+ public icon: string;
+
+ constructor(
+ public app: AppInfo,
+ public dialogRef: MatDialogRef,
+ @Inject(MAT_DIALOG_DATA) public data: SKChart
+ ) {}
+
+ isLocal(url: string) {
+ return url && url.indexOf('signalk') !== -1 ? 'map' : 'language';
+ }
+}
diff --git a/src/app/modules/skresources/lists/chartlist.html b/src/app/modules/skresources/components/charts/chartlist.html
similarity index 82%
rename from src/app/modules/skresources/lists/chartlist.html
rename to src/app/modules/skresources/components/charts/chartlist.html
index 819664352..ec6ce8794 100644
--- a/src/app/modules/skresources/lists/chartlist.html
+++ b/src/app/modules/skresources/components/charts/chartlist.html
@@ -3,18 +3,6 @@
Charts:
-
-
-