From 748d468e2b3233315a0eb232e5e642da55e398b0 Mon Sep 17 00:00:00 2001 From: Kai Volland Date: Fri, 1 Dec 2023 11:43:43 +0100 Subject: [PATCH 1/3] chore(deps): upgrade ol and geostyler-style --- jest.config.js | 2 +- package-lock.json | 163 ++++++++++++---------------------------------- package.json | 4 +- 3 files changed, 43 insertions(+), 126 deletions(-) diff --git a/jest.config.js b/jest.config.js index e4583676..9722bbef 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,7 +11,7 @@ module.exports = { '^.+\\.(ts|js)$': '/node_modules/babel-jest' }, transformIgnorePatterns: [ - 'node_modules/(?!(ol|color-name|@terrestris/*)/)' + 'node_modules/(?!(ol|color-name|color-space|color-rgba|color-parse|@terrestris/*)/)' ], testRegex: '/src/.*\\.spec.ts$', collectCoverageFrom: [ diff --git a/package-lock.json b/package-lock.json index ab0e9fb4..582008a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "BSD-2-Clause", "dependencies": { "css-font-parser": "^2.0.0", - "geostyler-style": "^7.3.1" + "geostyler-style": "^8.1.0" }, "devDependencies": { "@babel/core": "^7.22.9", @@ -40,7 +40,7 @@ "jest": "^29.6.1", "jest-canvas-mock": "^2.5.2", "jest-environment-jsdom": "^29.6.1", - "ol": "^7.4.0", + "ol": "^8.2.0", "regenerator-runtime": "^0.14.0", "typescript": "^5.1.6", "vite": "4.4.9" @@ -3638,49 +3638,6 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, - "node_modules/@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@mapbox/mapbox-gl-style-spec": { - "version": "13.28.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.28.0.tgz", - "integrity": "sha512-B8xM7Fp1nh5kejfIl4SWeY0gtIeewbuRencqO3cJDrCHZpaPg7uY+V8abuR+esMeuOjRl5cLhVTP40v+1ywxbg==", - "dev": true, - "dependencies": { - "@mapbox/jsonlint-lines-primitives": "~2.0.2", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/unitbezier": "^0.0.0", - "csscolorparser": "~1.0.2", - "json-stringify-pretty-compact": "^2.0.0", - "minimist": "^1.2.6", - "rw": "^1.3.3", - "sort-object": "^0.3.2" - }, - "bin": { - "gl-style-composite": "bin/gl-style-composite.js", - "gl-style-format": "bin/gl-style-format.js", - "gl-style-migrate": "bin/gl-style-migrate.js", - "gl-style-validate": "bin/gl-style-validate.js" - } - }, - "node_modules/@mapbox/point-geometry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", - "dev": true - }, - "node_modules/@mapbox/unitbezier": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5007,9 +4964,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.195", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", - "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==" + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==" }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -6451,6 +6408,31 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-2.0.0.tgz", + "integrity": "sha512-g2Z+QnWsdHLppAbrpcFWo629kLOnOPtpxYV69GCqm92gqSgyXbzlfyN3MXs0412fPBkFmiuS+rXposgBgBa6Kg==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/color-rgba": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-3.0.0.tgz", + "integrity": "sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==", + "dev": true, + "dependencies": { + "color-parse": "^2.0.0", + "color-space": "^2.0.0" + } + }, + "node_modules/color-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-space/-/color-space-2.0.1.tgz", + "integrity": "sha512-nKqUYlo0vZATVOFHY810BSYjmCARrG7e5R3UE3CQlyjJTvv5kSSmPG1kzm/oDyyqjehM+lW1RnEt9It9GNa5JA==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -6776,12 +6758,6 @@ "resolved": "https://registry.npmjs.org/css-font-parser/-/css-font-parser-2.0.0.tgz", "integrity": "sha512-YjgBiAq5rFNXfsPHofaEZwsUbCoSK0avstS76BSqNyVCM7+oiO44wZxbtq6YFSaQafCG0llS/f79oqlsmzaBJg==" }, - "node_modules/csscolorparser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", - "dev": true - }, "node_modules/cssfontparser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz", @@ -8126,15 +8102,15 @@ } }, "node_modules/geostyler-style": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/geostyler-style/-/geostyler-style-7.3.1.tgz", - "integrity": "sha512-9KOXmtRt0O7lhwWfmRORM5l3j3H1uR52NFHlHv1qTb1hgNGZIPhLUrGCaoceUdNkD9+P/Cjiqsea+X+H8h64zw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/geostyler-style/-/geostyler-style-8.1.0.tgz", + "integrity": "sha512-8NgtzRc63bxC+1Vgqj/mMj77GX38CXXXWQ93PeZBdoMTkY9C/H0Anz38OrrlKdUgNVFZ/GJTNYwnX4wdaO5j6A==", "dependencies": { - "@types/lodash": "^4.14.168", + "@types/lodash": "^4.14.201", "lodash": "^4.17.21" }, "engines": { - "node": ">=14.0.0", + "node": ">=16.0.0", "npm": ">=6.0.0" }, "funding": { @@ -10920,12 +10896,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stringify-pretty-compact": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz", - "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==", - "dev": true - }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -11316,12 +11286,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mapbox-to-css-font": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.2.tgz", - "integrity": "sha512-f+NBjJJY4T3dHtlEz1wCG7YFlkODEjFIYlxDdLIDMNpkSksqTt+l/d4rjuwItxuzkuMFvPyrjzV2lxRM4ePcIA==", - "dev": true - }, "node_modules/marked": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", @@ -14645,14 +14609,15 @@ } }, "node_modules/ol": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/ol/-/ol-7.5.2.tgz", - "integrity": "sha512-HJbb3CxXrksM6ct367LsP3N+uh+iBBMdP3DeGGipdV9YAYTP0vTJzqGnoqQ6C2IW4qf8krw9yuyQbc9fjOIaOQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ol/-/ol-8.2.0.tgz", + "integrity": "sha512-/m1ddd7Jsp4Kbg+l7+ozR5aKHAZNQOBAoNZ5pM9Jvh4Etkf0WGkXr9qXd7PnhmwiC1Hnc2Toz9XjCzBBvexfXw==", "dev": true, "dependencies": { + "color-rgba": "^3.0.0", + "color-space": "^2.0.1", "earcut": "^2.2.3", "geotiff": "^2.0.7", - "ol-mapbox-style": "^10.1.0", "pbf": "3.2.1", "rbush": "^3.0.1" }, @@ -14661,17 +14626,6 @@ "url": "https://opencollective.com/openlayers" } }, - "node_modules/ol-mapbox-style": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-10.6.0.tgz", - "integrity": "sha512-s86QhCoyyKVRsYkvPzzdWd///bhYh3onWrBq4lNXnCd9G/hS6AoK023kn4zlDESVlTBDTWLz8vhOistp0M3TXA==", - "dev": true, - "dependencies": { - "@mapbox/mapbox-gl-style-spec": "^13.23.1", - "mapbox-to-css-font": "^2.4.1", - "ol": "^7.3.0" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -15951,12 +15905,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "dev": true - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -16671,37 +16619,6 @@ "node": ">=8" } }, - "node_modules/sort-asc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.1.0.tgz", - "integrity": "sha512-jBgdDd+rQ+HkZF2/OHCmace5dvpos/aWQpcxuyRs9QUbPRnkEJmYVo81PIGpjIdpOcsnJ4rGjStfDHsbn+UVyw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-desc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.1.1.tgz", - "integrity": "sha512-jfZacW5SKOP97BF5rX5kQfJmRVZP5/adDUTY8fCSPvNcXDVpUEe2pr/iKGlcyZzchRJZrswnp68fgk3qBXgkJw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-object": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-0.3.2.tgz", - "integrity": "sha512-aAQiEdqFTTdsvUFxXm3umdo04J7MRljoVGbBlkH7BgNsMvVNAJyGj7C/wV1A8wHWAJj/YikeZbfuCKqhggNWGA==", - "dev": true, - "dependencies": { - "sort-asc": "^0.1.0", - "sort-desc": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 8639cfbe..8a60c8d5 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "css-font-parser": "^2.0.0", - "geostyler-style": "^7.3.1" + "geostyler-style": "^8.1.0" }, "peerDependencies": { "ol": ">=7.4" @@ -71,7 +71,7 @@ "jest": "^29.6.1", "jest-canvas-mock": "^2.5.2", "jest-environment-jsdom": "^29.6.1", - "ol": "^7.4.0", + "ol": "^8.2.0", "regenerator-runtime": "^0.14.0", "typescript": "^5.1.6", "vite": "4.4.9" From 785aee926d9e9fed0e05183fc6ad289ce5cf9845 Mon Sep 17 00:00:00 2001 From: Kai Volland Date: Fri, 1 Dec 2023 11:43:59 +0100 Subject: [PATCH 2/3] feat: add support for Sprite --- data/olStyles/point_icon_sprite.ts | 13 +++ data/styles/point_icon_sprite.ts | 21 ++++ src/OlStyleParser.spec.ts | 154 ++++++++++++++++------------- src/OlStyleParser.ts | 57 +++++++++-- 4 files changed, 170 insertions(+), 75 deletions(-) create mode 100644 data/olStyles/point_icon_sprite.ts create mode 100644 data/styles/point_icon_sprite.ts diff --git a/data/olStyles/point_icon_sprite.ts b/data/olStyles/point_icon_sprite.ts new file mode 100644 index 00000000..53725505 --- /dev/null +++ b/data/olStyles/point_icon_sprite.ts @@ -0,0 +1,13 @@ +import OlStyle from 'ol/style/Style'; +import OlStyleIcon from 'ol/style/Icon'; + +const olIconSpritePoint = new OlStyle({ + image: new OlStyleIcon({ + src: 'https://testurl.com/sprites/mysprite', + offset: [20, 20], + offsetOrigin: 'top-left', + size: [10, 10] + }) +}); + +export default olIconSpritePoint; diff --git a/data/styles/point_icon_sprite.ts b/data/styles/point_icon_sprite.ts new file mode 100644 index 00000000..15ed61e3 --- /dev/null +++ b/data/styles/point_icon_sprite.ts @@ -0,0 +1,21 @@ +import { Style } from 'geostyler-style'; + +const pointSpritePoint: Style = { + name: 'OL Style', + rules: [ + { + name: 'OL Style Rule 0', + symbolizers: [{ + kind: 'Icon', + image: { + source: 'https://testurl.com/sprites/mysprite', + position: [20, 20], + size: [10, 10] + }, + size: 10 + }] + } + ] +}; + +export default pointSpritePoint; diff --git a/src/OlStyleParser.spec.ts b/src/OlStyleParser.spec.ts index 48e525db..d31b0aeb 100644 --- a/src/OlStyleParser.spec.ts +++ b/src/OlStyleParser.spec.ts @@ -15,6 +15,7 @@ import OlStyleParser, { OlParserStyleFct } from './OlStyleParser'; import point_simplepoint from '../data/styles/point_simplepoint'; import point_icon from '../data/styles/point_icon'; +import point_icon_sprite from '../data/styles/point_icon_sprite'; import point_dynamic_icon from '../data/styles/point_dynamic_icon'; import point_simplesquare from '../data/styles/point_simplesquare'; import point_simplestar from '../data/styles/point_simplestar'; @@ -55,6 +56,7 @@ import ol_function_marksymbolizer from '../data/olStyles/function_markSymbolizer import ol_function_nested_fillsymbolizer from '../data/olStyles/function_nested_fillSymbolizer'; import ol_point_simplepoint from '../data/olStyles/point_simplepoint'; import ol_point_icon from '../data/olStyles/point_icon'; +import ol_point_icon_sprite from '../data/olStyles/point_icon_sprite'; import ol_point_simplesquare from '../data/olStyles/point_simplesquare'; import ol_point_simplestar from '../data/olStyles/point_simplestar'; import ol_point_simpletriangle from '../data/olStyles/point_simpletriangle'; @@ -92,10 +94,12 @@ import { FillSymbolizer, TextSymbolizer, IconSymbolizer, - MarkSymbolizer + MarkSymbolizer, + Sprite } from 'geostyler-style'; import OlStyleUtil from './Util/OlStyleUtil'; +import exp from 'constants'; // reverse calculation of resolution for scale (from ol-util MapUtil) function getResolutionForScale (scale, units) { @@ -149,7 +153,11 @@ describe('OlStyleParser implements StyleParser', () => { it('can read an OpenLayers IconSymbolizer', async () => { const { output: geoStylerStyle } = await styleParser.readStyle(ol_point_icon); expect(geoStylerStyle).toBeDefined(); - expect(geoStylerStyle).toEqual(point_icon); + }); + it('can read an OpenLayers IconSymbolizer with a sprite', async () => { + const { output: geoStylerStyle } = await styleParser.readStyle(ol_point_icon_sprite); + expect(geoStylerStyle).toBeDefined(); + expect(geoStylerStyle).toEqual(point_icon_sprite); }); it('can read an OpenLayers MarkSymbolizer as WellKnownName Square', async () => { const { output: geoStylerStyle } = await styleParser.readStyle(ol_point_simplesquare); @@ -434,7 +442,7 @@ describe('OlStyleParser implements StyleParser', () => { expect(olCircle).toBeDefined(); expect(olCircle.getRadius()).toBeCloseTo(expecSymb.radius as number); - expect(olCircle.getFill().getColor()).toEqual(expecSymb.color); + expect(olCircle.getFill()?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers IconSymbolizer', async () => { let { output: olStyle } = await styleParser.writeStyle(point_icon); @@ -451,6 +459,21 @@ describe('OlStyleParser implements StyleParser', () => { expect(olIcon).toBeDefined(); }); + it('can write an OpenLayers IconSymbolizer with a sprite', async () => { + let { output: olStyle } = await styleParser.writeStyle(point_icon_sprite); + olStyle = olStyle as OlStyle; + expect(olStyle).toBeDefined(); + + const expecSymb = point_icon_sprite.rules[0].symbolizers[0] as IconSymbolizer; + const image = expecSymb.image as Sprite; + const olIcon: OlStyleIcon = olStyle.getImage() as OlStyleIcon; + + expect(olIcon).toBeDefined(); + expect(olIcon.getSrc()).toEqual(image.source); + expect(olIcon.getSize()).toEqual(image.size); + // @ts-ignore + expect(olIcon.offset_).toEqual(image.position); + }); it('can write an OpenLayers IconSymbolizer with feature attribute based src', async () => { let { output: olStyle } = await styleParser.writeStyle(point_dynamic_icon); olStyle = olStyle as OlParserStyleFct; @@ -482,9 +505,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olSquare.getAngle()).toBeCloseTo(45 * Math.PI / 180); expect(olSquare.getRotation()).toBeCloseTo((expecSymb.rotate as number) * Math.PI / 180); - const olSquareFill: OlStyleFill = olSquare.getFill(); + const olSquareFill = olSquare.getFill(); expect(olSquareFill).toBeDefined(); - expect(olSquareFill.getColor()).toEqual(expecSymb.color); + expect(olSquareFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape star', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simplestar); @@ -504,9 +527,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olStar.getAngle()).toBeCloseTo(0); expect(olStar.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olStarFill: OlStyleFill = olStar.getFill(); + const olStarFill = olStar.getFill(); expect(olStarFill).toBeDefined(); - expect(olStarFill.getColor()).toEqual(expecSymb.color); + expect(olStarFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape triangle', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simpletriangle); @@ -525,9 +548,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olTriangle.getAngle()).toBeCloseTo(0); expect(olTriangle.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olTriangleFill: OlStyleFill = olTriangle.getFill(); + const olTriangleFill = olTriangle.getFill(); expect(olTriangleFill).toBeDefined(); - expect(olTriangleFill.getColor()).toEqual(expecSymb.color); + expect(olTriangleFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape cross', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simplecross); @@ -547,9 +570,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olCross.getAngle()).toBeCloseTo(0); expect(olCross.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olCrossFill: OlStyleFill = olCross.getFill(); + const olCrossFill = olCross.getFill(); expect(olCrossFill).toBeDefined(); - expect(olCrossFill.getColor()).toEqual(expecSymb.color); + expect(olCrossFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape x', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simplex); @@ -569,9 +592,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olX.getAngle()).toBeCloseTo(45 * Math.PI / 180); expect(olX.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olXFill: OlStyleFill = olX.getFill(); + const olXFill = olX.getFill(); expect(olXFill).toBeDefined(); - expect(olXFill.getColor()).toEqual(expecSymb.color); + expect(olXFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://slash', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simpleslash); @@ -590,9 +613,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olSlash.getAngle()).toBeCloseTo(Math.PI / 4); expect(olSlash.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olSlashFill: OlStyleFill = olSlash.getFill(); + const olSlashFill = olSlash.getFill(); expect(olSlashFill).toBeDefined(); - expect(olSlashFill.getColor()).toEqual(expecSymb.color); + expect(olSlashFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://backslash', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simplebackslash); @@ -611,9 +634,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olBackSlash.getAngle()).toBeCloseTo(2 * Math.PI - (Math.PI / 4)); expect(olBackSlash.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olBackSlashFill: OlStyleFill = olBackSlash.getFill(); + const olBackSlashFill = olBackSlash.getFill(); expect(olBackSlashFill).toBeDefined(); - expect(olBackSlashFill.getColor()).toEqual(expecSymb.color); + expect(olBackSlashFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://vertline', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simplevertline); @@ -632,9 +655,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olVertline.getAngle()).toBeCloseTo(0, 0); expect(olVertline.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olVertlineFill: OlStyleFill = olVertline.getFill(); + const olVertlineFill = olVertline.getFill(); expect(olVertlineFill).toBeDefined(); - expect(olVertlineFill.getColor()).toEqual(expecSymb.color); + expect(olVertlineFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://horline', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simplehorline); @@ -653,9 +676,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olHorline.getAngle()).toBeCloseTo(Math.PI / 2); expect(olHorline.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olHorlineFill: OlStyleFill = olHorline.getFill(); + const olHorlineFill = olHorline.getFill(); expect(olHorlineFill).toBeDefined(); - expect(olHorlineFill.getColor()).toEqual(expecSymb.color); + expect(olHorlineFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://carrow', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simplecarrow); @@ -674,9 +697,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olCarrow.getAngle()).toBeCloseTo(Math.PI / 2); expect(olCarrow.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olCarrowFill: OlStyleFill = olCarrow.getFill(); + const olCarrowFill = olCarrow.getFill(); expect(olCarrowFill).toBeDefined(); - expect(olCarrowFill.getColor()).toEqual(expecSymb.color); + expect(olCarrowFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://oarrow', async() => { let { output: olStyle } = await styleParser.writeStyle(point_simpleoarrow); @@ -695,9 +718,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olOarrow.getAngle()).toBeCloseTo(Math.PI / 2); expect(olOarrow.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olOarrowFill: OlStyleFill = olOarrow.getFill(); + const olOarrowFill = olOarrow.getFill(); expect(olOarrowFill).toBeDefined(); - expect(olOarrowFill.getColor()).toEqual(expecSymb.color); + expect(olOarrowFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://dot', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simpledot); @@ -712,7 +735,7 @@ describe('OlStyleParser implements StyleParser', () => { expect(olDot).toBeDefined(); expect(olDot.getRadius()).toBeCloseTo(expecSymb.radius); - expect(olDot.getFill().getColor()).toEqual(expecSymb.color); + expect(olDot.getFill()?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://plus', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simpleplus); @@ -732,9 +755,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olPlus.getAngle()).toBeCloseTo(0); expect(olPlus.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olPlusFill: OlStyleFill = olPlus.getFill(); + const olPlusFill = olPlus.getFill(); expect(olPlusFill).toBeDefined(); - expect(olPlusFill.getColor()).toEqual(expecSymb.color); + expect(olPlusFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers RegularShape shape://times', async () => { let { output: olStyle } = await styleParser.writeStyle(point_simpletimes); @@ -755,9 +778,9 @@ describe('OlStyleParser implements StyleParser', () => { expect(olTimes.getAngle()).toBeCloseTo(45 * Math.PI / 180); expect(olTimes.getRotation()).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olTimesFill: OlStyleFill = olTimes.getFill(); + const olTimesFill = olTimes.getFill(); expect(olTimesFill).toBeDefined(); - expect(olTimesFill.getColor()).toEqual(expecSymb.color); + expect(olTimesFill?.getColor()).toEqual(expecSymb.color); }); it('can write an OpenLayers Style based on a font glyph (WellKnownName starts with ttf://)', async () => { let { output: olStyle } = await styleParser.writeStyle(point_fontglyph); @@ -765,19 +788,19 @@ describe('OlStyleParser implements StyleParser', () => { expect(olStyle).toBeDefined(); const expecSymb = point_fontglyph.rules[0].symbolizers[0] as MarkSymbolizer; - const olText: OlStyleText = olStyle.getText(); + const olText = olStyle.getText(); expect(olText).toBeDefined(); - expect(olText.getFont()).toBe('Normal 12px \'My Font Name\', geostyler-mark-symbolizer'); - expect(olText.getText()).toBe('|'); + expect(olText?.getFont()).toBe('Normal 12px \'My Font Name\', geostyler-mark-symbolizer'); + expect(olText?.getText()).toBe('|'); - const olTextFill: OlStyleFill = olText.getFill(); + const olTextFill = olText?.getFill(); expect(olTextFill).toBeDefined(); - expect(olTextFill.getColor()).toEqual(expecSymb.color); + expect(olTextFill?.getColor()).toEqual(expecSymb.color); - const olTextStroke: OlStyleStroke = olText.getStroke(); + const olTextStroke = olText?.getStroke(); expect(olTextStroke).toBeDefined(); - expect(olTextStroke.getColor()).toEqual(expecSymb.strokeColor); + expect(olTextStroke?.getColor()).toEqual(expecSymb.strokeColor); }); it('can write an OpenLayers LineSymbolizer', async () => { let { output: olStyle } = await styleParser.writeStyle(line_simpleline); @@ -788,9 +811,9 @@ describe('OlStyleParser implements StyleParser', () => { const olStroke = olStyle.getStroke(); expect(olStroke).toBeDefined(); - expect(olStroke.getColor()).toEqual(expecSymb.color); - expect(olStroke.getWidth()).toBeCloseTo(expecSymb.width as number); - expect(olStroke.getLineDash()).toEqual(expecSymb.dasharray); + expect(olStroke?.getColor()).toEqual(expecSymb.color); + expect(olStroke?.getWidth()).toBeCloseTo(expecSymb.width as number); + expect(olStroke?.getLineDash()).toEqual(expecSymb.dasharray); }); it('can write an OpenLayers PolygonSymbolizer', async () => { let { output: olStyle } = await styleParser.writeStyle(polygon_transparentpolygon); @@ -803,16 +826,16 @@ describe('OlStyleParser implements StyleParser', () => { const expecSymbOutlCol: string = expecSymb.outlineColor as string; const expecSymbOutlOpac: number = expecSymb.outlineOpacity as number; - expect(olStroke.getColor()).toEqual(OlStyleUtil.getRgbaColor(expecSymbOutlCol, expecSymbOutlOpac)); + expect(olStroke?.getColor()).toEqual(OlStyleUtil.getRgbaColor(expecSymbOutlCol, expecSymbOutlOpac)); const olFill = olStyle.getFill(); expect(olFill).toBeDefined(); const expecSymbFillCol: string = expecSymb.color as string; const expecSymbFillOpac: number = expecSymb.fillOpacity as number; - expect(olFill.getColor()).toEqual(OlStyleUtil.getRgbaColor(expecSymbFillCol, expecSymbFillOpac)); + expect(olFill?.getColor()).toEqual(OlStyleUtil.getRgbaColor(expecSymbFillCol, expecSymbFillOpac)); - expect(olStroke.getLineDash()).toEqual(expecSymb.outlineDasharray); + expect(olStroke?.getLineDash()).toEqual(expecSymb.outlineDasharray); }); it('can write an OpenLayers PolygonSymbolizer with MarkSymbolizer as graphicFill', async () => { let { output: olStyle } = await styleParser.writeStyle(polygon_graphicfill_mark); @@ -821,7 +844,7 @@ describe('OlStyleParser implements StyleParser', () => { const olFill = olStyle.getFill(); expect(olFill).toBeDefined(); - expect(olFill.getColor()).toBeInstanceOf(CanvasPattern); + expect(olFill?.getColor()).toBeInstanceOf(CanvasPattern); }); it('can write an OpenLayers TextSymbolizer', async () => { let { output: olStyle } = await styleParser.writeStyle(point_styledlabel); @@ -839,28 +862,28 @@ describe('OlStyleParser implements StyleParser', () => { const olText = style.getText(); expect(olText).toBeDefined(); - const olTextStroke = olText.getStroke(); + const olTextStroke = olText?.getStroke(); expect(olTextStroke).toBeDefined(); - expect(olTextStroke.getColor()).toEqual(expecSymb.haloColor); - expect(olTextStroke.getWidth()).toBeCloseTo(expecSymb.haloWidth as number); + expect(olTextStroke?.getColor()).toEqual(expecSymb.haloColor); + expect(olTextStroke?.getWidth()).toBeCloseTo(expecSymb.haloWidth as number); - const olTextFill = olText.getFill(); + const olTextFill = olText?.getFill(); expect(olTextFill).toBeDefined(); - expect(olTextFill.getColor()).toEqual(expecSymb.color); + expect(olTextFill?.getColor()).toEqual(expecSymb.color); - const olTextFont = olText.getFont(); + const olTextFont = olText?.getFont(); expect(olTextFont).toEqual(OlStyleUtil.getTextFont(expecSymb)); - const olTextContent = olText.getText(); + const olTextContent = olText?.getText(); expect(olTextContent).toEqual(testFeature.get('name')); expecSymb.rotate = expecSymb.rotate as number; - const olTextRotation = olText.getRotation(); + const olTextRotation = olText?.getRotation(); expect(olTextRotation).toBeCloseTo(expecSymb.rotate * Math.PI / 180); - const olTextOffsetX = olText.getOffsetX(); - const olTextOffsetY = olText.getOffsetY(); + const olTextOffsetX = olText?.getOffsetX(); + const olTextOffsetY = olText?.getOffsetY(); const expectedOffsetX = expecSymb.offset ? expecSymb.offset[0] : null; const expectedOffsetY = expecSymb.offset ? expecSymb.offset[1] : null; expect(olTextOffsetX).toBeCloseTo(expectedOffsetX as number); @@ -875,7 +898,6 @@ describe('OlStyleParser implements StyleParser', () => { const styles = olStyle(testFeature, 1); expect(styles).toHaveLength(1); - const expecSymb = point_styledLabel_static.rules[0].symbolizers[0] as TextSymbolizer; const expecText = expecSymb.label; const expecOffset = expecSymb.offset; @@ -889,23 +911,23 @@ describe('OlStyleParser implements StyleParser', () => { const olTextStyle = style.getText(); expect(olTextStyle).toBeDefined(); - const olText = olTextStyle.getText(); + const olText = olTextStyle?.getText(); expect(olText).toBeDefined(); expect(olText).toEqual(expecText); - const olFont = olTextStyle.getFont(); + const olFont = olTextStyle?.getFont(); expect(olFont).toBeDefined(); expect(olFont).toEqual(expecFont); - const olRotation = olTextStyle.getRotation(); + const olRotation = olTextStyle?.getRotation(); expect(olRotation).toBeDefined(); expect(olRotation).toBeCloseTo(expecRotation); - const olOffsetX = olTextStyle.getOffsetX(); + const olOffsetX = olTextStyle?.getOffsetX(); expect(olOffsetX).toBeDefined(); expect(olOffsetX).toBeCloseTo(expecOffset?.[0] as number); - const olOffsetY = olTextStyle.getOffsetY(); + const olOffsetY = olTextStyle?.getOffsetY(); expect(olOffsetY).toBeDefined(); expect(olOffsetY).toBeCloseTo(expecOffset?.[1] as number); }); @@ -943,12 +965,12 @@ describe('OlStyleParser implements StyleParser', () => { const olCircle1 = styles[0].getImage() as OlStyleCircle; expect(olCircle1).toBeDefined(); expect(olCircle1.getRadius()).toBeCloseTo(expecSymb1.radius as number); - expect(olCircle1.getFill().getColor()).toEqual(expecSymb1.color); + expect(olCircle1.getFill()?.getColor()).toEqual(expecSymb1.color); const olCircle2 = styles[1].getImage() as OlStyleCircle; expect(olCircle2).toBeDefined(); expect(olCircle2.getRadius()).toBeCloseTo(expecSymb2.radius as number); - expect(olCircle2.getFill().getColor()).toEqual(expecSymb2.color); + expect(olCircle2.getFill()?.getColor()).toEqual(expecSymb2.color); }); it('transforms labels values based on fields to string ', async () => { // change the field as base for the label text to a numeric one @@ -1016,16 +1038,16 @@ describe('OlStyleParser implements StyleParser', () => { const expecFirst = scaleDenomLineCircle.rules[0].symbolizers[0] as LineSymbolizer; const olStroke = styleFirst.getStroke(); expect(olStroke).toBeDefined(); - expect(olStroke.getColor()).toEqual(expecFirst.color); - expect(olStroke.getWidth()).toBeCloseTo(expecFirst.width as number); - expect(olStroke.getLineDash()).toEqual(expecFirst.dasharray); + expect(olStroke?.getColor()).toEqual(expecFirst.color); + expect(olStroke?.getWidth()).toBeCloseTo(expecFirst.width as number); + expect(olStroke?.getLineDash()).toEqual(expecFirst.dasharray); const styleSecond: OlStyle = styleWithinSecond[0]; const expecSecond = scaleDenomLineCircle.rules[1].symbolizers[0] as MarkSymbolizer; const olCircle: OlStyleCircle = styleSecond.getImage() as OlStyleCircle; expect(olCircle).toBeDefined(); expect(olCircle.getRadius()).toBeCloseTo(expecSecond.radius as number); - expect(olCircle.getFill().getColor()).toEqual(expecSecond.color); + expect(olCircle.getFill()?.getColor()).toEqual(expecSecond.color); }); it('returns styles of all rules that lie within scaleDenominator', async () => { let { output: olStyle } = await styleParser.writeStyle(scaleDenomLineCircleOverlap); diff --git a/src/OlStyleParser.ts b/src/OlStyleParser.ts index d591afa8..d1b7f547 100644 --- a/src/OlStyleParser.ts +++ b/src/OlStyleParser.ts @@ -10,6 +10,7 @@ import { isGeoStylerStringFunction, isIconSymbolizer, isMarkSymbolizer, + isSprite, JoinType, LineSymbolizer, MarkSymbolizer, @@ -305,25 +306,57 @@ export class OlStyleParser implements StyleParser { } as MarkSymbolizer; } else { // icon - const olIconStyle: any = olStyle.getImage(); - const offset = olIconStyle.getDisplacement() as [number, number]; + const olIconStyle = olStyle.getImage() as OlStyleIcon; + const displacement = olIconStyle.getDisplacement() as [number, number]; // initialOptions_ as fallback when image is not yet loaded - const size = olIconStyle.getWidth() ?? olIconStyle.initialOptions_.width; + const image = this.getImageFromIconStyle(olIconStyle); + // this always gets calculated from ol so this might not have been set initially + let size = olIconStyle.getWidth(); + const rotation = olIconStyle.getRotation() / Math.PI * 180; + const opacity = olIconStyle.getOpacity(); const iconSymbolizer: IconSymbolizer = { kind: 'Icon', - image: olIconStyle.getSrc() ? olIconStyle.getSrc() : undefined, - opacity: olIconStyle.getOpacity(), + image, + opacity: opacity < 1 ? opacity : undefined, size, // Rotation in openlayers is radians while we use degree - rotate: olIconStyle.getRotation() / Math.PI * 180, - offset: offset[0] || offset[1] ? offset : undefined + rotate: rotation > 0 ? rotation : undefined, + offset: displacement[0] || displacement[1] ? displacement : undefined }; pointSymbolizer = iconSymbolizer; } return pointSymbolizer; } + /** + * + * @param olIconStyle An ol style Icon representation + * @returns A string or Sprite configuration + */ + getImageFromIconStyle(olIconStyle: OlStyleIcon): IconSymbolizer['image'] { + const size = olIconStyle.getSize(); + if (Array.isArray(size)) { + // TODO: create getters (and setters?) in openlayers + // @ts-ignore + let position = olIconStyle.offset_ as [number, number]; + // @ts-ignore + const offsetOrigin = olIconStyle.offsetOrigin_ as string; + if (offsetOrigin && offsetOrigin !== 'top-left') { + throw new Error(`Offset origin ${offsetOrigin} not supported`); + } + + return { + source: olIconStyle.getSrc()!, + position, + size: size as [number, number] + }; + } else { + return olIconStyle.getSrc() ? olIconStyle.getSrc() : undefined; + } + + } + /** * Get the GeoStyler-Style LineSymbolizer from an OpenLayers Style object. * @@ -396,6 +429,9 @@ export class OlStyleParser implements StyleParser { */ getTextSymbolizerFromOlStyle(olStyle: OlStyle): TextSymbolizer { const olTextStyle = olStyle.getText(); + if (!olTextStyle) { + throw new Error('Could not get text from olStyle.'); + } const olFillStyle = olTextStyle.getFill(); const olStrokeStyle = olTextStyle.getStroke(); const offsetX = olTextStyle.getOffsetX(); @@ -1189,14 +1225,17 @@ export class OlStyleParser implements StyleParser { } const baseProps: OlStyleIconOptions = { - src: symbolizer.image as string, + src: isSprite(symbolizer.image) ? symbolizer.image.source as string : symbolizer.image as string, crossOrigin: 'anonymous', opacity: symbolizer.opacity as number, width: symbolizer.size as number, // Rotation in openlayers is radians while we use degree rotation: (typeof(symbolizer.rotate) === 'number' ? symbolizer.rotate * Math.PI / 180 : undefined) as number, - displacement: symbolizer.offset as [number, number] + displacement: symbolizer.offset as [number, number], + size: isSprite(symbolizer.image) ? symbolizer.image.size as [number, number] : undefined, + offset: isSprite(symbolizer.image) ? symbolizer.image.position as [number, number] : undefined, }; + // check if IconSymbolizer.image contains a placeholder const prefix = '\\{\\{'; const suffix = '\\}\\}'; From ecd9ed450298ac6e65cfee96b1f4dec7548ac79d Mon Sep 17 00:00:00 2001 From: Kai Volland Date: Fri, 1 Dec 2023 14:20:13 +0100 Subject: [PATCH 3/3] fix: adapt rotation check --- src/OlStyleParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OlStyleParser.ts b/src/OlStyleParser.ts index d1b7f547..e67dd79f 100644 --- a/src/OlStyleParser.ts +++ b/src/OlStyleParser.ts @@ -321,7 +321,7 @@ export class OlStyleParser implements StyleParser { opacity: opacity < 1 ? opacity : undefined, size, // Rotation in openlayers is radians while we use degree - rotate: rotation > 0 ? rotation : undefined, + rotate: rotation !== 0 ? rotation : undefined, offset: displacement[0] || displacement[1] ? displacement : undefined }; pointSymbolizer = iconSymbolizer;