diff --git a/CHANGES.md b/CHANGES.md index d91b79a..27c1275 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,15 @@ # @geoblocks/geoblocks changes +## 0.2.15 + +- Use ol getFontParameters to parse font. +- Fallback to fill color if none is specified on circle style. + +Breaking changes: + +- Pass feature object to allow informed customization. + + ## 0.2.14 - Fix (invert) text Y axis offset. diff --git a/package-lock.json b/package-lock.json index c1d220a..4019b23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,26 +1,26 @@ { "name": "@geoblocks/mapfishprint", - "version": "0.2.14", + "version": "0.2.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@geoblocks/mapfishprint", - "version": "0.2.14", + "version": "0.2.15", "license": "BSD-3-Clause", "devDependencies": { "@geoblocks/print": "0.7.8", "@geoblocks/recast-utils": "0.1.0", "@types/geojson": "7946.0.14", - "@typescript-eslint/eslint-plugin": "7.7.1", + "@typescript-eslint/eslint-plugin": "^7.13.0", "color-name": "2.0.0", "color-parse": "2.0.2", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.1.3", "gh-pages": "6.1.1", - "ol": "9.0.0", - "prettier": "3.2.5", + "ol": "^9.2.4", + "prettier": "^3.3.2", "typedoc": "0.25.13", "typescript": "5.4.5" }, @@ -220,34 +220,20 @@ "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", "dev": true }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", - "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", + "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/type-utils": "7.13.0", + "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -268,13 +254,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", - "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -285,9 +271,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -298,12 +284,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/types": "7.13.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -362,13 +348,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", - "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", + "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/utils": "7.13.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -389,9 +375,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -402,13 +388,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", - "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -430,12 +416,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/types": "7.13.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -540,18 +526,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", - "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", + "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -565,13 +548,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", - "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -582,9 +565,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -595,13 +578,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", - "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -623,12 +606,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/types": "7.13.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2145,9 +2128,9 @@ } }, "node_modules/ol": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ol/-/ol-9.0.0.tgz", - "integrity": "sha512-+nYHZYbHrRUTDJ8ryxXPdDoAiaT6Zea02cocmGqsJXs4Oac1fYC9EbTIU2Y7803QcmG3u2MR88RxbksBvK+ZfQ==", + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/ol/-/ol-9.2.4.tgz", + "integrity": "sha512-bsbu4ObaAlbELMIZWnYEvX4Z9jO+OyCBshtODhDKmqYTPEfnKOX3RieCr97tpJkqWTZvyV4tS9UQDvHoCdxS+A==", "dev": true, "dependencies": { "color-rgba": "^3.0.0", @@ -2416,9 +2399,9 @@ } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" diff --git a/package.json b/package.json index a22df38..5ca9263 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@geoblocks/mapfishprint", - "version": "0.2.14", + "version": "0.2.15", "publishConfig": { "access": "public" }, @@ -37,15 +37,15 @@ "@geoblocks/print": "0.7.8", "@geoblocks/recast-utils": "0.1.0", "@types/geojson": "7946.0.14", - "@typescript-eslint/eslint-plugin": "7.7.1", + "@typescript-eslint/eslint-plugin": "^7.13.0", "color-name": "2.0.0", "color-parse": "2.0.2", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.1.3", "gh-pages": "6.1.1", - "ol": "9.0.0", - "prettier": "3.2.5", + "ol": "^9.2.4", + "prettier": "^3.3.2", "typedoc": "0.25.13", "typescript": "5.4.5" } diff --git a/src/BaseCustomizer.ts b/src/BaseCustomizer.ts index 6deece5..03c956c 100644 --- a/src/BaseCustomizer.ts +++ b/src/BaseCustomizer.ts @@ -67,7 +67,7 @@ export default class BaseCustomizer { * @param symbolizer * @param stroke */ - line(layerState: State, symbolizer: MFPSymbolizerLine, stroke: Stroke) {} + line(layerState: State, geojsonFeature: GeoJSONFeature, symbolizer: MFPSymbolizerLine, stroke: Stroke) {} /** * Can be used to manipulate the image symbolizers @@ -75,7 +75,7 @@ export default class BaseCustomizer { * @param symbolizer * @param image */ - point(layerState: State, symbolizer: MFPSymbolizerPoint, image: Image) {} + point(layerState: State, geojsonFeature: GeoJSONFeature, symbolizer: MFPSymbolizerPoint, image: Image) {} /** * Can be used to manipulate the text symbolizers @@ -83,7 +83,7 @@ export default class BaseCustomizer { * @param symbolizer * @param text */ - text(layerState: State, symbolizer: MFPSymbolizerText, text: Text) {} + text(layerState: State, geojsonFeature: GeoJSONFeature, symbolizer: MFPSymbolizerText, text: Text) {} /** * Can be used to manipulate a converted WMTS layer diff --git a/src/MFPEncoder.ts b/src/MFPEncoder.ts index 752009f..2eecc38 100644 --- a/src/MFPEncoder.ts +++ b/src/MFPEncoder.ts @@ -21,9 +21,9 @@ import VectorTileLayer from 'ol/layer/VectorTile.js'; import VectorLayer from 'ol/layer/Vector.js'; import VectorEncoder from './VectorEncoder'; import {toContext} from 'ol/render.js'; -import VectorSource from 'ol/source/Vector.js'; import LayerGroup from 'ol/layer/Group'; import VectorContext from 'ol/render/VectorContext'; +import type {Feature} from 'ol'; export interface EncodeMapOptions { map: Map; @@ -307,7 +307,7 @@ export default class MFPBaseEncoder { printResolution: number, customizer: BaseCustomizer, ): Promise { - const layer = layerState.layer as VectorTileLayer; + const layer = layerState.layer as VectorTileLayer; const {MVTEncoder} = await import('@geoblocks/print'); const encoder = new MVTEncoder(); const printExtent = customizer.getPrintExtent(); @@ -351,7 +351,7 @@ export default class MFPBaseEncoder { customizer: BaseCustomizer, additionalDraw: (cir: VectorContext, geometry: Geometry) => void, ): Promise { - const layer = layerState.layer as VectorLayer; + const layer = layerState.layer as VectorLayer; const printExtent = customizer.getPrintExtent(); const width = getExtentWidth(printExtent) / resolution; const height = getExtentHeight(printExtent) / resolution; diff --git a/src/VectorEncoder.ts b/src/VectorEncoder.ts index eefed95..f753311 100644 --- a/src/VectorEncoder.ts +++ b/src/VectorEncoder.ts @@ -1,7 +1,7 @@ import {rgbArrayToHex} from './utils'; import {GeoJSON as olFormatGeoJSON} from 'ol/format.js'; -import type {Fill, Icon, Image, Stroke, Style, Text} from 'ol/style.js'; -import {Circle as olStyleCircle, Icon as olStyleIcon} from 'ol/style.js'; +import type {Fill, Icon, Image, Style, Text} from 'ol/style.js'; +import {Circle as olStyleCircle, Icon as olStyleIcon, Stroke} from 'ol/style.js'; import Feature from 'ol/Feature.js'; import type Circle from 'ol/geom/Circle.js'; import {getUid} from 'ol'; @@ -25,6 +25,9 @@ import type {Feature as GeoJSONFeature, FeatureCollection as GeoJSONFeatureColle import {fromCircle} from 'ol/geom/Polygon.js'; import {Constants} from './constants'; +import {getFontParameters} from 'ol/css.js'; +import {type ColorLike} from 'ol/colorlike'; + /** Represents the different types of printing styles. */ export const PrintStyleType = { LINE_STRING: 'LineString', @@ -32,21 +35,22 @@ export const PrintStyleType = { POLYGON: 'Polygon', } as const; -/** Supported geometry types */ -type GeometryType = 'LineString' | 'Point' | 'Polygon' | 'MultiLineString' | 'MultiPolygon'; - /** * Link between supported geometry and print style types. * Circles will be handled as polygon. * */ -export const PrintStyleTypes_ = { +export const PrintStyleTypes = Object.freeze({ LineString: PrintStyleType.LINE_STRING, Point: PrintStyleType.POINT, Polygon: PrintStyleType.POLYGON, MultiLineString: PrintStyleType.LINE_STRING, MultiPoint: PrintStyleType.POINT, MultiPolygon: PrintStyleType.POLYGON, -} as const; +}); + +function isSupportedGeometryType(geometryType: string): geometryType is keyof typeof PrintStyleTypes { + return geometryType in PrintStyleTypes; +} /** Key prefix to feature style prop */ const FEATURE_STYLE_PROP = '_mfp_style'; @@ -81,7 +85,7 @@ const styleKey = (styles: string | string[]): string => { */ export default class VectorEncoder { private layerState_: State; - private layer_: VectorLayer; + private layer_: VectorLayer; private customizer_: BaseCustomizer; private geojsonFormat = new olFormatGeoJSON(); private deepIds_: Map = new Map(); @@ -89,7 +93,7 @@ export default class VectorEncoder { constructor(layerState: State, customizer: BaseCustomizer) { this.layerState_ = layerState; - this.layer_ = this.layerState_.layer as VectorLayer; + this.layer_ = this.layerState_.layer as VectorLayer; this.customizer_ = customizer; } @@ -201,8 +205,7 @@ export default class VectorEncoder { } } - const geometryType = geometry.getType(); - this.addVectorStyle(mapfishStyleObject, geojsonFeature, geometryType, style); + this.addVectorStyle(mapfishStyleObject, geojsonFeature, style); }); } @@ -236,12 +239,7 @@ export default class VectorEncoder { /** * Adds a vector style to the mapfishStyleObject based on the given parameters. */ - addVectorStyle( - mapfishStyleObject: MFPVectorStyle, - geojsonFeature: GeoJSONFeature, - geometryType: GeometryType, - style: Style, - ) { + addVectorStyle(mapfishStyleObject: MFPVectorStyle, geojsonFeature: GeoJSONFeature, style: Style) { const styleId = this.getDeepStyleUid(style); const key = styleKey(styleId); let hasSymbolizer; @@ -249,7 +247,7 @@ export default class VectorEncoder { // do nothing if we already have a style object for this CQL rule hasSymbolizer = true; } else { - const styleObject = this.encodeVectorStyle(geometryType, style); + const styleObject = this.encodeVectorStyle(geojsonFeature, style); hasSymbolizer = styleObject && styleObject.symbolizers.length !== 0; if (hasSymbolizer) { // @ts-ignore @@ -286,12 +284,13 @@ export default class VectorEncoder { * Encodes the vector style based on the geometry type and style. * @returns The encoded vector style, or null if the geometry type is unsupported. */ - encodeVectorStyle(geometryType: GeometryType, style: Style): MFPSymbolizers | null { - if (!(geometryType in PrintStyleTypes_)) { + encodeVectorStyle(geojsonFeature: GeoJSONFeature, style: Style): MFPSymbolizers | null { + const geometryType = geojsonFeature.geometry.type; + if (!isSupportedGeometryType(geometryType)) { console.warn('Unsupported geometry type: ', geometryType); return null; } - const styleType = PrintStyleTypes_[geometryType]; + const styleType = PrintStyleTypes[geometryType]; const styleObject = { symbolizers: [], } as MFPSymbolizers; @@ -301,19 +300,19 @@ export default class VectorEncoder { const textStyle = style.getText(); if (styleType === PrintStyleType.POLYGON) { if (fillStyle !== null) { - this.encodeVectorStylePolygon(styleObject.symbolizers, fillStyle, strokeStyle); + this.encodeVectorStylePolygon(geojsonFeature, styleObject.symbolizers, fillStyle, strokeStyle); } } else if (styleType === PrintStyleType.LINE_STRING) { if (strokeStyle !== null) { - this.encodeVectorStyleLine(styleObject.symbolizers, strokeStyle); + this.encodeVectorStyleLine(geojsonFeature, styleObject.symbolizers, strokeStyle); } } else if (styleType === PrintStyleType.POINT) { if (imageStyle !== null) { - this.encodeVectorStylePoint(styleObject.symbolizers, imageStyle); + this.encodeVectorStylePoint(geojsonFeature, styleObject.symbolizers, imageStyle); } } if (textStyle !== null) { - this.encodeVectorStyleText(styleObject.symbolizers, textStyle); + this.encodeVectorStyleText(geojsonFeature, styleObject.symbolizers, textStyle); } return styleObject; } @@ -322,6 +321,7 @@ export default class VectorEncoder { * Encodes the vector style fill for a symbolizer. */ protected encodeVectorStyleFill( + geojsonFeature: GeoJSONFeature, symbolizer: MFPSymbolizerPoint | MFPSymbolizerPolygon | MFPSymbolizerText, fillStyle: Fill, ) { @@ -340,27 +340,35 @@ export default class VectorEncoder { /** * Encodes the vector style for a line symbolizer, using the given stroke style. */ - protected encodeVectorStyleLine(symbolizers: MFPSymbolizer[], strokeStyle: Stroke) { + protected encodeVectorStyleLine( + geojsonFeature: GeoJSONFeature, + symbolizers: MFPSymbolizer[], + strokeStyle: Stroke, + ) { const symbolizer = { type: 'line', } as MFPSymbolizerLine; - this.encodeVectorStyleStroke(symbolizer, strokeStyle); - this.customizer_.line(this.layerState_, symbolizer, strokeStyle); + this.encodeVectorStyleStroke(geojsonFeature, symbolizer, strokeStyle); + this.customizer_.line(this.layerState_, geojsonFeature, symbolizer, strokeStyle); symbolizers.push(symbolizer); } /** * Encodes a vector style point. */ - protected encodeVectorStylePoint(symbolizers: MFPSymbolizer[], imageStyle: Image) { + protected encodeVectorStylePoint( + geojsonFeature: GeoJSONFeature, + symbolizers: MFPSymbolizer[], + imageStyle: Image, + ) { let symbolizer: MFPSymbolizerPoint | undefined; if (imageStyle instanceof olStyleCircle) { - symbolizer = this.encodeVectorStylePointStyleCircle(imageStyle); + symbolizer = this.encodeVectorStylePointStyleCircle(geojsonFeature, imageStyle); } else if (imageStyle instanceof olStyleIcon) { - symbolizer = this.encodeVectorStylePointStyleIcon(imageStyle); + symbolizer = this.encodeVectorStylePointStyleIcon(geojsonFeature, imageStyle); } if (symbolizer) { - this.customizer_.point(this.layerState_, symbolizer, imageStyle); + this.customizer_.point(this.layerState_, geojsonFeature, symbolizer, imageStyle); symbolizers.push(symbolizer); } } @@ -369,7 +377,10 @@ export default class VectorEncoder { * Encodes the vector style point style circle. * @returns The encoded symbolizer point. */ - protected encodeVectorStylePointStyleCircle(imageStyle: olStyleCircle): MFPSymbolizerPoint { + protected encodeVectorStylePointStyleCircle( + geojsonFeature: GeoJSONFeature, + imageStyle: olStyleCircle, + ): MFPSymbolizerPoint { const symbolizer = { type: 'point', } as MFPSymbolizerPoint; @@ -383,12 +394,20 @@ export default class VectorEncoder { } } const fillStyle = imageStyle.getFill(); + let strokeStyle = imageStyle.getStroke(); + if (fillStyle !== null) { - this.encodeVectorStyleFill(symbolizer, fillStyle); + this.encodeVectorStyleFill(geojsonFeature, symbolizer, fillStyle); + if (!strokeStyle) { + // Without a stroke style a black border would appear around the circle + strokeStyle = new Stroke({ + color: fillStyle.getColor() as ColorLike, + }); + } } - const strokeStyle = imageStyle.getStroke(); + if (strokeStyle !== null) { - this.encodeVectorStyleStroke(symbolizer, strokeStyle); + this.encodeVectorStyleStroke(geojsonFeature, symbolizer, strokeStyle); } return symbolizer; } @@ -397,7 +416,10 @@ export default class VectorEncoder { * Encodes a Vector Style point style icon. * @returns The encoded symbolizer point style or undefined if imageStyle src is undefined. */ - protected encodeVectorStylePointStyleIcon(imageStyle: olStyleIcon): MFPSymbolizerPoint | undefined { + protected encodeVectorStylePointStyleIcon( + geojsonFeature: GeoJSONFeature, + imageStyle: olStyleIcon, + ): MFPSymbolizerPoint | undefined { const src = imageStyle.getSrc(); if (src === undefined) { return undefined; @@ -466,13 +488,18 @@ export default class VectorEncoder { /** * Encodes the vector style of a polygon by applying fill and stroke styles. */ - protected encodeVectorStylePolygon(symbolizers: MFPSymbolizer[], fillStyle: Fill, strokeStyle: Stroke) { + protected encodeVectorStylePolygon( + geojsonFeature: GeoJSONFeature, + symbolizers: MFPSymbolizer[], + fillStyle: Fill, + strokeStyle: Stroke, + ) { const symbolizer = { type: 'polygon', } as MFPSymbolizerPolygon; - this.encodeVectorStyleFill(symbolizer, fillStyle); + this.encodeVectorStyleFill(geojsonFeature, symbolizer, fillStyle); if (strokeStyle !== null) { - this.encodeVectorStyleStroke(symbolizer, strokeStyle); + this.encodeVectorStyleStroke(geojsonFeature, symbolizer, strokeStyle); } symbolizers.push(symbolizer); } @@ -481,6 +508,7 @@ export default class VectorEncoder { * Encodes the vector style stroke properties. */ protected encodeVectorStyleStroke( + geojsonFeature: GeoJSONFeature, symbolizer: MFPSymbolizerPoint | MFPSymbolizerLine | MFPSymbolizerPolygon, strokeStyle: Stroke, ) { @@ -515,13 +543,22 @@ export default class VectorEncoder { /** * Encodes vector style text. */ - protected encodeVectorStyleText(symbolizers: MFPSymbolizer[], textStyle: Text) { + protected encodeVectorStyleText( + geojsonFeature: GeoJSONFeature, + symbolizers: MFPSymbolizer[], + textStyle: Text, + ) { const label = textStyle.getText(); if (label) { + const fp = getFontParameters(textStyle.getFont() || 'sans-serif'); const symbolizer = { type: 'text', label: textStyle.getText(), - fontFamily: textStyle.getFont() ? textStyle.getFont() : 'sans-serif', + fontFamily: fp.family, + fontSize: fp.size, + fontStyle: fp.style, + fontWeight: fp.weight, + // FIXME: missing fontVariant, is it supported in MFP? labelXOffset: textStyle.getOffsetX(), // OL and MFP behaves differently on the Y offset labelYOffset: -textStyle.getOffsetY(), @@ -529,7 +566,7 @@ export default class VectorEncoder { } as MFPSymbolizerText; const fillStyle = textStyle.getFill(); if (fillStyle !== null) { - this.encodeVectorStyleFill(symbolizer, fillStyle); + this.encodeVectorStyleFill(geojsonFeature, symbolizer, fillStyle); symbolizer.fontColor = symbolizer.fillColor; } const strokeStyle = textStyle.getStroke(); @@ -548,7 +585,7 @@ export default class VectorEncoder { symbolizer.haloRadius = strokeWidth; } } - this.customizer_.text(this.layerState_, symbolizer, textStyle); + this.customizer_.text(this.layerState_, geojsonFeature, symbolizer, textStyle); symbolizers.push(symbolizer); } } diff --git a/src/types.ts b/src/types.ts index 731f6ec..00d3b66 100644 --- a/src/types.ts +++ b/src/types.ts @@ -49,7 +49,7 @@ export interface MFPSymbolizerText extends MFPSymbolizer, MFPFillStyle { type: 'text'; fontColor: string; fontFamily: string; - fontSize: number; + fontSize: string; // ex 12px fontStyle: string; fontWeight: string; haloColor: string; diff --git a/test.js b/test.js index c13cbd4..4126fbe 100644 --- a/test.js +++ b/test.js @@ -241,7 +241,10 @@ test('Vector features', async (t) => { { type: 'text', label: 'A polygon', - fontFamily: '12px sans-serif', + fontFamily: 'sans-serif', + fontSize: '12px', + fontStyle: 'normal', + fontWeight: 'normal', labelXOffset: 0, labelYOffset: 12, labelAlign: 'cm', @@ -264,7 +267,10 @@ test('Vector features', async (t) => { { type: 'text', label: 'A circle', - fontFamily: '12px sans-serif', + fontFamily: 'sans-serif', + fontSize: '12px', + fontStyle: 'normal', + fontWeight: 'normal', labelXOffset: 0, labelYOffset: 12, labelAlign: 'cm', @@ -285,7 +291,10 @@ test('Vector features', async (t) => { { type: 'text', label: 'A line', - fontFamily: '12px sans-serif', + fontFamily: 'sans-serif', + fontSize: '12px', + fontStyle: 'normal', + fontWeight: 'normal', labelXOffset: 0, labelYOffset: 12, labelAlign: 'cm', @@ -300,7 +309,10 @@ test('Vector features', async (t) => { { type: 'text', label: 'A point', - fontFamily: '12px sans-serif', + fontFamily: 'sans-serif', + fontSize: '12px', + fontStyle: 'normal', + fontWeight: 'normal', labelXOffset: 0, labelYOffset: 12, labelAlign: 'cm',