From f2e5b0a7e3fc512579fc16df81242131d6c0e6e9 Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Fri, 7 May 2021 08:11:42 +0200 Subject: [PATCH 1/4] Adds support for symbol tag of a style within a label --- src/MapfileStyleParser.spec.ts | 8 ++++++++ src/MapfileStyleParser.ts | 18 +++++++++++++++++- src/mapfile2js/mapfileTypes.ts | 1 + src/mapfile2js/parse/resolveSymbolset.ts | 21 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/MapfileStyleParser.spec.ts b/src/MapfileStyleParser.spec.ts index 526ec02..30e7345 100644 --- a/src/MapfileStyleParser.spec.ts +++ b/src/MapfileStyleParser.spec.ts @@ -25,6 +25,7 @@ import raster_resampling_average from '../data/styles/raster_resampling_average' import raster_resampling_bilinear from '../data/styles/raster_resampling_bilinear'; import raster_resampling_nearest from '../data/styles/raster_resampling_nearest'; import line_set_of_expressions from '../data/styles/line_set_of_expressions'; +import point_symbol_style_in_label from '../data/styles/point_symbol_style_in_label'; it('MapfileStyleParser is defined', () => { @@ -202,6 +203,13 @@ describe('MapfileStyleParser implements StyleParser', () => { const geoStylerStyle = await styleParser.readMultiStyles(mapfile); expect(geoStylerStyle).toBeDefined(); expect(geoStylerStyle).toEqual(line_set_of_expressions); + + it('can read a simple MapFile with symbol style in label', async () => { + expect.assertions(2); + const mapfile = fs.readFileSync( './data/mapfiles/point_symbol_style_in_label.map', 'utf8'); + const geoStylerStyle = await styleParser.readMultiStyles(mapfile); + expect(geoStylerStyle).toBeDefined(); + expect(geoStylerStyle).toEqual(point_symbol_style_in_label); }); it('can translate Mapfile to SLD', async () => { diff --git a/src/MapfileStyleParser.ts b/src/MapfileStyleParser.ts index 6050b3c..1a9df23 100644 --- a/src/MapfileStyleParser.ts +++ b/src/MapfileStyleParser.ts @@ -45,6 +45,8 @@ export class MapfileStyleParser implements StyleParser { symbolsPath = `${process.cwd()}/symbols.sym`; + iconsOnLabels: IconSymbolizer = { kind: 'Icon' }; + constructor(opts?: ConstructorParams) { Object.assign(this, opts); } @@ -421,7 +423,7 @@ export class MapfileStyleParser implements StyleParser { getIconSymbolizerFromMapfileStyle(mapfileStyle: MapfileStyle): IconSymbolizer { const iconSymbolizer: IconSymbolizer = { kind: 'Icon', - image: mapfileStyle.symbol.image, + image: mapfileStyle.symbol.image || mapfileStyle.symbol, } as IconSymbolizer; if (mapfileStyle.size) { @@ -474,6 +476,15 @@ export class MapfileStyleParser implements StyleParser { textSymbolizer.padding = parseFloat(styleParameters.buffer); } + // collect icon data if defined within the label tag + if (styleParameters.styles) { + styleParameters.styles.forEach((style: MapfileStyle )=> { + if (style.symbol) { + this.iconsOnLabels = this.getIconSymbolizerFromMapfileStyle(style); + } + }); + } + if (styleParameters.position) { const anchorpointMap = { cc: 'center', @@ -821,6 +832,11 @@ export class MapfileStyleParser implements StyleParser { }); } + // check for available icons + if (Object.keys(this.iconsOnLabels).length > 1) { + symbolizers.unshift(this.iconsOnLabels as IconSymbolizer); + } + return symbolizers; } diff --git a/src/mapfile2js/mapfileTypes.ts b/src/mapfile2js/mapfileTypes.ts index ea0287f..9bd9dbb 100644 --- a/src/mapfile2js/mapfileTypes.ts +++ b/src/mapfile2js/mapfileTypes.ts @@ -131,6 +131,7 @@ export interface MapfileLabel { color: string; outlinecolor: string; outlinewidth: number; + styles?: MapfileStyle[]; } interface MapfileScaleTokenValue {} diff --git a/src/mapfile2js/parse/resolveSymbolset.ts b/src/mapfile2js/parse/resolveSymbolset.ts index 4f57c22..162aa1e 100644 --- a/src/mapfile2js/parse/resolveSymbolset.ts +++ b/src/mapfile2js/parse/resolveSymbolset.ts @@ -53,6 +53,27 @@ export function resolveSymbolsFromMapfile(mapfile: Mapfile): Mapfile { }); } }); + } else if (mclass.labels) { + // parse symbol data within a style tag of a label + mclass.labels.forEach((label) => { + const styles: MapfileStyle[] = label.styles as MapfileStyle[]; + if (styles) { + styles.forEach((style: MapfileStyle) => { + if (style.symbol) { + symbols.forEach((symbol: any) => { + if ( + symbol.name && + symbol.image && + symbol.name === style.symbol + ) { + style.symbol = (parse(symbol.image) + .base as unknown) as MapfileSymbol; + } + }); + } + }); + } + }); } }); } From 0e7462a7f29979b9d2772ded1093b3a1165806a9 Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Fri, 7 May 2021 08:20:19 +0200 Subject: [PATCH 2/4] Adds missing test files --- data/mapfiles/point_symbol_style_in_label.map | 28 +++++++++++++++++++ data/styles/point_symbol_style_in_label.ts | 25 +++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 data/mapfiles/point_symbol_style_in_label.map create mode 100644 data/styles/point_symbol_style_in_label.ts diff --git a/data/mapfiles/point_symbol_style_in_label.map b/data/mapfiles/point_symbol_style_in_label.map new file mode 100644 index 0000000..e5ec366 --- /dev/null +++ b/data/mapfiles/point_symbol_style_in_label.map @@ -0,0 +1,28 @@ +LAYER + NAME point_symbol_style_in_label + MAXSCALEDENOM 35000 + TYPE POINT + EXTENT -20026376.39 -20048966.10 20026376.39 20048966.10 + PROJECTION + "init=epsg:3857" + END + CLASS + MAXSCALEDENOM 35000 + LABEL + SIZE 6.644432194046306 + COLOR "#ffffff" + TEXT '[ref]' + PARTIALS false + FONT "ptsansbold" + TYPE truetype + STYLE + SYMBOL "simple_point_symbol_svg" + END + END + END +END +SYMBOL + NAME simple_point_symbol_svg + IMAGE "simple_point_symbol.svg" + TYPE svg +END diff --git a/data/styles/point_symbol_style_in_label.ts b/data/styles/point_symbol_style_in_label.ts new file mode 100644 index 0000000..7413789 --- /dev/null +++ b/data/styles/point_symbol_style_in_label.ts @@ -0,0 +1,25 @@ +import { Style } from 'geostyler-style'; + +const pointSymbolStyle: Style = [ + { + name: 'point_symbol_style_in_label', + rules: [ + { + name: '', + scaleDenominator: { max: 35000 }, + symbolizers: [ + { kind: 'Icon', image: 'simple_point_symbol.svg' }, + { + kind: 'Text', + label: '{{ref}}', + font: ['ptsansbold'], + size: 6.644432194046306, + color: '#ffffff' + } + ] + } + ] + } +]; + +export default pointSymbolStyle; From 9e1a9a5bcc753a3ec5b2bed71cc1b24b0ed217eb Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Fri, 7 May 2021 09:12:15 +0200 Subject: [PATCH 3/4] Uses optional chaining --- src/mapfile2js/parse/resolveSymbolset.ts | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/mapfile2js/parse/resolveSymbolset.ts b/src/mapfile2js/parse/resolveSymbolset.ts index 162aa1e..dd7428d 100644 --- a/src/mapfile2js/parse/resolveSymbolset.ts +++ b/src/mapfile2js/parse/resolveSymbolset.ts @@ -57,22 +57,18 @@ export function resolveSymbolsFromMapfile(mapfile: Mapfile): Mapfile { // parse symbol data within a style tag of a label mclass.labels.forEach((label) => { const styles: MapfileStyle[] = label.styles as MapfileStyle[]; - if (styles) { - styles.forEach((style: MapfileStyle) => { - if (style.symbol) { - symbols.forEach((symbol: any) => { - if ( - symbol.name && - symbol.image && - symbol.name === style.symbol - ) { - style.symbol = (parse(symbol.image) - .base as unknown) as MapfileSymbol; - } - }); + styles?.forEach((style: MapfileStyle) => { + symbols?.forEach((symbol: any) => { + if ( + symbol.name && + symbol.image && + symbol.name === style.symbol + ) { + style.symbol = (parse(symbol.image) + .base as unknown) as MapfileSymbol; } }); - } + }); }); } }); From 8900ca04689999643bfad66b97e4176ba91bd28d Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Fri, 7 May 2021 11:38:51 +0200 Subject: [PATCH 4/4] Restructuring of functionality --- data/mapfiles/point_symbol_style_in_label.map | 47 ++++++++++++++++-- data/styles/point_symbol_style_in_label.ts | 32 ++++++++++++- src/MapfileStyleParser.ts | 48 ++++++++++++------- 3 files changed, 106 insertions(+), 21 deletions(-) diff --git a/data/mapfiles/point_symbol_style_in_label.map b/data/mapfiles/point_symbol_style_in_label.map index e5ec366..6ada171 100644 --- a/data/mapfiles/point_symbol_style_in_label.map +++ b/data/mapfiles/point_symbol_style_in_label.map @@ -16,13 +16,54 @@ LAYER FONT "ptsansbold" TYPE truetype STYLE - SYMBOL "simple_point_symbol_svg" + SYMBOL "simple_point_1_symbol_svg" + END + STYLE + SYMBOL "simple_point_2_symbol_svg" + END + END + END + CLASS + MAXSCALEDENOM 25000 + LABEL + SIZE 5.644432194046306 + COLOR "#ffffff" + TEXT '[ref]' + PARTIALS false + FONT "ptsansbold" + TYPE truetype + STYLE + SYMBOL "simple_point_2_symbol_svg" + END + END + END + CLASS + MAXSCALEDENOM 20000 + LABEL + SIZE 4.644432194046306 + COLOR "#ffffff" + TEXT '[ref]' + PARTIALS false + FONT "ptsansbold" + TYPE truetype + STYLE + SYMBOL "simple_point_3_symbol_svg" END END END END SYMBOL - NAME simple_point_symbol_svg - IMAGE "simple_point_symbol.svg" + NAME simple_point_1_symbol_svg + IMAGE "simple_point_1_symbol.svg" + TYPE svg +END +SYMBOL + NAME simple_point_2_symbol_svg + IMAGE "simple_point_2_symbol.svg" + TYPE svg +END +SYMBOL + NAME simple_point_3_symbol_svg + IMAGE "simple_point_3_symbol.svg" TYPE svg END diff --git a/data/styles/point_symbol_style_in_label.ts b/data/styles/point_symbol_style_in_label.ts index 7413789..c2e73a6 100644 --- a/data/styles/point_symbol_style_in_label.ts +++ b/data/styles/point_symbol_style_in_label.ts @@ -8,7 +8,8 @@ const pointSymbolStyle: Style = [ name: '', scaleDenominator: { max: 35000 }, symbolizers: [ - { kind: 'Icon', image: 'simple_point_symbol.svg' }, + { kind: 'Icon', image: 'simple_point_1_symbol.svg' }, + { kind: 'Icon', image: 'simple_point_2_symbol.svg' }, { kind: 'Text', label: '{{ref}}', @@ -17,9 +18,36 @@ const pointSymbolStyle: Style = [ color: '#ffffff' } ] + }, + { + name: '', + scaleDenominator: { max: 25000 }, + symbolizers: [ + { kind: 'Icon', image: 'simple_point_2_symbol.svg' }, + { + kind: 'Text', + label: '{{ref}}', + font: ['ptsansbold'], + size: 5.644432194046306, + color: '#ffffff' + } + ] + }, + { + name: '', + scaleDenominator: { max: 20000 }, + symbolizers: [ + { kind: 'Icon', image: 'simple_point_3_symbol.svg' }, + { + kind: 'Text', + label: '{{ref}}', + font: ['ptsansbold'], + size: 4.644432194046306, + color: '#ffffff' + } + ] } ] } ]; - export default pointSymbolStyle; diff --git a/src/MapfileStyleParser.ts b/src/MapfileStyleParser.ts index 1a9df23..efddbcb 100644 --- a/src/MapfileStyleParser.ts +++ b/src/MapfileStyleParser.ts @@ -45,8 +45,6 @@ export class MapfileStyleParser implements StyleParser { symbolsPath = `${process.cwd()}/symbols.sym`; - iconsOnLabels: IconSymbolizer = { kind: 'Icon' }; - constructor(opts?: ConstructorParams) { Object.assign(this, opts); } @@ -476,15 +474,6 @@ export class MapfileStyleParser implements StyleParser { textSymbolizer.padding = parseFloat(styleParameters.buffer); } - // collect icon data if defined within the label tag - if (styleParameters.styles) { - styleParameters.styles.forEach((style: MapfileStyle )=> { - if (style.symbol) { - this.iconsOnLabels = this.getIconSymbolizerFromMapfileStyle(style); - } - }); - } - if (styleParameters.position) { const anchorpointMap = { cc: 'center', @@ -821,6 +810,15 @@ export class MapfileStyleParser implements StyleParser { mapfileLayerLabelItem = mapfileClass.text ? mapfileClass.text : mapfileLayerLabelItem; mapfileClass.labels.forEach((mapfileLabel) => { mapfileLabel.text = mapfileLabel.text ? mapfileLabel.text : mapfileLayerLabelItem; + + // Set Icons in front of the associated label + const labelIcons = this.getIconsFromMapfileLabel(mapfileLabel); + if (labelIcons) { + labelIcons.forEach(labelIcon => { + symbolizers.push(labelIcon); + }); + } + const symbolizer = Object.assign( this.getTextSymbolizerFromMapfileStyle(mapfileLabel), this.getBaseSymbolizerFromMapfileStyle(mapfileLabel) @@ -832,14 +830,32 @@ export class MapfileStyleParser implements StyleParser { }); } - // check for available icons - if (Object.keys(this.iconsOnLabels).length > 1) { - symbolizers.unshift(this.iconsOnLabels as IconSymbolizer); - } - return symbolizers; } + /** + * Collect icon data if defined within the label tag + * + * @param mapfileLabel + * @returns + */ + getIconsFromMapfileLabel( + mapfileLabel: MapfileLabel + ): IconSymbolizer[] | void { + const labelStyles: IconSymbolizer[] = []; + mapfileLabel?.styles?.forEach((style: MapfileStyle) => { + if (style.symbol) { + labelStyles.push(this.getIconSymbolizerFromMapfileStyle(style)); + } + }); + + if (labelStyles.length) { + return labelStyles; + } else { + return undefined; + } + } + /** * Get the GeoStyler-Style Rule from an Mapfile Object. *