From 03377a9f5dca9aa4e21f9cdc1eed7c677084cbcb Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Fri, 12 Jul 2024 10:39:46 +0930 Subject: [PATCH] standalone alignment --- .gitignore | 1 + CHANGELOG.md | 5 +- angular.json | 19 +- package.json | 32 +-- src/app-theme.scss | 39 +-- src/app/app.info.ts | 13 +- src/app/app.module.ts | 14 +- .../dialogs/common/dialogs.component.ts | 4 +- src/app/lib/components/index.ts | 1 - src/app/lib/components/wakelock.component.ts | 1 - src/app/modules/map/fb-map.component.html | 6 +- src/app/modules/map/fb-map.component.ts | 239 ++++++++++++++---- src/app/modules/map/mapconfig.ts | 7 +- src/app/modules/map/ol/index.ts | 2 +- .../lib/navigation/layer-layline.component.ts | 2 +- .../lib/resources/layer-charts.component.ts | 4 +- .../map/ol/lib/vectorLayerStyleFactory.ts | 26 +- .../popovers/aircraft-popover.component.ts | 18 +- .../map/popovers/alarm-popover.component.ts | 18 +- .../map/popovers/aton-popover.component.ts | 17 +- .../modules/map/popovers/compass.component.ts | 1 + .../popovers/featurelist-popover.component.ts | 11 +- src/app/modules/map/popovers/index.ts | 6 +- .../modules/map/popovers/popover.component.ts | 2 +- .../popovers/resource-popover.component.ts | 3 +- .../map/popovers/vessel-popover.component.ts | 1 - src/app/modules/map/vessel-calcs.types.ts | 23 -- src/app/modules/map/vessel-calcs.worker.ts | 165 ------------ .../skresources/components/ais/aislist.ts | 3 +- .../components/charts/chartlist.html | 4 +- .../modules/skresources/resource-classes.ts | 3 +- src/app/modules/skstream/skstream.worker.ts | 2 + src/assets/help/img/ais_shiptypes.png | Bin 31928 -> 32439 bytes src/assets/help/index.html | 2 +- src/assets/img/ais_other.png | Bin 0 -> 237 bytes src/assets/img/ais_passenger.png | Bin 269 -> 252 bytes src/assets/img/ais_special.png | Bin 237 -> 231 bytes src/index.html | 6 + tsconfig.json | 2 +- 39 files changed, 307 insertions(+), 395 deletions(-) delete mode 100644 src/app/modules/map/vessel-calcs.types.ts delete mode 100644 src/app/modules/map/vessel-calcs.worker.ts create mode 100644 src/assets/img/ais_other.png 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) {
- Visit Website + Visit Website
} 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 }}
-
Latitude:
-
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 }}
-
Type:
{{ id }}
-
Latitude:
-
 
@@ -87,11 +81,8 @@ export class AlarmPopoverComponent { @Input() canClose: boolean; @Output() info: EventEmitter = new EventEmitter(); @Output() closed: EventEmitter = new EventEmitter(); - _title: string; - constructor(public app: AppInfo) {} - ngOnInit() { if (!this.alarm) { this.handleClose(); @@ -99,18 +90,15 @@ export class AlarmPopoverComponent { this._title = this.title || 'Alarm:'; } } - ngOnChanges() { if (!this.alarm) { this.handleClose(); return; } } - handleInfo() { this.info.emit(this.alarm.id); } - handleClose() { this.closed.emit(); } diff --git a/src/app/modules/map/popovers/aton-popover.component.ts b/src/app/modules/map/popovers/aton-popover.component.ts index d9b6cd07..041f5902 100644 --- a/src/app/modules/map/popovers/aton-popover.component.ts +++ b/src/app/modules/map/popovers/aton-popover.component.ts @@ -5,22 +5,19 @@ 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 { CompassComponent } from './compass.component'; - import { SKMeteo } from 'src/app/modules'; import { AppInfo } from 'src/app/app.info'; import { Convert } from 'src/app/lib/convert'; - /*********** AtoN Popover *************** -title: string - title text, -aton: SKAtoN - aton data -*************************************************/ + title: string - title text, + aton: SKAtoN - aton data + *************************************************/ @Component({ selector: 'aton-popover', changeDetection: ChangeDetectionStrategy.OnPush, @@ -39,7 +36,6 @@ aton: SKAtoN - aton data
Type:
{{ aton.type.name }}
-
Latitude:
-
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 fccdf2ab5dd4d08e0ef942b399ba2da4b381e088..17d1fe5fd205e6f48db27664a719b89aa11cf107 100644 GIT binary patch literal 32439 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

- +
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 0000000000000000000000000000000000000000..411da1e4d3837556786a7e348e5e64ea3b4bcc3d GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#VfOe7N7D`G?c2hyw=>eAvHm;X`|7 zl^HA@7Y}$WdRV|W#W%oyXQ6|M!Zjw=oTf88XE<9-grr?G4l*+zVG%a8J0Lx?#YoOj zY>)f11;3xzAO8P$N>oFlhGO9)U4^RwT{;S)Jy8y|+!<0Q0}h*dZfy~8&|73#&=H)* hDCfK)=^zI?!+$TG1ewMTcc6P2JYD@<);T3K0RY=pQxgCH literal 0 HcmV?d00001 diff --git a/src/assets/img/ais_passenger.png b/src/assets/img/ais_passenger.png index 8c1bc21b2f1ff2ad852a3ff23ab694395de2158f..e6f8e50a8d10f0b1e74fbd4565d278830deca724 100644 GIT binary patch delta 208 zcmV;>05AWI0{j7xG=H;6L_t(YiS3gy4#F@DMPDOSl?^Eu=u#wZ!7&)Q2ugA?P86{+ z5eCYT3Q@ahwtgu?tmHq(c0ehEIcx9eWL?r6Hw!U+6+laS0T>v9G9jU?OB_=g%XFw? z{$0XeEbW0D_f(UotQM$a&KA)d`CmSFM2zxe%BZ@G~eTl=vZ)Xuys15+opgEIgG7?2_ z5kVAja2rdCqc%T%j1z$D)cm3zFqi~mO|4NMwOm_?zRS~NC|Z+x1Ff0b!&3zkU-!X8 z8pfaTah)UpfS=|0H%|-5O{WP+7QqaHq%SEKBw&@-J4Rv`bl*Z~(cX}qV{bA}?EZf` bwqWHAt5q!O29}Vs00000NkvXXu0mjfUOrtr diff --git a/src/assets/img/ais_special.png b/src/assets/img/ais_special.png index 411da1e4d3837556786a7e348e5e64ea3b4bcc3d..790a00bac41be07249b267e01009eff4b3e1e1d1 100644 GIT binary patch delta 187 zcmV;s07U=o0p|gbG=H8+L_t(YiS3lJ4S+BV1m9G2Faj-GFa{;7F{vpcP$EI>Pe=t{ zA&2+HZz%w;rNBc;nV-8t$W-XdOCT!%9Wd-o000!KiV)N2yA;Xm@!Ca(ZKt^)+zD3c>96lwqf002ovPDHLkV1nCCPJI9X delta 193 zcmV;y06zcc0qp^hG=HQ?L_t(YiDO_O5il|^I*_V|RPdh^#Y|*cqCloT{D6spDT0B4 z;lDV8_(Gakz`(%pzoDVwKLaF~1c=eVNTT6z4wOw$Ke=&0G$7Uj1#E)M49p3HG!h#` zD8T~*!~_#DKENB9gfbp67Q9F1p!?)M!~gx1T7Y3FA#su|AUf4hiYy=%j9Nf_3uqe2 vP{TDzwS*8rE}}Vbh*M?(9z&>N!3YNc|4J-i9D#^O00000NkvXXu0mjfWQa}K 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",