diff --git a/package.json b/package.json index 582f66d8..8b78e073 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@signalk/freeboard-sk", - "version": "2.6.0", + "version": "2.6.0-rc2", "description": "Openlayers chart plotter implementation for Signal K", "keywords": [ "signalk-webapp", diff --git a/src/app/app.info.ts b/src/app/app.info.ts index 0b0a956a..af35753c 100644 --- a/src/app/app.info.ts +++ b/src/app/app.info.ts @@ -105,12 +105,12 @@ const FreeboardConfig = { beyond24: '5m' }, s57Options: { - graphicsStyle:'Paper', - boundaries:'Plain', - colors:4, - shallowDepth:2, + graphicsStyle: 'Paper', + boundaries: 'Plain', + colors: 4, + shallowDepth: 2, safetyDepth: 3, - deepDepth:6 + deepDepth: 6 }, resourceSets: {}, // additional resources signalk: { @@ -278,7 +278,7 @@ export class AppInfo extends Info { this.name = 'Freeboard-SK'; this.shortName = 'Freeboard'; this.description = `Signal K Chart Plotter.`; - this.version = '2.6.0'; + this.version = '2.6.0-rc2'; this.url = 'https://github.com/signalk/freeboard-sk'; this.logo = './assets/img/app_logo.png'; @@ -730,6 +730,17 @@ export class AppInfo extends Info { } } + if (typeof settings.selections.s57Options === 'undefined') { + settings.selections.s57Options = { + graphicsStyle: 'Paper', + boundaries: 'Plain', + colors: 4, + shallowDepth: 2, + safetyDepth: 3, + deepDepth: 6 + }; + } + if (typeof settings.plugins === 'undefined') { settings.plugins = {}; } diff --git a/src/app/lib/services/state.service.ts b/src/app/lib/services/state.service.ts index c7bde4ad..45aacd18 100644 --- a/src/app/lib/services/state.service.ts +++ b/src/app/lib/services/state.service.ts @@ -54,27 +54,30 @@ export class State { } } - //merge new default values in storedvalue - merge(storedValue:any,defaultValue:any):any { + // merge new default values in storedvalue + // eslint-disable-next-line @typescript-eslint/no-explicit-any + merge(storedValue: any, defaultValue: any): any { Object.keys(defaultValue).forEach((key) => { if (!storedValue[key]) { - storedValue[key]=defaultValue[key] + storedValue[key] = defaultValue[key]; } else { - if( typeof storedValue[key] === 'object' && - !Array.isArray(storedValue[key]) && - storedValue[key] !== null) { - storedValue[key]=this.merge(storedValue[key],defaultValue[key]) + if ( + typeof storedValue[key] === 'object' && + !Array.isArray(storedValue[key]) && + storedValue[key] !== null + ) { + storedValue[key] = this.merge(storedValue[key], defaultValue[key]); } } - }) - return storedValue + }); + return storedValue; } //** load app config ** loadConfig(defaultValue = {}) { const config = this.ls.read('config'); - return config ? this.merge(config,defaultValue) : defaultValue; - // return config ? config : defaultValue; + //return config ? this.merge(config,defaultValue) : defaultValue; + return config ? config : defaultValue; } //** load app data ** diff --git a/src/app/modules/map/fb-map.component.ts b/src/app/modules/map/fb-map.component.ts index 83b26d8d..e235baaa 100644 --- a/src/app/modules/map/fb-map.component.ts +++ b/src/app/modules/map/fb-map.component.ts @@ -56,7 +56,7 @@ import { ModifyEvent } from 'ol/interaction/Modify'; import { DrawEvent } from 'ol/interaction/Draw'; import { Coordinate } from 'ol/coordinate'; import { ResourceSets, SKNotification } from 'src/app/types'; -import { S57Service} from './ol/lib/s57.service'; +import { S57Service } from './ol/lib/s57.service'; interface IResource { id: string; @@ -327,7 +327,7 @@ export class FBMapComponent implements OnInit, OnDestroy { this.app.settings$.subscribe((r: SettingsMessage) => { if (r.action === 'save' && r.setting === 'config') { this.fbMap.movingMap = this.app.config.map.moveMap; - this.s57Service.SetOptions(this.app.config.selections.s57Options) + this.s57Service.SetOptions(this.app.config.selections.s57Options); this.renderMapContents(); if (!this.app.config.selections.trailFromServer) { this.dfeat.trail = []; 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 0b08ea47..878f6b51 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 @@ -18,7 +18,7 @@ import WMTSCapabilities from 'ol/format/WMTSCapabilities'; import { MapComponent } from '../map.component'; import { osmLayer } from '../util'; import { MapService } from '../map.service'; -import { VectorLayerStyleFactory } from '../vectorLayerStyleFactory' +import { VectorLayerStyleFactory } from '../vectorLayerStyleFactory'; import DataTile from 'ol/source/DataTile'; import WebGLTileLayer from 'ol/layer/WebGLTile'; @@ -34,7 +34,8 @@ import { apply, applyStyle, applyBackground } from 'ol-mapbox-style'; changeDetection: ChangeDetectionStrategy.OnPush }) export class FreeboardChartLayerComponent - implements OnInit, OnDestroy, OnChanges { + implements OnInit, OnDestroy, OnChanges +{ // eslint-disable-next-line @typescript-eslint/no-explicit-any protected layers: Map = new Map(); @@ -161,7 +162,6 @@ export class FreeboardChartLayerComponent }); } - async parseCharts(charts: Array<[string, SKChart, boolean]> = this.charts) { const map = this.mapComponent.getMap(); @@ -201,11 +201,14 @@ export class FreeboardChartLayerComponent } else if ( charts[i][1].format === 'pbf' || charts[i][1].format === 'mvt' - ) { - let styleFactory = this.vectorLayerStyleFactory.CreateVectorLayerStyler(charts[i][1]) + ) { + let styleFactory = + this.vectorLayerStyleFactory.CreateVectorLayerStyler( + charts[i][1] + ); layer = styleFactory.CreateLayer(); - styleFactory.ApplyStyle(layer as VectorTileLayer) - layer.setZIndex(this.zIndex + parseInt(i)) + styleFactory.ApplyStyle(layer as VectorTileLayer); + layer.setZIndex(this.zIndex + parseInt(i)); } else { // raster tile let source; // select source type diff --git a/src/app/modules/map/ol/lib/s57.service.ts b/src/app/modules/map/ol/lib/s57.service.ts index 995610b2..3d299695 100644 --- a/src/app/modules/map/ol/lib/s57.service.ts +++ b/src/app/modules/map/ol/lib/s57.service.ts @@ -1,11 +1,11 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Style, Fill, Stroke, Icon, Text } from 'ol/style'; -import { Feature } from 'ol' +import { Feature } from 'ol'; import { Subject } from 'rxjs'; -const DRGARE = 46 // Dredged area -const DEPARE = 42 // Depth Area +const DRGARE = 46; // Dredged area +const DEPARE = 42; // Depth Area interface Symbol { image: HTMLImageElement; @@ -20,7 +20,7 @@ interface Symbol { } interface Lookup { - name: string + name: string; geometryType: GeometryType; lookupTable: LookupTable; instruction: string; @@ -38,20 +38,18 @@ export interface Options { colors: number; } -export const DefaultOptions:Options = { - shallowDepth:2, +export const DefaultOptions: Options = { + shallowDepth: 2, safetyDepth: 3, deepDepth: 6, - graphicsStyle:"Paper", //Simplified or Paper - boundaries:"Plain", // Plain or Symbolized - colors:4 // 2 or 4 - -} - + graphicsStyle: 'Paper', //Simplified or Paper + boundaries: 'Plain', // Plain or Symbolized + colors: 4 // 2 or 4 +}; interface ColorTable { symbolfile: string; - colors: Map + colors: Map; } enum GeometryType { @@ -61,16 +59,16 @@ enum GeometryType { } enum DisplayPriority { - PRIO_NODATA = 0, // no data fill area pattern - PRIO_GROUP1 = 1, // S57 group 1 filled areas - PRIO_AREA_1 = 2, // superimposed areas - PRIO_AREA_2 = 3, // superimposed areas also water features - PRIO_SYMB_POINT = 4, // point symbol also land features - PRIO_SYMB_LINE = 5, // line symbol also restricted areas - PRIO_SYMB_AREA = 6, // area symbol also traffic areas - PRIO_ROUTEING = 7, // routeing lines - PRIO_HAZARDS = 8, // hazards - PRIO_MARINERS = 9, // VRM, EBL, own ship + PRIO_NODATA = 0, // no data fill area pattern + PRIO_GROUP1 = 1, // S57 group 1 filled areas + PRIO_AREA_1 = 2, // superimposed areas + PRIO_AREA_2 = 3, // superimposed areas also water features + PRIO_SYMB_POINT = 4, // point symbol also land features + PRIO_SYMB_LINE = 5, // line symbol also restricted areas + PRIO_SYMB_AREA = 6, // area symbol also traffic areas + PRIO_ROUTEING = 7, // routeing lines + PRIO_HAZARDS = 8, // hazards + PRIO_MARINERS = 9 // VRM, EBL, own ship } enum LookupTable { @@ -81,14 +79,12 @@ enum LookupTable { SYMBOLIZED = 4 } -const LOOKUPINDEXKEY = "$lupIndex" - +const LOOKUPINDEXKEY = '$lupIndex'; @Injectable({ providedIn: 'root' }) export class S57Service { - private chartSymbols: Map = new Map(); private colorTables: ColorTable[] = []; private selectedColorTable: number = 0; @@ -96,159 +92,194 @@ export class S57Service { private lookups: Lookup[] = []; private lookupStartIndex: Map = new Map(); public refresh: Subject = new Subject(); - private selectedSafeContour:number = 1000 + private selectedSafeContour: number = 1000; //options - private options:Options = DefaultOptions + private options: Options = DefaultOptions; - private attMatch = new RegExp('([A-Za-z0-9]{6})([0-9,\\?]*)') - private instructionMatch = new RegExp('([A-Z][A-Z])\\((.*)\\)') + private attMatch = new RegExp('([A-Za-z0-9]{6})([0-9,\\?]*)'); + private instructionMatch = new RegExp('([A-Z][A-Z])\\((.*)\\)'); constructor(private http: HttpClient) { - - http.get("assets/s57/chartsymbols.json").subscribe((symbolsJson) => { - this.processSymbols(symbolsJson) - this.processLookup(symbolsJson) - this.processColors(symbolsJson) - this.refresh.next() + http.get('assets/s57/chartsymbols.json').subscribe((symbolsJson) => { + this.processSymbols(symbolsJson); + this.processLookup(symbolsJson); + this.processColors(symbolsJson); + this.refresh.next(); let image = new Image(); image.onload = () => { this.chartSymbolsImage = image; - this.refresh.next() - } - image.src = "assets/s57/" + this.colorTables[this.selectedColorTable].symbolfile + this.refresh.next(); + }; + image.src = + 'assets/s57/' + this.colorTables[this.selectedColorTable].symbolfile; }); } - private isChanged(currentValue:any,newValue:any):boolean { - let changed = false - let keys=Object.keys(newValue) + private isChanged(currentValue: any, newValue: any): boolean { + let changed = false; + let keys = Object.keys(newValue); for (let i = 0; i < keys.length; i++) { - if(currentValue[keys[i]] != newValue[keys[i]]) { - changed=true; + if (currentValue[keys[i]] != newValue[keys[i]]) { + changed = true; break; } } return changed; } - public SetOptions(options:Options) { - - if(this.isChanged(this.options,options)) { - this.options = Object.assign({},options) - this.refresh.next(); + public SetOptions(options: Options) { + if (this.isChanged(this.options, options)) { + this.options = Object.assign({}, options); + this.refresh.next(); } } private processColors(symbolsJson: any) { - (symbolsJson["chartsymbols"]["color-tables"]["color-table"] as any[]).forEach((colortable) => { - let colorTable: ColorTable = { symbolfile: colortable["graphics-file"]["_name"], colors: new Map() } - let colors = colortable["color"] as any[] + ( + symbolsJson['chartsymbols']['color-tables']['color-table'] as any[] + ).forEach((colortable) => { + let colorTable: ColorTable = { + symbolfile: colortable['graphics-file']['_name'], + colors: new Map() + }; + let colors = colortable['color'] as any[]; colors.forEach((color) => { - colorTable.colors.set(color["_name"], "rgba(" + color["_r"] + ", " + color["_g"] + ", " + color["_b"] + ",1)") - }) + colorTable.colors.set( + color['_name'], + 'rgba(' + + color['_r'] + + ', ' + + color['_g'] + + ', ' + + color['_b'] + + ',1)' + ); + }); this.colorTables.push(colorTable); }); } private processSymbols(symbolsJson: any) { - (symbolsJson["chartsymbols"]["symbols"]["symbol"] as any[]).forEach((symbol) => { - let bitmap = symbol["bitmap"] - if (bitmap) { - this.chartSymbols.set(symbol["name"], { - image: null, - pivotX: parseInt(bitmap["pivot"]["_x"]), - pivotY: parseInt(bitmap["pivot"]["_y"]), - originX: parseInt(bitmap["origin"]["_x"]), - originY: parseInt(bitmap["origin"]["_y"]), - width: parseInt(bitmap["_width"]), - height: parseInt(bitmap["_height"]), - locationX: parseInt(bitmap["graphics-location"]["_x"]), - locationY: parseInt(bitmap["graphics-location"]["_y"]), - }) + (symbolsJson['chartsymbols']['symbols']['symbol'] as any[]).forEach( + (symbol) => { + let bitmap = symbol['bitmap']; + if (bitmap) { + this.chartSymbols.set(symbol['name'], { + image: null, + pivotX: parseInt(bitmap['pivot']['_x']), + pivotY: parseInt(bitmap['pivot']['_y']), + originX: parseInt(bitmap['origin']['_x']), + originY: parseInt(bitmap['origin']['_y']), + width: parseInt(bitmap['_width']), + height: parseInt(bitmap['_height']), + locationX: parseInt(bitmap['graphics-location']['_x']), + locationY: parseInt(bitmap['graphics-location']['_y']) + }); + } } - }); + ); } - private compareLookup(a: Lookup, b: Lookup): number { let lt = a.lookupTable - b.lookupTable; - if (lt != 0) return lt - let ir = a.name.localeCompare(b.name) - if (ir != 0) return ir - let c1 = Object.keys(a.attributes).length - let c2 = Object.keys(a.attributes).length - if (c1 != c2) return c2 - c1 - return a.id - b.id + if (lt != 0) return lt; + let ir = a.name.localeCompare(b.name); + if (ir != 0) return ir; + let c1 = Object.keys(a.attributes).length; + let c2 = Object.keys(a.attributes).length; + if (c1 != c2) return c2 - c1; + return a.id - b.id; } private getGeometryType(type: string): GeometryType { switch (type) { - case "Line": return GeometryType.LINES; break; - case "Area": return GeometryType.AREA; break; - default: return GeometryType.POINT; + case 'Line': + return GeometryType.LINES; + break; + case 'Area': + return GeometryType.AREA; + break; + default: + return GeometryType.POINT; } } private getLookupTable(table: string): LookupTable { switch (table) { - case "Simplified": return LookupTable.SIMPLIFIED; break; - case "Paper": return LookupTable.PAPER_CHART; break; - case "Lines": return LookupTable.LINES; break; - case "Plain": return LookupTable.PLAIN; break; - default: return LookupTable.SYMBOLIZED + case 'Simplified': + return LookupTable.SIMPLIFIED; + break; + case 'Paper': + return LookupTable.PAPER_CHART; + break; + case 'Lines': + return LookupTable.LINES; + break; + case 'Plain': + return LookupTable.PLAIN; + break; + default: + return LookupTable.SYMBOLIZED; } } private processLookup(symbolsJson: any) { - (symbolsJson["chartsymbols"]["lookups"]["lookup"] as any[]).forEach((lookup) => { - let lup: Lookup = { - name: lookup["_name"], - instruction: lookup["instruction"], - lookupTable: this.getLookupTable(lookup["table-name"]), - geometryType: this.getGeometryType(lookup["type"]), - attributes: {}, - id: parseInt(lookup["_id"]), - displayPriority: this.getDisplayPriority(lookup["disp-prio"]), - } - let attributes = lookup["attrib-code"] - if (attributes) { - (attributes as any[]).forEach((att) => { - lup.attributes[att["_index"]] = att["__text"] - }) + (symbolsJson['chartsymbols']['lookups']['lookup'] as any[]).forEach( + (lookup) => { + let lup: Lookup = { + name: lookup['_name'], + instruction: lookup['instruction'], + lookupTable: this.getLookupTable(lookup['table-name']), + geometryType: this.getGeometryType(lookup['type']), + attributes: {}, + id: parseInt(lookup['_id']), + displayPriority: this.getDisplayPriority(lookup['disp-prio']) + }; + let attributes = lookup['attrib-code']; + if (attributes) { + (attributes as any[]).forEach((att) => { + lup.attributes[att['_index']] = att['__text']; + }); + } + this.lookups.push(lup); } - this.lookups.push(lup) - - }); + ); // sort - this.lookups = this.lookups.sort(this.compareLookup) + this.lookups = this.lookups.sort(this.compareLookup); // build index - let lastkey = "" + let lastkey = ''; this.lookups.forEach((lup, index) => { - let key = lup.lookupTable + "," + lup.name + "," + lup.geometryType + let key = lup.lookupTable + ',' + lup.name + ',' + lup.geometryType; if (key != lastkey) { this.lookupStartIndex.set(key, index); - lastkey = key + lastkey = key; } - }) + }); } private getSymbol(key: string): Symbol { - let icon = this.chartSymbols.get(key) + let icon = this.chartSymbols.get(key); if (icon && this.chartSymbolsImage) { if (!icon.image) { - icon.image = new Image(icon.width, icon.height) - createImageBitmap(this.chartSymbolsImage, icon.locationX, icon.locationY, icon.width, icon.height).then((bitmap) => { - let canvas = document.createElement("CANVAS") as HTMLCanvasElement - canvas.height = icon.height - canvas.width = icon.width - let ctx = canvas.getContext("2d"); + icon.image = new Image(icon.width, icon.height); + createImageBitmap( + this.chartSymbolsImage, + icon.locationX, + icon.locationY, + icon.width, + icon.height + ).then((bitmap) => { + let canvas = document.createElement('CANVAS') as HTMLCanvasElement; + canvas.height = icon.height; + canvas.width = icon.width; + let ctx = canvas.getContext('2d'); ctx.drawImage(bitmap, 0, 0); icon.image.src = canvas.toDataURL(); - //this.refresh.next() - }) - return icon + //this.refresh.next() + }); + return icon; } else { return icon; } @@ -260,65 +291,76 @@ export class S57Service { private selectLookup(feature: Feature): number { let properties = feature.getProperties(); let geometry = feature.getGeometry(); - let name = properties["layer"] - let geomType = geometry.getType() - let lookupTable = LookupTable.PAPER_CHART + let name = properties['layer']; + let geomType = geometry.getType(); + let lookupTable = LookupTable.PAPER_CHART; let type = GeometryType.POINT; - if (geomType == "Polygon") { - type = GeometryType.AREA - } else if (geomType == "LineString") { - type = GeometryType.LINES + if (geomType == 'Polygon') { + type = GeometryType.AREA; + } else if (geomType == 'LineString') { + type = GeometryType.LINES; } switch (type) { - case GeometryType.POINT: { - if (this.options.graphicsStyle == "Paper") { - lookupTable = LookupTable.PAPER_CHART - } else { - lookupTable = LookupTable.SIMPLIFIED + case GeometryType.POINT: + { + if (this.options.graphicsStyle == 'Paper') { + lookupTable = LookupTable.PAPER_CHART; + } else { + lookupTable = LookupTable.SIMPLIFIED; + } } - }; break; - case GeometryType.LINES: lookupTable = LookupTable.LINES; break - case GeometryType.AREA: { - if (this.options.boundaries == "Plain") { - lookupTable = LookupTable.PLAIN - } else { - lookupTable = LookupTable.SYMBOLIZED + break; + case GeometryType.LINES: + lookupTable = LookupTable.LINES; + break; + case GeometryType.AREA: + { + if (this.options.boundaries == 'Plain') { + lookupTable = LookupTable.PLAIN; + } else { + lookupTable = LookupTable.SYMBOLIZED; + } } - }; break; + break; } - let best = -1 + let best = -1; - let startIndex = this.lookupStartIndex.get(lookupTable + "," + name + "," + type); + let startIndex = this.lookupStartIndex.get( + lookupTable + ',' + name + ',' + type + ); if (startIndex) { - let lup = this.lookups[startIndex] - best = startIndex - let lmatch = 0 - while (lup.name == name && lup.geometryType == type && lup.lookupTable == lookupTable) { - let nmatch = 0 + let lup = this.lookups[startIndex]; + best = startIndex; + let lmatch = 0; + while ( + lup.name == name && + lup.geometryType == type && + lup.lookupTable == lookupTable + ) { + let nmatch = 0; Object.keys(lup.attributes).forEach((k) => { - let v = lup.attributes[k] - let parts = this.attMatch.exec(v) - let key = parts[1].toUpperCase() - let value = parts[2].toUpperCase() - if (value == " ") { + let v = lup.attributes[k]; + let parts = this.attMatch.exec(v); + let key = parts[1].toUpperCase(); + let value = parts[2].toUpperCase(); + if (value == ' ') { nmatch++; return; } - if (value == "?") return + if (value == '?') return; if (properties[key] == value) { - nmatch++ + nmatch++; } - }) + }); if (nmatch >= lmatch) { - best = startIndex - lmatch = nmatch + best = startIndex; + lmatch = nmatch; } - startIndex++ - lup = this.lookups[startIndex] + startIndex++; + lup = this.lookups[startIndex]; } return best; - } return -1; } @@ -336,48 +378,46 @@ export class S57Service { anchorYUnits: 'pixels', anchor: [symbol.pivotX, symbol.pivotY] }) - }) + }); } - return null + return null; } - private stripQuotes(text: string): string { - return text.substring(1).substring(0, text.length - 2) + return text.substring(1).substring(0, text.length - 2); } //TODO implement more parameters private getTextStyle(text: string, params: string[]): Style { - if( typeof text !== 'string') { + if (typeof text !== 'string') { debugger; - return null + return null; } - let textBaseline: any = 'middle' + let textBaseline: any = 'middle'; let offsetY = 0; - if (params[1] == "3") { + if (params[1] == '3') { textBaseline = 'top'; offsetY = 15; - } else if (params[1] == "1") { + } else if (params[1] == '1') { textBaseline = 'bottom'; - offsetY = -15 + offsetY = -15; } let textAlign: any = 'left'; let offsetX = 15; - if (params[0] == "2") { + if (params[0] == '2') { textAlign = 'right'; offsetX = -15; - } else if (params[0] == "1") { + } else if (params[0] == '1') { textAlign = 'center'; - offsetX = 0 + offsetX = 0; } - if (text) { - let tx = text + let tx = text; if (typeof tx !== 'string') { - tx = text.toString() + tx = text.toString(); } return new Style({ text: new Text({ @@ -394,27 +434,26 @@ export class S57Service { } private getTextStyleTX(featureProperties: any, parameters: string): Style { - let params = parameters.split(","); + let params = parameters.split(','); let text = featureProperties[params[0]]; - if(!text) { + if (!text) { return null; } - return this.getTextStyle(text, params.slice(1)) + return this.getTextStyle(text, params.slice(1)); } //TODO format string private getTextStyleTE(featureProperties: any, parameters: string): Style { - let params = parameters.split(","); + let params = parameters.split(','); let text = featureProperties[this.stripQuotes(params[1])]; let format = this.stripQuotes(params[0]); - if(!text || !format) { + if (!text || !format) { return null; } - let formatted=format.replace(/%[0-9]*.?[0-9]*l?[sfd]/,text) - return this.getTextStyle(formatted, params.slice(2)) + let formatted = format.replace(/%[0-9]*.?[0-9]*l?[sfd]/, text); + return this.getTextStyle(formatted, params.slice(2)); } - private getDefaultStyle(): Style { return new Style({ fill: new Fill({ @@ -427,217 +466,383 @@ export class S57Service { }); } - private getDisplayPriority(dispPrio: string): DisplayPriority { switch (dispPrio) { - case "Group 1": return DisplayPriority.PRIO_GROUP1; break; - case "Area 1": return DisplayPriority.PRIO_AREA_1; break; - case "Area 2": return DisplayPriority.PRIO_AREA_2; break; - case "Point Symbol": return DisplayPriority.PRIO_SYMB_POINT; break; - case "Line Symbol": return DisplayPriority.PRIO_SYMB_LINE; break; - case "Area Symbol": return DisplayPriority.PRIO_SYMB_AREA; break; - case "Routing": return DisplayPriority.PRIO_ROUTEING; break; - case "Hazards": return DisplayPriority.PRIO_HAZARDS; break; - case "Mariners": return DisplayPriority.PRIO_MARINERS; break; - default: return DisplayPriority.PRIO_NODATA; break; + case 'Group 1': + return DisplayPriority.PRIO_GROUP1; + break; + case 'Area 1': + return DisplayPriority.PRIO_AREA_1; + break; + case 'Area 2': + return DisplayPriority.PRIO_AREA_2; + break; + case 'Point Symbol': + return DisplayPriority.PRIO_SYMB_POINT; + break; + case 'Line Symbol': + return DisplayPriority.PRIO_SYMB_LINE; + break; + case 'Area Symbol': + return DisplayPriority.PRIO_SYMB_AREA; + break; + case 'Routing': + return DisplayPriority.PRIO_ROUTEING; + break; + case 'Hazards': + return DisplayPriority.PRIO_HAZARDS; + break; + case 'Mariners': + return DisplayPriority.PRIO_MARINERS; + break; + default: + return DisplayPriority.PRIO_NODATA; + break; } } - - private getAreaStyle(colorName:string): Style { - let color = this.colorTables[this.selectedColorTable].colors.get(colorName) + private getAreaStyle(colorName: string): Style { + let color = this.colorTables[this.selectedColorTable].colors.get(colorName); if (color) { return new Style({ fill: new Fill({ color: color - }), + }) }); } return null; } - private getLineStyle(params:string):Style { - let parts=params.split(",") - let color = this.colorTables[this.selectedColorTable].colors.get(parts[2]) - let width=parseInt(parts[1]); - let lineStyle=parts[0]; - let lineDash=null - switch(lineStyle) { - case "DASH":lineDash=[4,4];break; - case "SOLD":lineDash=null;break; - default:console.debug("Unsupported linestyle:",lineStyle) + private getLineStyle(params: string): Style { + let parts = params.split(','); + let color = this.colorTables[this.selectedColorTable].colors.get(parts[2]); + let width = parseInt(parts[1]); + let lineStyle = parts[0]; + let lineDash = null; + switch (lineStyle) { + case 'DASH': + lineDash = [4, 4]; + break; + case 'SOLD': + lineDash = null; + break; + default: + console.debug('Unsupported linestyle:', lineStyle); } return new Style({ stroke: new Stroke({ color: color, - width:width, - lineDash:lineDash - }), + width: width, + lineDash: lineDash + }) }); } - //https://github.com/OpenCPN/OpenCPN/blob/20a781ecc507443e5aaa1d33d0cb91852feb07ee/libs/s52plib/src/s52cnsy.cpp#L5809 - private GetCSTOPMAR01(feature:Feature): string[] { - let rulestring: string = null - let featureProperties = feature.getProperties() - if (!featureProperties["TOPSHP"]) { - rulestring="SY(QUESMRK1)" + //https://github.com/OpenCPN/OpenCPN/blob/20a781ecc507443e5aaa1d33d0cb91852feb07ee/libs/s52plib/src/s52cnsy.cpp#L5809 + private GetCSTOPMAR01(feature: Feature): string[] { + let rulestring: string = null; + let featureProperties = feature.getProperties(); + if (!featureProperties['TOPSHP']) { + rulestring = 'SY(QUESMRK1)'; } else { - let floating = false - let layer = featureProperties["layer"] - if(layer =="LITFLT" || layer == "LITVES" || layer.startsWith("BOY")) { - floating = true + let floating = false; + let layer = featureProperties['layer']; + if (layer == 'LITFLT' || layer == 'LITVES' || layer.startsWith('BOY')) { + floating = true; } - let topshp = featureProperties["TOPSHP"] - if(floating) { - switch(topshp) { - case 1 : rulestring = "SY(TOPMAR02)"; break; - case 2 : rulestring = "SY(TOPMAR04)"; break; - case 3 : rulestring = "SY(TOPMAR10)"; break; - case 4 : rulestring = "SY(TOPMAR12)"; break; - - case 5 : rulestring = "SY(TOPMAR13)"; break; - case 6 : rulestring = "SY(TOPMAR14)"; break; - case 7 : rulestring = "SY(TOPMAR65)"; break; - case 8 : rulestring = "SY(TOPMAR17)"; break; - - case 9 : rulestring = "SY(TOPMAR16)"; break; - case 10: rulestring = "SY(TOPMAR08)"; break; - case 11: rulestring = "SY(TOPMAR07)"; break; - case 12: rulestring = "SY(TOPMAR14)"; break; - - case 13: rulestring = "SY(TOPMAR05)"; break; - case 14: rulestring = "SY(TOPMAR06)"; break; - case 17: rulestring = "SY(TMARDEF2)"; break; - case 18: rulestring = "SY(TOPMAR10)"; break; - - case 19: rulestring = "SY(TOPMAR13)"; break; - case 20: rulestring = "SY(TOPMAR14)"; break; - case 21: rulestring = "SY(TOPMAR13)"; break; - case 22: rulestring = "SY(TOPMAR14)"; break; - - case 23: rulestring = "SY(TOPMAR14)"; break; - case 24: rulestring = "SY(TOPMAR02)"; break; - case 25: rulestring = "SY(TOPMAR04)"; break; - case 26: rulestring = "SY(TOPMAR10)"; break; - - case 27: rulestring = "SY(TOPMAR17)"; break; - case 28: rulestring = "SY(TOPMAR18)"; break; - case 29: rulestring = "SY(TOPMAR02)"; break; - case 30: rulestring = "SY(TOPMAR17)"; break; - - case 31: rulestring = "SY(TOPMAR14)"; break; - case 32: rulestring = "SY(TOPMAR10)"; break; - case 33: rulestring = "SY(TMARDEF2)"; break; - default: rulestring = "SY(TMARDEF2)"; break; + let topshp = featureProperties['TOPSHP']; + if (floating) { + switch (topshp) { + case 1: + rulestring = 'SY(TOPMAR02)'; + break; + case 2: + rulestring = 'SY(TOPMAR04)'; + break; + case 3: + rulestring = 'SY(TOPMAR10)'; + break; + case 4: + rulestring = 'SY(TOPMAR12)'; + break; + + case 5: + rulestring = 'SY(TOPMAR13)'; + break; + case 6: + rulestring = 'SY(TOPMAR14)'; + break; + case 7: + rulestring = 'SY(TOPMAR65)'; + break; + case 8: + rulestring = 'SY(TOPMAR17)'; + break; + + case 9: + rulestring = 'SY(TOPMAR16)'; + break; + case 10: + rulestring = 'SY(TOPMAR08)'; + break; + case 11: + rulestring = 'SY(TOPMAR07)'; + break; + case 12: + rulestring = 'SY(TOPMAR14)'; + break; + + case 13: + rulestring = 'SY(TOPMAR05)'; + break; + case 14: + rulestring = 'SY(TOPMAR06)'; + break; + case 17: + rulestring = 'SY(TMARDEF2)'; + break; + case 18: + rulestring = 'SY(TOPMAR10)'; + break; + + case 19: + rulestring = 'SY(TOPMAR13)'; + break; + case 20: + rulestring = 'SY(TOPMAR14)'; + break; + case 21: + rulestring = 'SY(TOPMAR13)'; + break; + case 22: + rulestring = 'SY(TOPMAR14)'; + break; + + case 23: + rulestring = 'SY(TOPMAR14)'; + break; + case 24: + rulestring = 'SY(TOPMAR02)'; + break; + case 25: + rulestring = 'SY(TOPMAR04)'; + break; + case 26: + rulestring = 'SY(TOPMAR10)'; + break; + + case 27: + rulestring = 'SY(TOPMAR17)'; + break; + case 28: + rulestring = 'SY(TOPMAR18)'; + break; + case 29: + rulestring = 'SY(TOPMAR02)'; + break; + case 30: + rulestring = 'SY(TOPMAR17)'; + break; + + case 31: + rulestring = 'SY(TOPMAR14)'; + break; + case 32: + rulestring = 'SY(TOPMAR10)'; + break; + case 33: + rulestring = 'SY(TMARDEF2)'; + break; + default: + rulestring = 'SY(TMARDEF2)'; + break; } } else { - switch(topshp) { - case 1 : rulestring = "SY(TOPMAR22)"; break; - case 2 : rulestring = "SY(TOPMAR24)"; break; - case 3 : rulestring = "SY(TOPMAR30)"; break; - case 4 : rulestring = "SY(TOPMAR32)"; break; - - case 5 : rulestring = "SY(TOPMAR33)"; break; - case 6 : rulestring = "SY(TOPMAR34)"; break; - case 7 : rulestring = "SY(TOPMAR85)"; break; - case 8 : rulestring = "SY(TOPMAR86)"; break; - - case 9 : rulestring = "SY(TOPMAR36)"; break; - case 10: rulestring = "SY(TOPMAR28)"; break; - case 11: rulestring = "SY(TOPMAR27)"; break; - case 12: rulestring = "SY(TOPMAR14)"; break; - - case 13: rulestring = "SY(TOPMAR25)"; break; - case 14: rulestring = "SY(TOPMAR26)"; break; - case 15: rulestring = "SY(TOPMAR88)"; break; - case 16: rulestring = "SY(TOPMAR87)"; break; - - case 17: rulestring = "SY(TMARDEF1)"; break; - case 18: rulestring = "SY(TOPMAR30)"; break; - case 19: rulestring = "SY(TOPMAR33)"; break; - case 20: rulestring = "SY(TOPMAR34)"; break; - - case 21: rulestring = "SY(TOPMAR33)"; break; - case 22: rulestring = "SY(TOPMAR34)"; break; - case 23: rulestring = "SY(TOPMAR34)"; break; - case 24: rulestring = "SY(TOPMAR22)"; break; - - case 25: rulestring = "SY(TOPMAR24)"; break; - case 26: rulestring = "SY(TOPMAR30)"; break; - case 27: rulestring = "SY(TOPMAR86)"; break; - case 28: rulestring = "SY(TOPMAR89)"; break; - - case 29: rulestring = "SY(TOPMAR22)"; break; - case 30: rulestring = "SY(TOPMAR86)"; break; - case 31: rulestring = "SY(TOPMAR14)"; break; - case 32: rulestring = "SY(TOPMAR30)"; break; - case 33: rulestring = "SY(TMARDEF1)"; break; - default: rulestring = "SY(TMARDEF1)"; break; + switch (topshp) { + case 1: + rulestring = 'SY(TOPMAR22)'; + break; + case 2: + rulestring = 'SY(TOPMAR24)'; + break; + case 3: + rulestring = 'SY(TOPMAR30)'; + break; + case 4: + rulestring = 'SY(TOPMAR32)'; + break; + + case 5: + rulestring = 'SY(TOPMAR33)'; + break; + case 6: + rulestring = 'SY(TOPMAR34)'; + break; + case 7: + rulestring = 'SY(TOPMAR85)'; + break; + case 8: + rulestring = 'SY(TOPMAR86)'; + break; + + case 9: + rulestring = 'SY(TOPMAR36)'; + break; + case 10: + rulestring = 'SY(TOPMAR28)'; + break; + case 11: + rulestring = 'SY(TOPMAR27)'; + break; + case 12: + rulestring = 'SY(TOPMAR14)'; + break; + + case 13: + rulestring = 'SY(TOPMAR25)'; + break; + case 14: + rulestring = 'SY(TOPMAR26)'; + break; + case 15: + rulestring = 'SY(TOPMAR88)'; + break; + case 16: + rulestring = 'SY(TOPMAR87)'; + break; + + case 17: + rulestring = 'SY(TMARDEF1)'; + break; + case 18: + rulestring = 'SY(TOPMAR30)'; + break; + case 19: + rulestring = 'SY(TOPMAR33)'; + break; + case 20: + rulestring = 'SY(TOPMAR34)'; + break; + + case 21: + rulestring = 'SY(TOPMAR33)'; + break; + case 22: + rulestring = 'SY(TOPMAR34)'; + break; + case 23: + rulestring = 'SY(TOPMAR34)'; + break; + case 24: + rulestring = 'SY(TOPMAR22)'; + break; + + case 25: + rulestring = 'SY(TOPMAR24)'; + break; + case 26: + rulestring = 'SY(TOPMAR30)'; + break; + case 27: + rulestring = 'SY(TOPMAR86)'; + break; + case 28: + rulestring = 'SY(TOPMAR89)'; + break; + + case 29: + rulestring = 'SY(TOPMAR22)'; + break; + case 30: + rulestring = 'SY(TOPMAR86)'; + break; + case 31: + rulestring = 'SY(TOPMAR14)'; + break; + case 32: + rulestring = 'SY(TOPMAR30)'; + break; + case 33: + rulestring = 'SY(TMARDEF1)'; + break; + default: + rulestring = 'SY(TMARDEF1)'; + break; } } } - - return rulestring ? [rulestring] : [] + return rulestring ? [rulestring] : []; } //https://github.com/OpenCPN/OpenCPN/blob/c2ffb36ebca8c3777f03ea4d42e24f897aa62609/libs/s52plib/src/s52cnsy.cpp#L4494C40-L4494C40 - private GetCSLIGHTS05(feature:Feature): string[] { - let rulestring: string = null - let featureProperties = feature.getProperties() + private GetCSLIGHTS05(feature: Feature): string[] { + let rulestring: string = null; + let featureProperties = feature.getProperties(); - if (featureProperties["COLOUR"]) { - let colVals = featureProperties["COLOUR"].split(",") as string[] + if (featureProperties['COLOUR']) { + let colVals = featureProperties['COLOUR'].split(',') as string[]; if (colVals.length == 1) { - if (colVals[0] == "3") { - rulestring = "SY(LIGHTS11)" - } else if (colVals[0] == "4") { - rulestring = "SY(LIGHTS12)" - } else if (colVals[0] == "1" || colVals[0] == "6" || colVals[0] == "13") { - rulestring = "SY(LIGHTS13)" + if (colVals[0] == '3') { + rulestring = 'SY(LIGHTS11)'; + } else if (colVals[0] == '4') { + rulestring = 'SY(LIGHTS12)'; + } else if ( + colVals[0] == '1' || + colVals[0] == '6' || + colVals[0] == '13' + ) { + rulestring = 'SY(LIGHTS13)'; } } else if (colVals.length == 2) { - if (colVals.includes("1") && colVals.includes("3")) { - rulestring = "SY(LIGHTS11)" - } else if (colVals.includes("1") && colVals.includes("4")) { - rulestring = "SY(LIGHTS12)" + if (colVals.includes('1') && colVals.includes('3')) { + rulestring = 'SY(LIGHTS11)'; + } else if (colVals.includes('1') && colVals.includes('4')) { + rulestring = 'SY(LIGHTS12)'; } } - } - return rulestring ? [rulestring] : [] + } + return rulestring ? [rulestring] : []; } - //https://github.com/OpenCPN/OpenCPN/blob/c2ffb36ebca8c3777f03ea4d42e24f897aa62609/libs/s52plib/src/s52cnsy.cpp#L5597 private GetSeabed01(drval1: number, drval2: number): string[] { - let retval: string[] = ["AC(DEPIT)"]; + let retval: string[] = ['AC(DEPIT)']; let shallow = true; if (drval1 >= 0 && drval2 > 0) { - retval = ["AC(DEPVS)"]; + retval = ['AC(DEPVS)']; } if (this.options.colors == 2) { - if (drval1 >= this.options.safetyDepth && drval2 > this.options.safetyDepth) { - retval = ["AC(DEPDW)"]; + if ( + drval1 >= this.options.safetyDepth && + drval2 > this.options.safetyDepth + ) { + retval = ['AC(DEPDW)']; shallow = false; } } else { - if (drval1 >= this.options.shallowDepth && drval2 > this.options.shallowDepth) { - retval = ["AC(DEPMS)"]; + if ( + drval1 >= this.options.shallowDepth && + drval2 > this.options.shallowDepth + ) { + retval = ['AC(DEPMS)']; } - if (drval1 >= this.options.safetyDepth && drval2 > this.options.safetyDepth) { - retval = ["AC(DEPMD)"] + if ( + drval1 >= this.options.safetyDepth && + drval2 > this.options.safetyDepth + ) { + retval = ['AC(DEPMD)']; shallow = false; } if (drval1 >= this.options.deepDepth && drval2 > this.options.deepDepth) { - retval = ["AC(DEPDW)"]; + retval = ['AC(DEPDW)']; shallow = false; } } if (shallow) { - retval.push("AP(DIAMOND1)") + retval.push('AP(DIAMOND1)'); } return retval; @@ -645,42 +850,41 @@ export class S57Service { //https://github.com/OpenCPN/OpenCPN/blob/c2ffb36ebca8c3777f03ea4d42e24f897aa62609/libs/s52plib/src/s52cnsy.cpp#L4295 private GetCSDEPCNT02(feature: Feature): string[] { - let rulestring: string = null - let featureProperties = feature.getProperties() - let geometry = feature.getGeometry() + let rulestring: string = null; + let featureProperties = feature.getProperties(); + let geometry = feature.getGeometry(); - let safe = false + let safe = false; let drval1 = 0; let depth_value = -1; let valdco = 0; - let quapos =0; - let objl = 0 + let quapos = 0; + let objl = 0; - if (featureProperties["OBJL"]) { - objl=parseInt(featureProperties["OBJL"]) + if (featureProperties['OBJL']) { + objl = parseInt(featureProperties['OBJL']); } - if (DEPARE == objl && geometry.getType() == "LineString") { - if ( featureProperties["DRVAL1"]) { - drval1 = parseFloat(featureProperties["DRVAL1"]) + if (DEPARE == objl && geometry.getType() == 'LineString') { + if (featureProperties['DRVAL1']) { + drval1 = parseFloat(featureProperties['DRVAL1']); } - depth_value = drval1 + depth_value = drval1; } else { - if ( featureProperties["VALDCO"]) { - valdco = parseFloat(featureProperties["VALDCO"]) - depth_value = valdco + if (featureProperties['VALDCO']) { + valdco = parseFloat(featureProperties['VALDCO']); + depth_value = valdco; } } - if(depth_value 2 && quapos < 10) { - - if(depth_value == this.selectedSafeContour) { - rulestring="LS(DASH,2,DEPSC)" + if (featureProperties['QUAPOS']) { + quapos = parseFloat(featureProperties['QUAPOS']); + if (quapos > 2 && quapos < 10) { + if (depth_value == this.selectedSafeContour) { + rulestring = 'LS(DASH,2,DEPSC)'; } // else { // rulestring="LS(DASH,1,DEPCN)" @@ -688,115 +892,137 @@ export class S57Service { // } } } else { - if(depth_value == this.selectedSafeContour) { - rulestring="LS(SOLD,2,DEPSC)" - } + if (depth_value == this.selectedSafeContour) { + rulestring = 'LS(SOLD,2,DEPSC)'; + } // else { // rulestring="LS(SOLD,1,DEPCN)" // } } - return rulestring ? [rulestring] : [] + return rulestring ? [rulestring] : []; } - //https://github.com/OpenCPN/OpenCPN/blob/c2ffb36ebca8c3777f03ea4d42e24f897aa62609/libs/s52plib/src/s52cnsy.cpp#L4247 private getCSDEPARE01(feature: Feature): string[] { - let retval: string[] = [] + let retval: string[] = []; - let featureProperties = feature.getProperties() + let featureProperties = feature.getProperties(); - let drval1 = parseFloat(featureProperties["DRVAL1"]) - let drval2 = parseFloat(featureProperties["DRVAL2"]) + let drval1 = parseFloat(featureProperties['DRVAL1']); + let drval2 = parseFloat(featureProperties['DRVAL2']); - retval = this.GetSeabed01(drval1, drval2) + retval = this.GetSeabed01(drval1, drval2); - let objl = featureProperties["OBJL"] + let objl = featureProperties['OBJL']; if (parseInt(objl) == DRGARE) { - retval.push("AP(DRGARE01)"); - retval.push("LS(DASH,1,CHGRF)"); + retval.push('AP(DRGARE01)'); + retval.push('LS(DASH,1,CHGRF)'); // if (featureProperties["RESTRN"]) { // } } - - return retval + return retval; } private evalCS(feature: Feature, instruction: string): string[] { - let retval: string[] = [] - let instrParts = this.instructionMatch.exec(instruction) + let retval: string[] = []; + let instrParts = this.instructionMatch.exec(instruction); if (instrParts && instrParts.length > 1) { switch (instrParts[2]) { - case "LIGHTS05": retval = this.GetCSLIGHTS05(feature); break; - case "DEPCNT02": retval = this.GetCSDEPCNT02(feature); break; - case "DEPARE01": - case "DEPARE02": retval = this.getCSDEPARE01(feature); break; - case "TOPMAR01": retval = this.GetCSTOPMAR01(feature); break; - default: console.debug("Unsupported CS:" + instruction) + case 'LIGHTS05': + retval = this.GetCSLIGHTS05(feature); + break; + case 'DEPCNT02': + retval = this.GetCSDEPCNT02(feature); + break; + case 'DEPARE01': + case 'DEPARE02': + retval = this.getCSDEPARE01(feature); + break; + case 'TOPMAR01': + retval = this.GetCSTOPMAR01(feature); + break; + default: + console.debug('Unsupported CS:' + instruction); } } - return retval + return retval; } private getStylesFromRules(lup: Lookup, feature: Feature): Style[] { - let styles: Style[] = [] + let styles: Style[] = []; if (lup) { - let properties = feature.getProperties() - let instructions = lup.instruction.split(";") + let properties = feature.getProperties(); + let instructions = lup.instruction.split(';'); //PreProcess CS for (var i = 0; i < instructions.length; i++) { - if (instructions[i].startsWith("CS")) { - let conditionals = this.evalCS(feature, instructions[i]) - instructions.splice(i, 1, ...conditionals) + if (instructions[i].startsWith('CS')) { + let conditionals = this.evalCS(feature, instructions[i]); + instructions.splice(i, 1, ...conditionals); } } instructions.forEach((instruction) => { - let instrParts = this.instructionMatch.exec(instruction) + let instrParts = this.instructionMatch.exec(instruction); if (instrParts && instrParts.length > 1) { - let style: Style = null + let style: Style = null; switch (instrParts[1]) { - case "SY": style = this.getSymbolStyle(instrParts[2]); break; - case "AC": style = this.getAreaStyle(instrParts[2]); break; - case "TX": style = this.getTextStyleTX(properties, instrParts[2]); break; - case "TE": style = this.getTextStyleTE(properties, instrParts[2]); break; - case "LS": style = this.getLineStyle(instrParts[2]); break; - default: console.debug("Unsupported instruction:" + instruction) + case 'SY': + style = this.getSymbolStyle(instrParts[2]); + break; + case 'AC': + style = this.getAreaStyle(instrParts[2]); + break; + case 'TX': + style = this.getTextStyleTX(properties, instrParts[2]); + break; + case 'TE': + style = this.getTextStyleTE(properties, instrParts[2]); + break; + case 'LS': + style = this.getLineStyle(instrParts[2]); + break; + default: + console.debug('Unsupported instruction:' + instruction); } if (style != null) { - style.setZIndex(lup.displayPriority) - styles.push(style) + style.setZIndex(lup.displayPriority); + styles.push(style); } } - }) + }); } - return styles + return styles; } - - private updateSafeContour(feature:Feature):number { - + private updateSafeContour(feature: Feature): number { let properties = feature.getProperties(); - if (properties["DRVAL1"]) { - let drval1 = properties["DRVAL1"] - if (drval1 >= this.options.safetyDepth && drval1 < this.selectedSafeContour) { - this.selectedSafeContour = drval1 + if (properties['DRVAL1']) { + let drval1 = properties['DRVAL1']; + if ( + drval1 >= this.options.safetyDepth && + drval1 < this.selectedSafeContour + ) { + this.selectedSafeContour = drval1; } - return drval1 + return drval1; } - if (properties["VALDCO"]) { - let valdco = properties["VALDCO"] - if (valdco >= this.options.safetyDepth && valdco < this.selectedSafeContour) { - this.selectedSafeContour = valdco + if (properties['VALDCO']) { + let valdco = properties['VALDCO']; + if ( + valdco >= this.options.safetyDepth && + valdco < this.selectedSafeContour + ) { + this.selectedSafeContour = valdco; } - return valdco + return valdco; } - return 0 + return 0; } // the interface of this service @@ -807,36 +1033,36 @@ export class S57Service { let lupIndex1 = feature1[LOOKUPINDEXKEY]; let lupIndex2 = feature1[LOOKUPINDEXKEY]; if (!lupIndex1) { - lupIndex1 = this.selectLookup(feature1) - feature1[LOOKUPINDEXKEY] = lupIndex1 + lupIndex1 = this.selectLookup(feature1); + feature1[LOOKUPINDEXKEY] = lupIndex1; } if (!lupIndex2) { - lupIndex2 = this.selectLookup(feature2) - feature2[LOOKUPINDEXKEY] = lupIndex2 + lupIndex2 = this.selectLookup(feature2); + feature2[LOOKUPINDEXKEY] = lupIndex2; } - + if (lupIndex1 >= 0 && lupIndex2 >= 0) { - let c1 = this.lookups[lupIndex1].displayPriority - let c2 = this.lookups[lupIndex2].displayPriority - let cmp = c1 - c2 + let c1 = this.lookups[lupIndex1].displayPriority; + let c2 = this.lookups[lupIndex2].displayPriority; + let cmp = c1 - c2; if (cmp) { - return cmp + return cmp; } } - if( o1 != o2 ) { - return o1-o2 - } + if (o1 != o2) { + return o1 - o2; + } - return lupIndex1 - lupIndex2 - } + return lupIndex1 - lupIndex2; + }; public getStyle = (feature: Feature, resolution: number): Style[] => { let lupIndex = feature[LOOKUPINDEXKEY]; if (lupIndex >= 0) { - let lup = this.lookups[lupIndex] - return this.getStylesFromRules(lup, feature) + let lup = this.lookups[lupIndex]; + return this.getStylesFromRules(lup, feature); } return null; - } -} \ No newline at end of file + }; +} diff --git a/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts b/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts index f2d3f3b7..f3b6e40c 100644 --- a/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts +++ b/src/app/modules/map/ol/lib/vectorLayerStyleFactory.ts @@ -1,176 +1,168 @@ import { Injectable } from '@angular/core'; import { SKChart } from 'src/app/modules'; -import { S57Service } from './s57.service' +import { S57Service } from './s57.service'; import VectorTileLayer from 'ol/layer/VectorTile'; import VectorTileSource from 'ol/source/VectorTile'; import { MVT } from 'ol/format'; import { Style, Fill, Stroke } from 'ol/style'; import * as pmtiles from 'pmtiles'; - export abstract class VectorLayerStyler { - public MinZ: number - public MaxZ: number - - constructor(public chart: SKChart) { - this.MinZ = - chart.minZoom && chart.minZoom >= 0.1 - ? chart.minZoom - 0.1 - : chart.minZoom; - this.MaxZ = chart.maxZoom; - } - - public abstract ApplyStyle(vectorLayer: VectorTileLayer) - public abstract CreateLayer():VectorTileLayer + public MinZ: number; + public MaxZ: number; + + constructor(public chart: SKChart) { + this.MinZ = + chart.minZoom && chart.minZoom >= 0.1 + ? chart.minZoom - 0.1 + : chart.minZoom; + this.MaxZ = chart.maxZoom; + } + + public abstract ApplyStyle(vectorLayer: VectorTileLayer); + public abstract CreateLayer(): VectorTileLayer; } - class S57LayerStyler extends VectorLayerStyler { - constructor(chart: SKChart, private s57service: S57Service) { - super(chart) - } - - public CreateLayer(): VectorTileLayer { - return new VectorTileLayer() - } - - - public ApplyStyle(vectorLayer: VectorTileLayer) { - vectorLayer.set("declutter",true) - const source = new VectorTileSource({ - url: this.chart.url, - minZoom: this.chart.minZoom, - maxZoom: this.chart.maxZoom, - format: new MVT({}) - }); - - vectorLayer.setSource(source) - vectorLayer.setPreload(0) - vectorLayer.setStyle(this.s57service.getStyle) - vectorLayer.setMinZoom(13) - vectorLayer.setMaxZoom(23) - vectorLayer.setRenderOrder(this.s57service.renderOrder) - - this.s57service.refresh.subscribe(() => { - source.refresh() - }) - } + constructor(chart: SKChart, private s57service: S57Service) { + super(chart); + } + + public CreateLayer(): VectorTileLayer { + return new VectorTileLayer(); + } + + public ApplyStyle(vectorLayer: VectorTileLayer) { + vectorLayer.set('declutter', true); + const source = new VectorTileSource({ + url: this.chart.url, + minZoom: this.chart.minZoom, + maxZoom: this.chart.maxZoom, + format: new MVT({}) + }); + + vectorLayer.setSource(source); + vectorLayer.setPreload(0); + vectorLayer.setStyle(this.s57service.getStyle); + vectorLayer.setMinZoom(13); + vectorLayer.setMaxZoom(23); + vectorLayer.setRenderOrder(this.s57service.renderOrder); + + this.s57service.refresh.subscribe(() => { + source.refresh(); + }); + } } - class DefaultLayerStyler extends VectorLayerStyler { - constructor(chart: SKChart) { - super(chart) - } - - public CreateLayer(): VectorTileLayer { - return new VectorTileLayer() - } - - // apply default vector tile style - applyVectorStyle() { - return new Style({ - fill: new Fill({ - color: 'rgba(#224, 209, 14, 0.8)' - }), - stroke: new Stroke({ - color: '#444', - width: 1 - }) - }); - } - - public ApplyStyle(vectorLayer: VectorTileLayer) { - // mbtiles source - const source = new VectorTileSource({ - url: this.chart.url, - format: new MVT({ - layers: - this.chart.layers && this.chart.layers.length !== 0 - ? this.chart.layers - : null - }) - }); - - vectorLayer.setSource(source) - vectorLayer.setPreload(0) - vectorLayer.setStyle(this.applyVectorStyle) - vectorLayer.setMinZoom(this.MinZ) - vectorLayer.setMaxZoom(this.MaxZ) - } + constructor(chart: SKChart) { + super(chart); + } + + public CreateLayer(): VectorTileLayer { + return new VectorTileLayer(); + } + + // apply default vector tile style + applyVectorStyle() { + return new Style({ + fill: new Fill({ + color: 'rgba(#224, 209, 14, 0.8)' + }), + stroke: new Stroke({ + color: '#444', + width: 1 + }) + }); + } + + public ApplyStyle(vectorLayer: VectorTileLayer) { + // mbtiles source + const source = new VectorTileSource({ + url: this.chart.url, + format: new MVT({ + layers: + this.chart.layers && this.chart.layers.length !== 0 + ? this.chart.layers + : null + }) + }); + + vectorLayer.setSource(source); + vectorLayer.setPreload(0); + vectorLayer.setStyle(this.applyVectorStyle); + vectorLayer.setMinZoom(this.MinZ); + vectorLayer.setMaxZoom(this.MaxZ); + } } class PMLayerStyler extends DefaultLayerStyler { - constructor(chart: SKChart) { - super(chart) - } - - public CreateLayer(): VectorTileLayer { - return new VectorTileLayer({ declutter: true }) - } - - public ApplyStyle(vectorLayer: VectorTileLayer) { - - vectorLayer.set("declutter",true) - const tiles = new pmtiles.PMTiles(this.chart.url); - - function loader(tile, url) { - // the URL construction is done internally by OL, so we need to parse it - // back out here using a hacky regex - const re = new RegExp(/pmtiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/); - const result = url.match(re); - const z = +result[2]; - const x = +result[3]; - const y = +result[4]; - - tile.setLoader((extent, resolution, projection) => { - tile.setState(1); // LOADING - tiles.getZxy(z, x, y).then((tile_result) => { - if (tile_result) { - const format = tile.getFormat(); - const features = format.readFeatures(tile_result.data, { - //}.buffer, { - extent: extent, - featureProjection: projection - }); - tile.setFeatures(features); - tile.setState(2); // LOADED - } else { - tile.setState(4); // EMPTY - } - }); + constructor(chart: SKChart) { + super(chart); + } + + public CreateLayer(): VectorTileLayer { + return new VectorTileLayer({ declutter: true }); + } + + public ApplyStyle(vectorLayer: VectorTileLayer) { + vectorLayer.set('declutter', true); + const tiles = new pmtiles.PMTiles(this.chart.url); + + function loader(tile, url) { + // the URL construction is done internally by OL, so we need to parse it + // back out here using a hacky regex + const re = new RegExp(/pmtiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/); + const result = url.match(re); + const z = +result[2]; + const x = +result[3]; + const y = +result[4]; + + tile.setLoader((extent, resolution, projection) => { + tile.setState(1); // LOADING + tiles.getZxy(z, x, y).then((tile_result) => { + if (tile_result) { + const format = tile.getFormat(); + const features = format.readFeatures(tile_result.data, { + //}.buffer, { + extent: extent, + featureProjection: projection }); - } - - const source = new VectorTileSource({ - format: new MVT(), - url: 'pmtiles://' + this.chart.url + '/{z}/{x}/{y}', - tileLoadFunction: loader - }) - - vectorLayer.setSource(source) - vectorLayer.setPreload(0) - vectorLayer.setStyle(this.applyVectorStyle) - vectorLayer.setMinZoom(this.chart.minZoom) - vectorLayer.setMaxZoom(this.chart.maxZoom) + tile.setFeatures(features); + tile.setState(2); // LOADED + } else { + tile.setState(4); // EMPTY + } + }); + }); } -} + const source = new VectorTileSource({ + format: new MVT(), + url: 'pmtiles://' + this.chart.url + '/{z}/{x}/{y}', + tileLoadFunction: loader + }); + + vectorLayer.setSource(source); + vectorLayer.setPreload(0); + vectorLayer.setStyle(this.applyVectorStyle); + vectorLayer.setMinZoom(this.chart.minZoom); + vectorLayer.setMaxZoom(this.chart.maxZoom); + } +} @Injectable({ - providedIn: 'root' + providedIn: 'root' }) export class VectorLayerStyleFactory { - constructor(private s57service: S57Service) { - - } - public CreateVectorLayerStyler(chart: SKChart): VectorLayerStyler { - if (chart.url.indexOf('.pmtiles') !== -1) { - return new PMLayerStyler(chart); - } else if (chart.type == "S-57") { - return new S57LayerStyler(chart, this.s57service) - } else { - return new DefaultLayerStyler(chart); - } + constructor(private s57service: S57Service) {} + public CreateVectorLayerStyler(chart: SKChart): VectorLayerStyler { + if (chart.url.indexOf('.pmtiles') !== -1) { + return new PMLayerStyler(chart); + } else if (chart.type == 'S-57') { + return new S57LayerStyler(chart, this.s57service); + } else { + return new DefaultLayerStyler(chart); } -} \ No newline at end of file + } +} diff --git a/src/app/modules/settings/settings-dialog.html b/src/app/modules/settings/settings-dialog.html index 64d3d4d8..52549ca7 100644 --- a/src/app/modules/settings/settings-dialog.html +++ b/src/app/modules/settings/settings-dialog.html @@ -226,7 +226,96 @@ Animate Map - --> + --> + + + + +
+
VECTOR CHARTS
+ +
+
+ + Graphics Style + + {{i.value}} + + +
+
+ + Boundaries + + {{i.value}} + + +
+
+ + Colors + + {{i}} + + +
+
+
+
+ + Shallow depth + + m + +
+
+ + Safety depth + + m + +
+
+ + Deep depth + + m + +
+
@@ -712,82 +801,6 @@ -
-
VECTOR CHART DISPLAY
- -
-
- - - {{i.value}} - - -
-
- - - {{i.value}} - - -
-
- - - {{i}} - - -
-
-
-
- - Shallow depth - - m - -
-
- - Safety depth - - m - -
-
- - Deep depth - - m - -
-
-
-
-
RESOURCES: NOTES
diff --git a/src/app/modules/settings/settings-dialog.ts b/src/app/modules/settings/settings-dialog.ts index 9221b024..fc3bc9fa 100644 --- a/src/app/modules/settings/settings-dialog.ts +++ b/src/app/modules/settings/settings-dialog.ts @@ -18,12 +18,12 @@ export class SettingsDialog implements OnInit { public display = { favourites: false }; public menuItems = [ { id: 'sectDisplay', text: 'Display' }, + { id: 'sectS57', text: 'Charts' }, { id: 'sectUnits', text: 'Units & Values' }, { id: 'sectCourse', text: 'Course' }, { id: 'sectVessels', text: 'Vessels' }, { id: 'sectNotes', text: 'Notes' }, { id: 'sectVideo', text: 'Video' }, - { id: 'sectS57', text: 'Vector chart display' }, { id: 'sectResLayers', text: 'Resources' }, { id: 'sectResLayers', text: 'Signal K' } ]; diff --git a/src/app/modules/settings/settings.facade.ts b/src/app/modules/settings/settings.facade.ts index 7517c3df..f1222c88 100644 --- a/src/app/modules/settings/settings.facade.ts +++ b/src/app/modules/settings/settings.facade.ts @@ -137,20 +137,19 @@ export class SettingsFacade { fixedPosition = [0, 0]; - s57Options = { graphicsStyle: new Map([ - ['Simplified','Simplified'], - ['Paper','Paper chart'], + ['Simplified', 'Simplified'], + ['Paper', 'Paper chart'] ]), boundaries: new Map([ - ['Symbolized','Symbolized'], - ['Plain','Plain'], + ['Symbolized', 'Symbolized'], + ['Plain', 'Plain'] ]), - colors: [2,4], - shallowDepth:2, - safetyDepth:3, - deepDepth:6 + colors: [2, 4], + shallowDepth: 2, + safetyDepth: 3, + deepDepth: 6 }; // *****************************************************