From f2e5b0a7e3fc512579fc16df81242131d6c0e6e9 Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Fri, 7 May 2021 08:11:42 +0200 Subject: [PATCH 1/8] 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/8] 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/8] 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/8] 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. * From 91d316432d78cc10a5940cb0f769de8dda070208 Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Fri, 7 May 2021 11:56:34 +0200 Subject: [PATCH 5/8] Fixes MapfileStyleParser tests --- src/MapfileStyleParser.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MapfileStyleParser.spec.ts b/src/MapfileStyleParser.spec.ts index 30e7345..8d87922 100644 --- a/src/MapfileStyleParser.spec.ts +++ b/src/MapfileStyleParser.spec.ts @@ -203,7 +203,7 @@ 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'); From 8526ce8447e6c0b7fdd6fc134e1dfde729536c66 Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Fri, 7 May 2021 14:37:51 +0200 Subject: [PATCH 6/8] Addresses review comments --- src/MapfileStyleParser.ts | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/MapfileStyleParser.ts b/src/MapfileStyleParser.ts index efddbcb..9d2980f 100644 --- a/src/MapfileStyleParser.ts +++ b/src/MapfileStyleParser.ts @@ -421,7 +421,7 @@ export class MapfileStyleParser implements StyleParser { getIconSymbolizerFromMapfileStyle(mapfileStyle: MapfileStyle): IconSymbolizer { const iconSymbolizer: IconSymbolizer = { kind: 'Icon', - image: mapfileStyle.symbol.image || mapfileStyle.symbol, + image: mapfileStyle.symbol.image, } as IconSymbolizer; if (mapfileStyle.size) { @@ -812,12 +812,10 @@ export class MapfileStyleParser implements StyleParser { 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 labelIcons = this.getIconsFromMapfileLabel(mapfileLabel); + labelIcons?.forEach(labelIcon => { + symbolizers.push(labelIcon); + }); const symbolizer = Object.assign( this.getTextSymbolizerFromMapfileStyle(mapfileLabel), @@ -836,24 +834,19 @@ export class MapfileStyleParser implements StyleParser { /** * Collect icon data if defined within the label tag * - * @param mapfileLabel - * @returns + * @param {MapfileLabel} mapfileLabel Mapfile label data + * @return {IconSymbolizer[]} The IconSymbolizer */ - getIconsFromMapfileLabel( - mapfileLabel: MapfileLabel - ): IconSymbolizer[] | void { + getIconsFromMapfileLabel(mapfileLabel: MapfileLabel): IconSymbolizer[] { const labelStyles: IconSymbolizer[] = []; mapfileLabel?.styles?.forEach((style: MapfileStyle) => { if (style.symbol) { - labelStyles.push(this.getIconSymbolizerFromMapfileStyle(style)); + labelStyles.push(this.getIconSymbolizerFromMapfileStyle( + {symbol: {image: style.symbol}} as unknown as MapfileStyle + )); } }); - - if (labelStyles.length) { - return labelStyles; - } else { - return undefined; - } + return labelStyles; } /** From 86f8ce6d5136338f85691cd02bbf1e251385699f Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Mon, 10 May 2021 14:10:56 +0200 Subject: [PATCH 7/8] Rename labelStyles to iconStyles --- src/MapfileStyleParser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MapfileStyleParser.ts b/src/MapfileStyleParser.ts index 9d2980f..7a067f2 100644 --- a/src/MapfileStyleParser.ts +++ b/src/MapfileStyleParser.ts @@ -838,15 +838,15 @@ export class MapfileStyleParser implements StyleParser { * @return {IconSymbolizer[]} The IconSymbolizer */ getIconsFromMapfileLabel(mapfileLabel: MapfileLabel): IconSymbolizer[] { - const labelStyles: IconSymbolizer[] = []; + const iconStyles: IconSymbolizer[] = []; mapfileLabel?.styles?.forEach((style: MapfileStyle) => { if (style.symbol) { - labelStyles.push(this.getIconSymbolizerFromMapfileStyle( + iconStyles.push(this.getIconSymbolizerFromMapfileStyle( {symbol: {image: style.symbol}} as unknown as MapfileStyle )); } }); - return labelStyles; + return iconStyles; } /** From 0b4449e26f4a8c7b80f493c1434dd6c7f417a961 Mon Sep 17 00:00:00 2001 From: Michael Holthausen Date: Mon, 10 May 2021 14:13:06 +0200 Subject: [PATCH 8/8] Addresses review comment --- src/MapfileStyleParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MapfileStyleParser.ts b/src/MapfileStyleParser.ts index 7a067f2..5e75dc2 100644 --- a/src/MapfileStyleParser.ts +++ b/src/MapfileStyleParser.ts @@ -813,7 +813,7 @@ export class MapfileStyleParser implements StyleParser { // Set Icons in front of the associated label const labelIcons = this.getIconsFromMapfileLabel(mapfileLabel); - labelIcons?.forEach(labelIcon => { + labelIcons.forEach(labelIcon => { symbolizers.push(labelIcon); });