diff --git a/.gitignore b/.gitignore
index f2bf0fc1..38f1f4ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
/node_modules
package-lock.json
.angular
+node_modules
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae3d617d..f579b3f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,14 +1,13 @@
# CHANGELOG: Freeboard
-### v2.9.0
+### v2.9.1
- **Added**: Ability to filter vessels by `AIS Ship Type` (#163).
-- **Added**: Display `performance.beatAngle` vectors on the map.
+- **Added**: Display `performance.beatAngle` and `performance.gybeAngle` 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
diff --git a/angular.json b/angular.json
index 234f6ae8..f02497b0 100644
--- a/angular.json
+++ b/angular.json
@@ -15,16 +15,12 @@
"prefix": "app",
"architect": {
"build": {
- "builder": "@angular-devkit/build-angular:application",
+ "builder": "@angular-devkit/build-angular:browser",
"options": {
- "outputPath": {
- "base": "public",
- "browser": ""
- },
+ "outputPath": "public",
"index": "src/index.html",
- "polyfills": [
- "src/polyfills.ts"
- ],
+ "main": "src/main.ts",
+ "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
@@ -37,7 +33,9 @@
"src/styles.scss"
],
"scripts": [],
+ "vendorChunk": true,
"extractLicenses": false,
+ "buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true,
@@ -45,8 +43,7 @@
"allowedCommonJsDependencies": [
"geolib",
"simplify-ts"
- ],
- "browser": "src/main.ts"
+ ]
},
"configurations": {
"production": {
@@ -61,6 +58,8 @@
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
"budgets": [
{
"type": "initial",
diff --git a/package.json b/package.json
index e87a848f..55def847 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@signalk/freeboard-sk",
- "version": "2.9.0",
+ "version": "2.9.1",
"description": "Openlayers chart plotter implementation for Signal K",
"keywords": [
"signalk-webapp",
@@ -43,19 +43,19 @@
"tslib": "^2.0.0"
},
"devDependencies": {
- "@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",
+ "@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",
"@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": "^18.0.0",
+ "ng-packagr": "^17.3.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 146f9c46..bcffae9f 100644
--- a/src/app-theme.scss
+++ b/src/app-theme.scss
@@ -4,33 +4,33 @@
@include mat.core();
// Define a theme.
-$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);
+$my-primary: mat.define-palette(mat.$indigo-palette, 500,700,200);
+$my-accent: mat.define-palette(mat.$amber-palette, 500,700,200);
// The "warn" palette is optional and defaults to red if not specified.
-$my-warn: mat.m2-define-palette(mat.$m2-red-palette, 500,700,200);
+$my-warn: mat.define-palette(mat.$red-palette, 500,700,200);
-$my-theme: mat.m2-define-light-theme((
+$my-theme: mat.define-light-theme((
color: (
primary: $my-primary,
accent: $my-accent,
warn: $my-warn,
),
- typography: mat.m2-define-typography-config(),
+ typography: mat.define-typography-config(),
density: 0,
));
// Define a dark theme.
-$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-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-theme: mat.m2-define-dark-theme((
+$my-dark-theme: mat.define-dark-theme((
color: (
primary: $my-dark-primary,
accent: $my-dark-accent,
warn: $my-dark-warn,
),
- typography: mat.m2-define-typography-config(),
+ typography: mat.define-typography-config(),
density: 0,
));
@@ -38,11 +38,11 @@ $my-dark-theme: mat.m2-define-dark-theme((
@include mat.all-component-colors($my-dark-theme);
.about-row .item a {
- color: mat.m2-get-color-from-palette($my-dark-accent);
+ color: mat.get-color-from-palette($my-dark-accent);
}
.welcome a {
- color: mat.m2-get-color-from-palette($my-dark-accent);
+ color: mat.get-color-from-palette($my-dark-accent);
}
.popover > .arrow:after {
@@ -55,12 +55,12 @@ $my-dark-theme: mat.m2-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.m2-define-dark-theme((
// std elements
.about-row .item a {
- color: mat.m2-get-color-from-palette($my-primary);
+ color: mat.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,3 +110,4 @@ $my-dark-theme: mat.m2-define-dark-theme((
// Include all theme styles for the components.
@include mat.all-component-themes($my-theme);
+
diff --git a/src/app/app.info.ts b/src/app/app.info.ts
index 9b0deeaf..64deccc1 100644
--- a/src/app/app.info.ts
+++ b/src/app/app.info.ts
@@ -276,7 +276,7 @@ export class AppInfo extends Info {
this.name = 'Freeboard-SK';
this.shortName = 'Freeboard';
this.description = `Signal K Chart Plotter.`;
- this.version = '2.9.0';
+ this.version = '2.9.1';
this.url = 'https://github.com/signalk/freeboard-sk';
this.logo = './assets/img/app_logo.png';
@@ -930,15 +930,16 @@ export class AppInfo extends Info {
for more details.`
},
'whats-new': [
- {
+ /*{
type: 'signalk-server-node',
- title: 'AIS Vessels',
+ title: 'OpenWeather 3.0 Support',
message: `
- Freeboard-SK now supports filtering the disply of vessels by AIS ship type.
+ OpenWeather is deprecating support for v2.5 of their API in April 2024!
- Select Vessels from the menu and turn on View by Vessel type.
+ Freeboard-SK now supports the v3.0 API which will require you to supply
+ a new API Key in the configuration.
`
- }
+ }*/
]
};
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 24c08428..323c84d1 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -1,9 +1,6 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
-import {
- provideHttpClient,
- withInterceptorsFromDi
-} from '@angular/common/http';
+import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatBadgeModule } from '@angular/material/badge';
@@ -14,8 +11,8 @@ import { MatMenuModule } from '@angular/material/menu';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatTooltipModule } from '@angular/material/tooltip';
+// ***
import { AppComponent } from './app.component';
-
import {
FBMapComponent,
ExperimentsComponent,
@@ -42,9 +39,8 @@ import {
@NgModule({
declarations: [AppComponent],
- exports: [],
- bootstrap: [AppComponent],
imports: [
+ HttpClientModule,
MatMenuModule,
MatSidenavModule,
MatBadgeModule,
@@ -74,6 +70,8 @@ import {
AlarmsDialog,
RouteNextPointComponent
],
- providers: [provideHttpClient(withInterceptorsFromDi())]
+ exports: [],
+ providers: [],
+ bootstrap: [AppComponent]
})
export class AppModule {}
diff --git a/src/app/lib/components/dialogs/common/dialogs.component.ts b/src/app/lib/components/dialogs/common/dialogs.component.ts
index 3f7267bf..48fedd40 100644
--- a/src/app/lib/components/dialogs/common/dialogs.component.ts
+++ b/src/app/lib/components/dialogs/common/dialogs.component.ts
@@ -275,9 +275,7 @@ export class ConfirmDialog implements OnInit {
@if(data.url) {
}
diff --git a/src/app/lib/components/index.ts b/src/app/lib/components/index.ts
index 7d6b6bc5..41225086 100644
--- a/src/app/lib/components/index.ts
+++ b/src/app/lib/components/index.ts
@@ -1,7 +1,6 @@
export * from './dial-text';
export * from './file-input.component';
export * from './pip.component';
-export * from '../../modules/skresources/components/signalk-details.component';
export * from './wakelock.component';
export * from './measurements.component';
export * from './dialogs';
diff --git a/src/app/lib/components/wakelock.component.ts b/src/app/lib/components/wakelock.component.ts
index f89aa322..09fdcd42 100644
--- a/src/app/lib/components/wakelock.component.ts
+++ b/src/app/lib/components/wakelock.component.ts
@@ -27,7 +27,6 @@ import { MatTooltipModule } from '@angular/material/tooltip';
@@ -580,7 +580,7 @@
(click)="onContextMenuAction('add_note', item)"
(contextmenu)="$event.preventDefault()"
>
- local_offer
+ local_offer
Add Note here
}
diff --git a/src/app/modules/map/fb-map.component.ts b/src/app/modules/map/fb-map.component.ts
index 0689f2c0..5ac94885 100644
--- a/src/app/modules/map/fb-map.component.ts
+++ b/src/app/modules/map/fb-map.component.ts
@@ -8,7 +8,6 @@ import {
ViewChild,
SimpleChanges
} from '@angular/core';
-
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
@@ -28,18 +27,17 @@ import {
ResourceSetPopoverComponent,
VesselPopoverComponent
} from './popovers';
-
import { FreeboardOpenlayersModule } from 'src/app/modules/map/ol';
import { PipesModule } from 'src/app/lib/pipes';
-import { getGreatCircleBearing } from 'geolib';
+import { computeDestinationPoint, getGreatCircleBearing } from 'geolib';
import { toLonLat } from 'ol/proj';
import { Style, Stroke, Fill } from 'ol/style';
import { Collection, Feature } from 'ol';
import { Feature as GeoJsonFeature } from 'geojson';
import { Convert } from 'src/app/lib/convert';
-import { GeoUtils } from 'src/app/lib/geoutils';
+import { GeoUtils, Angle } from 'src/app/lib/geoutils';
import { Position } from 'src/app/types';
import { AppInfo } from 'src/app/app.info';
@@ -92,7 +90,6 @@ import {
SKNotification
} from 'src/app/types';
import { S57Service } from './ol/lib/s57.service';
-import { VesselLinesResult } from './vessel-calcs.types';
interface IResource {
id: string;
@@ -163,20 +160,6 @@ interface IMeasureInfo {
coords: Position[];
}
-interface VesselLines {
- twd: Array;
- awa: Array;
- cog: Array;
- bearing: Array;
- heading: Array;
- anchor: Array;
- trail: Array;
- cpa: Array;
- xtePath: Array;
- laylines: { port: number[][][]; starboard: number[][][] };
- targetAngle: Array;
-}
-
enum INTERACTION_MODE {
MEASURE,
DRAW,
@@ -258,7 +241,7 @@ export class FBMapComponent implements OnInit, OnDestroy {
coords: []
};
- public vesselLines: VesselLines = {
+ public vesselLines = {
twd: [],
awa: [],
bearing: [],
@@ -266,7 +249,6 @@ export class FBMapComponent implements OnInit, OnDestroy {
anchor: [],
trail: [],
cpa: [],
- cog: [],
xtePath: [],
laylines: { port: [], starboard: [] },
targetAngle: []
@@ -369,8 +351,6 @@ export class FBMapComponent implements OnInit, OnDestroy {
private obsList = [];
- private worker: Worker;
-
constructor(
public app: AppInfo,
public s57Service: S57Service,
@@ -378,12 +358,7 @@ export class FBMapComponent implements OnInit, OnDestroy {
public skresOther: SKOtherResources,
private skstream: SKStreamFacade,
private alarmsFacade: AlarmsFacade
- ) {
- this.worker = new Worker(new URL('./vessel-calcs.worker', import.meta.url));
- this.worker.onmessage = ({ data }) => {
- this.drawVesselLinesResult(data);
- };
- }
+ ) {}
ngAfterViewInit() {
// ** set map focus **
@@ -430,11 +405,6 @@ export class FBMapComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.stopSaveTimer();
this.obsList.forEach((i) => i.unsubscribe());
- if (this.worker) {
- console.log('Terminating Vessel-Calcs Worker....');
- this.worker.terminate();
- this.worker = undefined;
- }
}
ngOnChanges(changes: SimpleChanges) {
@@ -1119,31 +1089,30 @@ export class FBMapComponent implements OnInit, OnDestroy {
}
}
- // center map to active vessel position
+ // ** center map to active vessel position
public centerVessel() {
const t = this.dfeat.active.position;
t[0] += 0.0000000000001;
this.fbMap.center = t;
}
- // trigger line calcs worker
public drawVesselLines(vesselUpdate = false) {
- this.worker.postMessage({
- vesselConfig: this.app.config.vessel,
- vesselSelf: this.app.data.vessels.self,
- vesselActive: this.app.data.vessels.active,
- navData: this.app.data.navData,
- mapZoomLevel: this.fbMap.zoomLevel,
- zoomOffsetLevel: this.zoomOffsetLevel,
- units: this.app.config.units
- });
+ const z = this.fbMap.zoomLevel;
+ const offset = z < 29 ? this.zoomOffsetLevel[Math.floor(z)] : 60;
+ const wMax = 10; // ** max line length
const vl = {
trail: [],
xtePath: [],
bearing: [],
anchor: [],
- cpa: []
+ cpa: [],
+ heading: [],
+ awa: [],
+ twd: [],
+ cog: [],
+ laylines: { port: [], starboard: [] },
+ targetAngle: []
};
// vessel trail
@@ -1177,6 +1146,117 @@ export class FBMapComponent implements OnInit, OnDestroy {
: this.dfeat.active.position;
vl.bearing = [this.dfeat.active.position, bpos];
+ // laylines (active)
+ if (
+ this.app.config.vessel.laylines &&
+ Array.isArray(this.dfeat.navData.position) &&
+ typeof this.dfeat.navData.position[0] === 'number' &&
+ typeof this.app.data.vessels.active.heading === 'number'
+ ) {
+ const twd_deg = Convert.radiansToDegrees(
+ this.app.data.vessels.self.wind.twd
+ );
+ const destUpwind =
+ Math.abs(
+ Angle.difference(this.app.data.navData.bearing.value, twd_deg)
+ ) < 90;
+ const ba_deg = Convert.radiansToDegrees(
+ this.app.data.vessels.self.performance.beatAngle ?? Math.PI / 4
+ );
+ const destInTarget =
+ Math.abs(
+ Angle.difference(this.app.data.navData.bearing.value, twd_deg)
+ ) < ba_deg;
+ const dtg =
+ this.app.config.units.distance === 'm'
+ ? this.app.data.navData.dtg * 1000
+ : Convert.nauticalMilesToKm(this.app.data.navData.dtg * 1000);
+
+ if (destInTarget) {
+ const bta = Angle.add(twd_deg, 90); // tack angle = 90
+
+ const hbd_rad = Convert.degreesToRadians(
+ Angle.difference(twd_deg, this.app.data.navData.bearing.value)
+ );
+ const dist1 = Math.sin(hbd_rad) * dtg;
+ const dist2 = Math.cos(hbd_rad) * dtg;
+ const pt1 = computeDestinationPoint(
+ this.app.data.vessels.active.position,
+ dist1,
+ bta
+ );
+ const pt2 = computeDestinationPoint(
+ this.app.data.vessels.active.position,
+ dist2,
+ twd_deg
+ );
+ const p1a = [
+ this.app.data.vessels.active.position,
+ [pt1.longitude, pt1.latitude]
+ ];
+ const p1b = [
+ [pt1.longitude, pt1.latitude],
+ this.dfeat.navData.position
+ ];
+ const l1 = hbd_rad < 0 ? [p1a, p1b] : [p1b, p1a];
+
+ const p2a = [
+ [pt2.longitude, pt2.latitude],
+ this.dfeat.navData.position
+ ];
+ const p2b = [
+ this.app.data.vessels.active.position,
+ [pt2.longitude, pt2.latitude]
+ ];
+ const l2 = hbd_rad < 0 ? [p2a, p2b] : [p2b, p2a];
+
+ vl.laylines = {
+ port: hbd_rad < 0 ? l2 : l1,
+ starboard: hbd_rad < 0 ? l1 : l2
+ };
+ }
+ // target angle lines
+ if (destUpwind && destInTarget) {
+ const bapt1 = computeDestinationPoint(
+ this.app.data.vessels.active.position,
+ dtg,
+ Angle.add(twd_deg, ba_deg)
+ );
+ const bapt2 = computeDestinationPoint(
+ this.app.data.vessels.active.position,
+ dtg,
+ Angle.add(twd_deg, 0 - ba_deg)
+ );
+ vl.targetAngle = [
+ [bapt1.longitude, bapt1.latitude],
+ this.app.data.vessels.active.position,
+ [bapt2.longitude, bapt2.latitude]
+ ];
+ } else if (
+ !destUpwind &&
+ typeof this.app.data.vessels.self.performance.gybeAngle === 'number'
+ ) {
+ const ga_deg = Convert.radiansToDegrees(
+ this.app.data.vessels.self.performance.gybeAngle
+ );
+ const gapt1 = computeDestinationPoint(
+ this.app.data.vessels.active.position,
+ dtg,
+ Angle.add(this.app.data.navData.bearing.value, ga_deg)
+ );
+ const gapt2 = computeDestinationPoint(
+ this.app.data.vessels.active.position,
+ dtg,
+ Angle.add(this.app.data.navData.bearing.value, 0 - ga_deg)
+ );
+ vl.targetAngle = [
+ [gapt1.longitude, gapt1.latitude],
+ this.app.data.vessels.active.position,
+ [gapt2.longitude, gapt2.latitude]
+ ];
+ }
+ }
+
// ** anchor line (active) **
if (!this.app.data.anchor.raised) {
vl.anchor = [this.app.data.anchor.position, this.dfeat.active.position];
@@ -1185,12 +1265,69 @@ export class FBMapComponent implements OnInit, OnDestroy {
// ** CPA line **
vl.cpa = [this.dfeat.closest.position, this.dfeat.self.position];
- this.vesselLines = Object.assign({}, this.vesselLines, vl);
- }
+ const sog = this.dfeat.active.sog || 0;
+
+ // ** cog line (active) **
+ const cl = sog * (this.app.config.vessel.cogLine * 60);
+ if (this.dfeat.active.cog) {
+ vl.cog = [
+ this.dfeat.active.position,
+ GeoUtils.destCoordinate(
+ this.dfeat.active.position,
+ this.dfeat.active.cog,
+ cl
+ )
+ ];
+ }
+
+ // ** heading line (active) **
+ let hl = 0;
+ if (this.app.config.vessel.headingLineSize === -1) {
+ hl = (sog > wMax ? wMax : sog) * offset;
+ } else {
+ hl =
+ Convert.nauticalMilesToKm(this.app.config.vessel.headingLineSize) *
+ 1000;
+ }
+ vl.heading = [
+ this.dfeat.active.position,
+ GeoUtils.destCoordinate(
+ this.dfeat.active.position,
+ this.dfeat.active.orientation,
+ hl
+ )
+ ];
+
+ // ** awa (focused) **
+ let aws = this.dfeat.active.wind.aws || 0;
+ if (aws > wMax) {
+ aws = wMax;
+ }
- // worker call back
- private drawVesselLinesResult(data: VesselLinesResult) {
- this.vesselLines = Object.assign({}, this.vesselLines, data);
+ vl.awa = [
+ this.dfeat.active.position,
+ GeoUtils.destCoordinate(
+ this.dfeat.active.position,
+ this.dfeat.active.wind.awa + this.dfeat.active.orientation,
+ typeof this.dfeat.active.orientation === 'number' ? aws * offset : 0
+ )
+ ];
+
+ // ** twd (focused) **
+ let tws = this.dfeat.active.wind.tws || 0;
+ if (tws > wMax) {
+ tws = wMax;
+ }
+ vl.twd = [
+ this.dfeat.active.position,
+ GeoUtils.destCoordinate(
+ this.dfeat.active.position,
+ this.dfeat.active.wind.direction || 0,
+ typeof this.dfeat.active.orientation === 'number' ? tws * offset : 0
+ )
+ ];
+
+ this.vesselLines = vl;
}
// ******** OVERLAY ACTIONS ************
diff --git a/src/app/modules/map/mapconfig.ts b/src/app/modules/map/mapconfig.ts
index bf9094ec..808be1a5 100644
--- a/src/app/modules/map/mapconfig.ts
+++ b/src/app/modules/map/mapconfig.ts
@@ -313,6 +313,11 @@ const ais80 = new Icon({
rotateWithView: true,
rotation: 0
});
+const ais90 = new Icon({
+ src: './assets/img/ais_other.png',
+ rotateWithView: true,
+ rotation: 0
+});
const aisBuddy = new Icon({
src: './assets/img/ais_buddy.png',
rotateWithView: true,
@@ -506,7 +511,7 @@ export const aisVesselStyles = {
90: {
// other
default: new Style({
- image: ais50,
+ image: ais90,
text: new Text({
text: '',
offsetY: -12
diff --git a/src/app/modules/map/ol/index.ts b/src/app/modules/map/ol/index.ts
index 6cf63750..62a5ad26 100644
--- a/src/app/modules/map/ol/index.ts
+++ b/src/app/modules/map/ol/index.ts
@@ -46,7 +46,6 @@ import { ArrivalCircleComponent } from './lib/navigation/layer-arrival-circle.co
import { XTEPathComponent } from './lib/navigation/layer-xte-path.component';
import { BearingLineComponent } from './lib/navigation/layer-bearing-line.component';
import { LaylineComponent } from './lib/navigation/layer-layline.component';
-import { TargetAngleComponent } from './lib/navigation/layer-target-angle.component';
import { DirectionOfTravelComponent } from './lib/navigation/layer-dot.component';
import { VesselComponent } from './lib/vessel/layer-vessel.component';
import { VesselTrailComponent } from './lib/vessel/layer-vessel-trail.component';
@@ -99,6 +98,7 @@ export { XTEPathComponent } from './lib/navigation/layer-xte-path.component';
export { BearingLineComponent } from './lib/navigation/layer-bearing-line.component';
export { LaylineComponent } from './lib/navigation/layer-layline.component';
export { TargetAngleComponent } from './lib/navigation/layer-target-angle.component';
+import { TargetAngleComponent } from './lib/navigation/layer-target-angle.component';
export { DirectionOfTravelComponent } from './lib/navigation/layer-dot.component';
export { VesselComponent } from './lib/vessel/layer-vessel.component';
export { VesselTrailComponent } from './lib/vessel/layer-vessel-trail.component';
diff --git a/src/app/modules/map/ol/lib/navigation/layer-layline.component.ts b/src/app/modules/map/ol/lib/navigation/layer-layline.component.ts
index b26537a4..e40d42e6 100644
--- a/src/app/modules/map/ol/lib/navigation/layer-layline.component.ts
+++ b/src/app/modules/map/ol/lib/navigation/layer-layline.component.ts
@@ -84,7 +84,7 @@ export class LaylineComponent implements OnInit, OnDestroy, OnChanges {
const properties: { [index: string]: any } = {};
for (const key in changes) {
- if (key === 'lines' || key === 'twd' || key === 'bearing') {
+ if (key === 'lines' || key === 'twd' || key === 'position') {
this.parseValues();
if (this.source) {
this.source.clear();
diff --git a/src/app/modules/map/ol/lib/resources/layer-charts.component.ts b/src/app/modules/map/ol/lib/resources/layer-charts.component.ts
index bf8f85f9..c5adde93 100644
--- a/src/app/modules/map/ol/lib/resources/layer-charts.component.ts
+++ b/src/app/modules/map/ol/lib/resources/layer-charts.component.ts
@@ -10,6 +10,7 @@ import {
} from '@angular/core';
import TileLayer from 'ol/layer/Tile';
+import VectorTileLayer from 'ol/layer/VectorTile';
import { TileWMS, XYZ, TileJSON, WMTS } from 'ol/source';
import { optionsFromCapabilities } from 'ol/source/WMTS';
import WMTSCapabilities from 'ol/format/WMTSCapabilities';
@@ -25,6 +26,7 @@ import * as pmtiles from 'pmtiles';
import { SKChart } from 'src/app/modules';
import LayerGroup from 'ol/layer/Group';
import { apply } from 'ol-mapbox-style';
+import { FeatureLike } from 'ol/Feature';
// ** Freeboard resource collection format **
@Component({
@@ -206,7 +208,7 @@ export class FreeboardChartLayerComponent
charts[i][1]
);
layer = styleFactory.CreateLayer();
- styleFactory.ApplyStyle(layer);
+ styleFactory.ApplyStyle(layer as VectorTileLayer);
layer.setZIndex(this.zIndex + parseInt(i));
} else {
// raster tile
diff --git a/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts b/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts
index cd7da311..d0362ee6 100644
--- a/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts
+++ b/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts
@@ -6,6 +6,7 @@ import VectorTileSource from 'ol/source/VectorTile';
import { MVT } from 'ol/format';
import { Style, Fill, Stroke } from 'ol/style';
import * as pmtiles from 'pmtiles';
+import { FeatureLike } from 'ol/Feature';
export abstract class VectorLayerStyler {
public MinZ: number;
@@ -18,10 +19,9 @@ export abstract class VectorLayerStyler {
: chart.minZoom;
this.MaxZ = chart.maxZoom;
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public abstract ApplyStyle(vectorLayer: any);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public abstract CreateLayer(): VectorTileLayer;
+
+ public abstract ApplyStyle(vectorLayer: VectorTileLayer);
+ public abstract CreateLayer(): VectorTileLayer;
}
class S57LayerStyler extends VectorLayerStyler {
@@ -29,13 +29,11 @@ class S57LayerStyler extends VectorLayerStyler {
super(chart);
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public CreateLayer(): VectorTileLayer {
+ public CreateLayer(): VectorTileLayer {
return new VectorTileLayer();
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public ApplyStyle(vectorLayer: VectorTileLayer) {
+ public ApplyStyle(vectorLayer: VectorTileLayer) {
vectorLayer.set('declutter', true);
const source = new VectorTileSource({
url: this.chart.url,
@@ -62,8 +60,7 @@ class DefaultLayerStyler extends VectorLayerStyler {
super(chart);
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public CreateLayer(): VectorTileLayer {
+ public CreateLayer(): VectorTileLayer {
return new VectorTileLayer();
}
@@ -80,8 +77,7 @@ class DefaultLayerStyler extends VectorLayerStyler {
});
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public ApplyStyle(vectorLayer: VectorTileLayer) {
+ public ApplyStyle(vectorLayer: VectorTileLayer) {
// mbtiles source
const source = new VectorTileSource({
url: this.chart.url,
@@ -106,13 +102,11 @@ class PMLayerStyler extends DefaultLayerStyler {
super(chart);
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public CreateLayer(): VectorTileLayer {
+ public CreateLayer(): VectorTileLayer {
return new VectorTileLayer({ declutter: true });
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public ApplyStyle(vectorLayer: VectorTileLayer) {
+ public ApplyStyle(vectorLayer: VectorTileLayer) {
vectorLayer.set('declutter', true);
const tiles = new pmtiles.PMTiles(this.chart.url);
diff --git a/src/app/modules/map/popovers/aircraft-popover.component.ts b/src/app/modules/map/popovers/aircraft-popover.component.ts
index b6f95ed6..8ab24661 100644
--- a/src/app/modules/map/popovers/aircraft-popover.component.ts
+++ b/src/app/modules/map/popovers/aircraft-popover.component.ts
@@ -5,20 +5,17 @@ import {
EventEmitter,
ChangeDetectionStrategy
} from '@angular/core';
-
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { PipesModule } from 'src/app/lib/pipes';
import { PopoverComponent } from './popover.component';
-
import { AppInfo } from 'src/app/app.info';
import { SKAircraft } from 'src/app/modules';
-
/*********** Aircraft Popover ***************
-title: string - title text,
-aircraft: SKAircraft - aircraft data
-*************************************************/
+ title: string - title text,
+ aircraft: SKAircraft - aircraft data
+ *************************************************/
@Component({
selector: 'aircraft-popover',
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -36,14 +33,12 @@ aircraft: SKAircraft - aircraft data
Name:
{{ aircraft.name }}
-
Call sign:
{{ aircraft.callsign }}
-
-
Last Update:
@@ -93,13 +87,10 @@ export class AircraftPopoverComponent {
@Input() canClose: boolean;
@Output() info: EventEmitter
= new EventEmitter();
@Output() closed: EventEmitter = new EventEmitter();
-
_title: string;
timeLastUpdate: string;
timeAgo: string; // last update in minutes ago
-
constructor(public app: AppInfo) {}
-
ngOnInit() {
if (!this.aircraft) {
this.handleClose();
@@ -108,7 +99,6 @@ export class AircraftPopoverComponent {
this.title || this.aircraft.name || this.aircraft.mmsi || 'Aircraft:';
}
}
-
ngOnChanges() {
if (!this.aircraft) {
this.handleClose();
@@ -121,11 +111,9 @@ export class AircraftPopoverComponent {
(new Date().valueOf() - this.aircraft.lastUpdated.valueOf()) / 1000;
this.timeAgo = td < 60 ? '' : `(${Math.floor(td / 60)} min ago)`;
}
-
handleInfo() {
this.info.emit(this.aircraft.id);
}
-
handleClose() {
this.closed.emit();
}
diff --git a/src/app/modules/map/popovers/alarm-popover.component.ts b/src/app/modules/map/popovers/alarm-popover.component.ts
index 2e798f71..662bb3ff 100644
--- a/src/app/modules/map/popovers/alarm-popover.component.ts
+++ b/src/app/modules/map/popovers/alarm-popover.component.ts
@@ -5,20 +5,17 @@ import {
EventEmitter,
ChangeDetectionStrategy
} from '@angular/core';
-
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { PipesModule } from 'src/app/lib/pipes';
import { PopoverComponent } from './popover.component';
-
import { AppInfo } from 'src/app/app.info';
import { SKNotification } from 'src/app/types';
-
/*********** Alarm Popover ***************
-title: string - title text,
-aton: SKNotification - alarm data
-*************************************************/
+ title: string - title text,
+ aton: SKNotification - alarm data
+ *************************************************/
@Component({
selector: 'alarm-popover',
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -36,12 +33,10 @@ aton: SKNotification - alarm data
Message:
{{ alarm.message }}
-
-
-
-
-
Last Update:
@@ -110,15 +105,12 @@ export class AtoNPopoverComponent {
@Input() canClose: boolean;
@Output() info: EventEmitter
= new EventEmitter();
@Output() closed: EventEmitter = new EventEmitter();
-
_title: string;
timeLastUpdate: string;
timeAgo: string; // last update in minutes ago
protected convert = Convert;
isMeteo: boolean;
-
constructor(public app: AppInfo) {}
-
ngOnInit() {
if (!this.aton) {
this.handleClose();
@@ -126,7 +118,6 @@ export class AtoNPopoverComponent {
this.isMeteo = this.aton.id.includes('meteo');
}
}
-
ngOnChanges() {
if (!this.aton) {
this.handleClose();
@@ -139,11 +130,9 @@ export class AtoNPopoverComponent {
const td = (new Date().valueOf() - this.aton.lastUpdated.valueOf()) / 1000;
this.timeAgo = td < 60 ? '' : `(${Math.floor(td / 60)} min ago)`;
}
-
handleInfo() {
this.info.emit(this.aton.id);
}
-
handleClose() {
this.closed.emit();
}
diff --git a/src/app/modules/map/popovers/compass.component.ts b/src/app/modules/map/popovers/compass.component.ts
index 94da93db..b222cd1a 100644
--- a/src/app/modules/map/popovers/compass.component.ts
+++ b/src/app/modules/map/popovers/compass.component.ts
@@ -6,6 +6,7 @@ import {
ChangeDetectionStrategy,
Renderer2
} from '@angular/core';
+
import { CommonModule } from '@angular/common';
//** Base class **
diff --git a/src/app/modules/map/popovers/featurelist-popover.component.ts b/src/app/modules/map/popovers/featurelist-popover.component.ts
index 978b57e2..95b2b6d0 100644
--- a/src/app/modules/map/popovers/featurelist-popover.component.ts
+++ b/src/app/modules/map/popovers/featurelist-popover.component.ts
@@ -5,18 +5,16 @@ import {
EventEmitter,
ChangeDetectionStrategy
} from '@angular/core';
-
import { MatListModule } from '@angular/material/list';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { PipesModule } from 'src/app/lib/pipes';
import { PopoverComponent } from './popover.component';
-
/*********** feature List Popover ***************
-title: string - title text,
-features: Array - list of features
-*************************************************/
+ title: string - title text,
+ features: Array - list of features
+ *************************************************/
@Component({
selector: 'feature-list-popover',
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -54,14 +52,11 @@ export class FeatureListPopoverComponent {
@Output() closed: EventEmitter = new EventEmitter();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@Output() selected: EventEmitter = new EventEmitter();
-
//constructor() {}
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleSelect(item: any) {
this.selected.emit(item);
}
-
handleClose() {
this.closed.emit();
}
diff --git a/src/app/modules/map/popovers/index.ts b/src/app/modules/map/popovers/index.ts
index 3db01d72..f0a18fa1 100644
--- a/src/app/modules/map/popovers/index.ts
+++ b/src/app/modules/map/popovers/index.ts
@@ -1,8 +1,8 @@
export * from './popover.component';
+export * from './resource-popover.component';
+export * from './compass.component';
+export * from './vessel-popover.component';
export * from './featurelist-popover.component';
export * from './aircraft-popover.component';
export * from './alarm-popover.component';
export * from './aton-popover.component';
-export * from './resource-popover.component';
-export * from './compass.component';
-export * from './vessel-popover.component';
diff --git a/src/app/modules/map/popovers/popover.component.ts b/src/app/modules/map/popovers/popover.component.ts
index 42f3363c..2e2f39dd 100644
--- a/src/app/modules/map/popovers/popover.component.ts
+++ b/src/app/modules/map/popovers/popover.component.ts
@@ -8,8 +8,8 @@ import {
EventEmitter,
ChangeDetectionStrategy
} from '@angular/core';
-import { CommonModule } from '@angular/common';
+import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
diff --git a/src/app/modules/map/popovers/resource-popover.component.ts b/src/app/modules/map/popovers/resource-popover.component.ts
index e0f3559e..ec5191e7 100644
--- a/src/app/modules/map/popovers/resource-popover.component.ts
+++ b/src/app/modules/map/popovers/resource-popover.component.ts
@@ -10,7 +10,6 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { PipesModule } from 'src/app/lib/pipes';
-
import { PopoverComponent } from './popover.component';
import { AppInfo } from 'src/app/app.info';
@@ -25,6 +24,7 @@ id: string - resource id
*************************************************/
@Component({
selector: 'resource-popover',
+ changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
MatButtonModule,
@@ -33,7 +33,6 @@ id: string - resource id
PipesModule,
PopoverComponent
],
- changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@for(p of properties; track p) {
diff --git a/src/app/modules/map/popovers/vessel-popover.component.ts b/src/app/modules/map/popovers/vessel-popover.component.ts
index 5f8fd970..59950c59 100644
--- a/src/app/modules/map/popovers/vessel-popover.component.ts
+++ b/src/app/modules/map/popovers/vessel-popover.component.ts
@@ -13,7 +13,6 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { PipesModule } from 'src/app/lib/pipes';
-
import { PopoverComponent } from './popover.component';
import { CompassComponent } from './compass.component';
diff --git a/src/app/modules/map/vessel-calcs.types.ts b/src/app/modules/map/vessel-calcs.types.ts
deleted file mode 100644
index 51b7b7b6..00000000
--- a/src/app/modules/map/vessel-calcs.types.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Position } from 'src/app/types';
-import { SKVessel } from '../skresources';
-
-export interface VesselLinesData {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- vesselConfig: any; // app.config.vessel
- vesselSelf: SKVessel; // dfeat.self === app.data.vessels.self
- vesselActive: SKVessel; // app.data.vessels.active
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- navData: any; // dfeat.navData.position = app.data.navData.position;
- mapZoomLevel: number; // fbMap.zoomLevel
- zoomOffsetLevel: number; // this.zoomOffsetLevel
- units: { distance: string }; // app.config.units
-}
-
-export interface VesselLinesResult {
- laylines: { port: number[][][]; starboard: number[][][] };
- targetAngle: Array;
- cog: Array;
- heading: Array;
- twd: Array;
- awa: Array;
-}
diff --git a/src/app/modules/map/vessel-calcs.worker.ts b/src/app/modules/map/vessel-calcs.worker.ts
deleted file mode 100644
index b8f063a2..00000000
--- a/src/app/modules/map/vessel-calcs.worker.ts
+++ /dev/null
@@ -1,165 +0,0 @@
-///
-
-import { VesselLinesData, VesselLinesResult } from './vessel-calcs.types';
-
-import { Convert } from 'src/app/lib/convert';
-import { GeoUtils, Angle } from 'src/app/lib/geoutils';
-import { computeDestinationPoint } from 'geolib';
-
-// ******** MESSAGE FROM APP ************
-// ** listen for posted messages from APP
-addEventListener('message', ({ data }) => {
- drawVesselLines(data);
-});
-
-//** POST message to App**
-function drawVesselLines(data: VesselLinesData) {
- const vl: VesselLinesResult = {
- laylines: { port: [], starboard: [] },
- targetAngle: [],
- cog: [],
- heading: [],
- awa: [],
- twd: []
- };
-
- // laylines (active)
- if (
- data.vesselConfig.laylines &&
- Array.isArray(data.navData.position) &&
- typeof data.navData.position[0] === 'number' &&
- typeof data.vesselActive.heading === 'number'
- ) {
- const twd_deg = Convert.radiansToDegrees(data.vesselSelf.wind.twd);
- const destUpwind =
- Math.abs(Angle.difference(data.navData.bearing.value, twd_deg)) < 90;
- const ba_deg = Convert.radiansToDegrees(
- data.vesselSelf.performance.beatAngle ?? Math.PI / 4
- );
- const destInTarget =
- Math.abs(Angle.difference(data.navData.bearing.value, twd_deg)) < ba_deg;
- const dtg =
- data.units.distance === 'm'
- ? data.navData.dtg * 1000
- : Convert.nauticalMilesToKm(data.navData.dtg * 1000);
-
- if (destInTarget) {
- const heading_deg = Convert.radiansToDegrees(data.vesselActive.heading);
-
- const bta = Angle.add(heading_deg, 90); // tack angle
- const hbd_rad = Convert.degreesToRadians(
- Angle.difference(heading_deg, data.navData.bearing.value)
- );
- const dist1 = Math.sin(hbd_rad) * dtg;
- const dist2 = Math.cos(hbd_rad) * dtg;
- const pt1 = computeDestinationPoint(
- data.vesselActive.position,
- dist1,
- bta
- );
- const pt2 = computeDestinationPoint(
- data.vesselActive.position,
- dist2,
- heading_deg
- );
- const p1a = [data.vesselActive.position, [pt1.longitude, pt1.latitude]];
- const p1b = [[pt1.longitude, pt1.latitude], data.navData.position];
- const l1 = hbd_rad < 0 ? [p1a, p1b] : [p1b, p1a];
-
- const p2a = [[pt2.longitude, pt2.latitude], data.navData.position];
- const p2b = [data.vesselActive.position, [pt2.longitude, pt2.latitude]];
- const l2 = hbd_rad < 0 ? [p2a, p2b] : [p2b, p2a];
-
- vl.laylines = {
- port: hbd_rad < 0 ? l2 : l1,
- starboard: hbd_rad < 0 ? l1 : l2
- };
- }
-
- // beat / gybe angle lines
- if (destUpwind) {
- const ta_deg = ba_deg;
- const bapt1 = computeDestinationPoint(
- data.vesselActive.position,
- dtg,
- Angle.add(twd_deg, ta_deg)
- );
- const bapt2 = computeDestinationPoint(
- data.vesselActive.position,
- dtg,
- Angle.add(twd_deg, 0 - ta_deg)
- );
-
- vl.targetAngle = [
- [bapt1.longitude, bapt1.latitude],
- data.vesselActive.position,
- [bapt2.longitude, bapt2.latitude]
- ];
- }
- }
-
- // ** cog line (active) **
- const sog = data.vesselActive.sog || 0;
- const cl = sog * (data.vesselConfig.cogLine * 60);
- if (data.vesselActive.cog) {
- vl.cog = [
- data.vesselActive.position,
- GeoUtils.destCoordinate(
- data.vesselActive.position,
- data.vesselActive.cog,
- cl
- )
- ];
- }
-
- // ** heading line (active) **
- const z = data.mapZoomLevel;
- const offset = z < 29 ? data.zoomOffsetLevel[Math.floor(z)] : 60;
- const wMax = 10; // ** max line length
-
- let hl = 0;
- if (data.vesselConfig.headingLineSize === -1) {
- hl = (sog > wMax ? wMax : sog) * offset;
- } else {
- hl = Convert.nauticalMilesToKm(data.vesselConfig.headingLineSize) * 1000;
- }
- vl.heading = [
- data.vesselActive.position,
- GeoUtils.destCoordinate(
- data.vesselActive.position,
- data.vesselActive.orientation,
- hl
- )
- ];
-
- // ** awa (focused) **
- let aws = data.vesselActive.wind.aws || 0;
- if (aws > wMax) {
- aws = wMax;
- }
-
- vl.awa = [
- data.vesselActive.position,
- GeoUtils.destCoordinate(
- data.vesselActive.position,
- data.vesselActive.wind.awa + data.vesselActive.orientation,
- typeof data.vesselActive.orientation === 'number' ? aws * offset : 0
- )
- ];
-
- // ** twd (focused) **
- let tws = data.vesselActive.wind.tws || 0;
- if (tws > wMax) {
- tws = wMax;
- }
- vl.twd = [
- data.vesselActive.position,
- GeoUtils.destCoordinate(
- data.vesselActive.position,
- data.vesselActive.wind.direction || 0,
- typeof data.vesselActive.orientation === 'number' ? tws * offset : 0
- )
- ];
-
- postMessage(vl);
-}
diff --git a/src/app/modules/skresources/components/ais/aislist.ts b/src/app/modules/skresources/components/ais/aislist.ts
index bf998a79..c4e7037f 100644
--- a/src/app/modules/skresources/components/ais/aislist.ts
+++ b/src/app/modules/skresources/components/ais/aislist.ts
@@ -107,10 +107,9 @@ export class AISListComponent {
id: 90,
description: 'Other',
selected: false,
- icon: './assets/img/ais_special.png'
+ icon: './assets/img/ais_other.png'
}
];
- otherShiptypes = [10, 20, 30, 90];
constructor(public app: AppInfo) {}
diff --git a/src/app/modules/skresources/components/charts/chartlist.html b/src/app/modules/skresources/components/charts/chartlist.html
index ec6ce879..e9d6dc34 100644
--- a/src/app/modules/skresources/components/charts/chartlist.html
+++ b/src/app/modules/skresources/components/charts/chartlist.html
@@ -82,7 +82,7 @@
mat-button
(click)="toggleChartBoundaries()"
matTooltip="Chart boundaries"
- matTooltipPosition="top"
+ matTooltipPosition="right"
>
import_export
Re-order
diff --git a/src/app/modules/skresources/resource-classes.ts b/src/app/modules/skresources/resource-classes.ts
index 53d044f3..f6fcf488 100644
--- a/src/app/modules/skresources/resource-classes.ts
+++ b/src/app/modules/skresources/resource-classes.ts
@@ -209,7 +209,8 @@ export class SKVessel {
previousPoint: {}
};
performance = {
- beatAngle: null
+ beatAngle: null,
+ gybeAngle: null
};
properties = {};
}
diff --git a/src/app/modules/skstream/skstream.worker.ts b/src/app/modules/skstream/skstream.worker.ts
index 56bbcc02..17101dc5 100644
--- a/src/app/modules/skstream/skstream.worker.ts
+++ b/src/app/modules/skstream/skstream.worker.ts
@@ -768,6 +768,8 @@ function processVessel(d: SKVessel, v, isSelf = false) {
}
} else if (v.path === 'performance.beatAngle') {
d.performance.beatAngle = v.value;
+ } else if (v.path === 'performance.gybeAngle') {
+ d.performance.gybeAngle = v.value;
} else if (v.path === 'communication.callsignVhf') {
d.callsign = v.value;
} else if (v.path === 'design.aisShipType') {
diff --git a/src/assets/help/img/ais_shiptypes.png b/src/assets/help/img/ais_shiptypes.png
index fccdf2ab..17d1fe5f 100644
Binary files a/src/assets/help/img/ais_shiptypes.png and b/src/assets/help/img/ais_shiptypes.png differ
diff --git a/src/assets/help/index.html b/src/assets/help/index.html
index 0ddb45a9..79848c80 100644
--- a/src/assets/help/index.html
+++ b/src/assets/help/index.html
@@ -1578,7 +1578,7 @@ Vessels
-
+
Other (AIS type 90-99)
diff --git a/src/assets/img/ais_other.png b/src/assets/img/ais_other.png
new file mode 100644
index 00000000..411da1e4
Binary files /dev/null and b/src/assets/img/ais_other.png differ
diff --git a/src/assets/img/ais_passenger.png b/src/assets/img/ais_passenger.png
index 8c1bc21b..e6f8e50a 100644
Binary files a/src/assets/img/ais_passenger.png and b/src/assets/img/ais_passenger.png differ
diff --git a/src/assets/img/ais_special.png b/src/assets/img/ais_special.png
index 411da1e4..790a00ba 100644
Binary files a/src/assets/img/ais_special.png and b/src/assets/img/ais_special.png differ
diff --git a/src/index.html b/src/index.html
index 808c1638..b5274723 100644
--- a/src/index.html
+++ b/src/index.html
@@ -27,6 +27,12 @@
+
diff --git a/tsconfig.json b/tsconfig.json
index 713f1b25..f6b73653 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,8 +4,8 @@
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
- "esModuleInterop": true,
"declaration": false,
+ "downlevelIteration": true,
"experimentalDecorators": true,
"module": "es2022",
"moduleResolution": "node",