diff --git a/data/olStyles/text_placement_line.ts b/data/olStyles/text_placement_line.ts new file mode 100644 index 00000000..7d3812c0 --- /dev/null +++ b/data/olStyles/text_placement_line.ts @@ -0,0 +1,14 @@ +import OlStyleText from 'ol/style/Text'; +import OlStyle from 'ol/style/Style'; +import OlStyleStroke from 'ol/style/Stroke'; +const olTextPlacementStyle = new OlStyle({ + text: new OlStyleText({ + text: 'name', + placement:'line', + stroke: new OlStyleStroke({ + width: 5 + }) + }) +}); + +export default olTextPlacementStyle; diff --git a/data/olStyles/text_placement_point.ts b/data/olStyles/text_placement_point.ts new file mode 100644 index 00000000..fae4b711 --- /dev/null +++ b/data/olStyles/text_placement_point.ts @@ -0,0 +1,14 @@ +import OlStyleText from 'ol/style/Text'; +import OlStyle from 'ol/style/Style'; +import OlStyleStroke from 'ol/style/Stroke'; +const olTextPlacementStyle = new OlStyle({ + text: new OlStyleText({ + text: 'name', + placement:'point', + stroke: new OlStyleStroke({ + width: 5 + }) + }) +}); + +export default olTextPlacementStyle; diff --git a/data/styles/point_styledLabel_static.ts b/data/styles/point_styledLabel_static.ts index d70a5d9f..57f81681 100644 --- a/data/styles/point_styledLabel_static.ts +++ b/data/styles/point_styledLabel_static.ts @@ -7,6 +7,9 @@ const pointStyledLabel: Style = { name: 'OL Style Rule 0', symbolizers: [{ kind: 'Text', + allowOverlap: undefined, + fontStyle: undefined, + fontWeight: undefined, color: '#000000', label: 'name', font: ['Arial'], @@ -14,7 +17,8 @@ const pointStyledLabel: Style = { offset: [0, 5], haloColor: '#000000', haloWidth: 5, - rotate: 45 + rotate: 45, + placement: 'point' }] } ] diff --git a/data/styles/text_palcement_line_center.ts b/data/styles/text_palcement_line_center.ts new file mode 100644 index 00000000..0b3509c8 --- /dev/null +++ b/data/styles/text_palcement_line_center.ts @@ -0,0 +1,27 @@ +import { Style } from 'geostyler-style'; + +const textStyle: Style = { + name: 'OL Style', + rules: [ + { + name: 'OL Style Rule 0', + symbolizers: [{ + kind: 'Text', + placement:'line-center', + allowOverlap: undefined, + fontStyle: undefined, + fontWeight: undefined, + color: '#333', + label: 'name', + font: undefined, + size: undefined, + offset: [0,0], + haloColor: undefined, + haloWidth: 5, + rotate: undefined + }] + } + ] +}; + +export default textStyle; diff --git a/data/styles/text_placement_line.ts b/data/styles/text_placement_line.ts new file mode 100644 index 00000000..2cf7dca7 --- /dev/null +++ b/data/styles/text_placement_line.ts @@ -0,0 +1,27 @@ +import { Style } from 'geostyler-style'; + +const textStyle: Style = { + name: 'OL Style', + rules: [ + { + name: 'OL Style Rule 0', + symbolizers: [{ + kind: 'Text', + placement:'line', + allowOverlap: undefined, + fontStyle: undefined, + fontWeight: undefined, + color: '#333', + label: 'name', + font: undefined, + size: undefined, + offset: [0,0], + haloColor: undefined, + haloWidth: 5, + rotate: undefined + }] + } + ] +}; + +export default textStyle; diff --git a/data/styles/text_placement_point.ts b/data/styles/text_placement_point.ts new file mode 100644 index 00000000..c96b39ca --- /dev/null +++ b/data/styles/text_placement_point.ts @@ -0,0 +1,27 @@ +import { Style } from 'geostyler-style'; + +const textStyle: Style = { + name: 'OL Style', + rules: [ + { + name: 'OL Style Rule 0', + symbolizers: [{ + kind: 'Text', + placement:'point', + allowOverlap: undefined, + fontStyle: undefined, + fontWeight: undefined, + color: '#333', + label: 'name', + font: undefined, + size: undefined, + offset: [0,0], + haloColor: undefined, + haloWidth: 5, + rotate: undefined + }] + } + ] +}; + +export default textStyle; diff --git a/src/OlStyleParser.spec.ts b/src/OlStyleParser.spec.ts index d31b0aeb..c32633a4 100644 --- a/src/OlStyleParser.spec.ts +++ b/src/OlStyleParser.spec.ts @@ -51,6 +51,9 @@ import point_fontglyph from '../data/styles/point_fontglyph'; import unsupported_properties from '../data/styles/unsupported_properties'; import function_boolean from '../data/styles/function_boolean'; import function_case from '../data/styles/function_case'; +import text_placement_point from '../data/styles/text_placement_point'; +import text_placement_line from '../data/styles/text_placement_line'; +import text_placement_line_center from '../data/styles/text_palcement_line_center'; import ol_function_marksymbolizer from '../data/olStyles/function_markSymbolizer'; import ol_function_nested_fillsymbolizer from '../data/olStyles/function_nested_fillSymbolizer'; @@ -78,6 +81,8 @@ import ol_multi_simplefillSimpleline from '../data/olStyles/multi_simplefillSimp import ol_point_styledLabel_static from '../data/olStyles/point_styledLabel_static'; import ol_point_fontglyph from '../data/olStyles/point_fontglyph'; import ol_unsupported_properties from '../data/olStyles/unsupported_properties'; +import ol_text_placement_point from '../data/olStyles/text_placement_point'; +import ol_text_placement_line from '../data/olStyles/text_placement_line'; import { olBoolean1 as ol_function_boolean_fillsymbolizer1, olBoolean2 as ol_function_boolean_fillsymbolizer2 @@ -257,6 +262,16 @@ describe('OlStyleParser implements StyleParser', () => { expect(geoStylerStyle).toBeDefined(); expect(geoStylerStyle).toEqual(point_styledLabel_static); }); + it('can read an OpenLayers TextSymbolizer with placement point', async () => { + const { output: geoStylerStyle } = await styleParser.readStyle(ol_text_placement_point); + expect(geoStylerStyle).toBeDefined(); + expect(geoStylerStyle).toEqual(text_placement_point); + }); + it('can read an OpenLayers TextSymbolizer with placement line', async () => { + const { output: geoStylerStyle } = await styleParser.readStyle(ol_text_placement_line); + expect(geoStylerStyle).toBeDefined(); + expect(geoStylerStyle).toEqual(text_placement_line); + }); // it('can read an OpenLayers style with a filter', () => { // expect.assertions(2); // const sld = fs.readFileSync( './data/slds/point_simplepoint_filter.sld', 'utf8'); @@ -1148,6 +1163,47 @@ describe('OlStyleParser implements StyleParser', () => { expect(geoStylerStyle).toBeDefined(); expect(geoStylerStyle).toEqual(ol_polygon_simple); }); + it('can write a TextSymbolizer with placement point', async () => { + let { output: olStyle } = await styleParser.writeStyle(text_placement_point); + olStyle = olStyle as OlParserStyleFct; + expect(olStyle).toBeDefined(); + + const testFeature = new OlFeature({name: 'GeoStyler'}); + const styles = olStyle(testFeature, 1); + expect(styles).toHaveLength(1); + + const style: OlStyle = styles[0]; + const olPlacement = style.getText().getPlacement(); + expect(olPlacement).toEqual('point'); + }); + + it('can write a TextSymbolizer with placement line', async () => { + let { output: olStyle } = await styleParser.writeStyle(text_placement_line); + olStyle = olStyle as OlParserStyleFct; + expect(olStyle).toBeDefined(); + + const testFeature = new OlFeature({name: 'GeoStyler'}); + const styles = olStyle(testFeature, 1); + expect(styles).toHaveLength(1); + + const style: OlStyle = styles[0]; + const olPlacement = style.getText().getPlacement(); + expect(olPlacement).toEqual('line'); + }); + + it('can write a TextSymbolizer with placement line-center to line ', async () => { + let { output: olStyle } = await styleParser.writeStyle(text_placement_line_center); + olStyle = olStyle as OlParserStyleFct; + expect(olStyle).toBeDefined(); + + const testFeature = new OlFeature({name: 'GeoStyler'}); + const styles = olStyle(testFeature, 1); + expect(styles).toHaveLength(1); + + const style: OlStyle = styles[0]; + const olPlacement = style.getText().getPlacement(); + expect(olPlacement).toEqual('line'); + }); it('can write a Marksymbolizer with GeoStylerFunction', async () => { let { output: geoStylerStyle } = await styleParser.writeStyle(function_marksymbolizer); diff --git a/src/OlStyleParser.ts b/src/OlStyleParser.ts index e67dd79f..b9cd557f 100644 --- a/src/OlStyleParser.ts +++ b/src/OlStyleParser.ts @@ -114,7 +114,13 @@ export class OlStyleParser implements StyleParser { graphicStroke: 'none', perpendicularOffset: 'none' }, - RasterSymbolizer: 'none' + RasterSymbolizer: 'none', + TextSymbolizer: { + placement: { + support:'partial', + info: 'point and line supported. line-center will be mapped to line.' + } + } }, Function: { double2bool: { @@ -439,13 +445,13 @@ export class OlStyleParser implements StyleParser { const font = olTextStyle.getFont(); const rotation = olTextStyle.getRotation(); const allowOverlap = olTextStyle.getOverflow() ? olTextStyle.getOverflow() : undefined; + const placement = olTextStyle.getPlacement(); const text = olTextStyle.getText(); const label = Array.isArray(text) ? text[0] : text; let fontSize: number = Infinity; let fontFamily: string[]|undefined = undefined; let fontWeight: 'normal' | 'bold' | undefined = undefined; let fontStyle: 'normal' | 'italic' | 'oblique' | undefined = undefined; - if (font) { const fontObj = parseFont(font); if (fontObj['font-weight']) { @@ -466,6 +472,7 @@ export class OlStyleParser implements StyleParser { return { kind: 'Text', label, + placement, allowOverlap, color: olFillStyle ? OlStyleUtil.getHexColor(olFillStyle.getColor() as string) : undefined, size: isFinite(fontSize) ? fontSize : undefined, @@ -1437,8 +1444,18 @@ export class OlStyleParser implements StyleParser { (symbolizer as any)[key] = OlStyleUtil.evaluateFunction((symbolizer as any)[key], feat); } } - const color = symbolizer.color as string; + let placement = symbolizer.placement; + if (!placement) { + // When setting placement it must not be undefined. + // So we set it to the OL default value. + placement = 'point'; + } + if (placement === 'line-center') { + // line-center not supported by OL. + // So we use the closest supported value. + placement = 'line'; + } const opacity = symbolizer.opacity as number; const fColor = color && Number.isFinite(opacity) ? OlStyleUtil.getRgbaColor(color, opacity) @@ -1449,7 +1466,6 @@ export class OlStyleParser implements StyleParser { const sColor = haloColor && Number.isFinite(opacity) ? OlStyleUtil.getRgbaColor(haloColor, opacity) : haloColor; - const baseProps: OlStyleTextOptions = { font: OlStyleUtil.getTextFont(symbolizer), fill: new this.OlStyleFillConstructor({ @@ -1462,7 +1478,8 @@ export class OlStyleParser implements StyleParser { overflow: symbolizer.allowOverlap as boolean, offsetX: (symbolizer.offset ? symbolizer.offset[0] : 0) as number, offsetY: (symbolizer.offset ? symbolizer.offset[1] : 0) as number, - rotation: typeof(symbolizer.rotate) === 'number' ? symbolizer.rotate * Math.PI / 180 : undefined + rotation: typeof(symbolizer.rotate) === 'number' ? symbolizer.rotate * Math.PI / 180 : undefined, + placement: placement as 'line' | 'point' // TODO check why props match // textAlign: symbolizer.pitchAlignment, // textBaseline: symbolizer.anchor diff --git a/src/Util/OlStyleUtil.ts b/src/Util/OlStyleUtil.ts index a64d470f..1257c73c 100644 --- a/src/Util/OlStyleUtil.ts +++ b/src/Util/OlStyleUtil.ts @@ -176,6 +176,9 @@ class OlStyleUtil { * @param font The text font to analyze */ public static getIsMarkSymbolizerFont(font: string) { + if (!font) { + return false; + } const search = DUMMY_MARK_SYMBOLIZER_FONT; return font.substring(font.length - search.length, font.length) === search; }