From c8de70a027c13d08823a35b340950a9d76564c1a Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 2 Oct 2025 10:49:13 +0200 Subject: [PATCH 01/10] fix(MapsetKmlFormat): extend functionality to support feature scaling disable in KML --- src/ol/utils/MapsetKmlFormat.ts | 48 ++++++++++++++++----------------- src/ol/utils/index.js | 2 ++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/ol/utils/MapsetKmlFormat.ts b/src/ol/utils/MapsetKmlFormat.ts index d9331aba..be1b5e49 100644 --- a/src/ol/utils/MapsetKmlFormat.ts +++ b/src/ol/utils/MapsetKmlFormat.ts @@ -69,6 +69,11 @@ interface IconOptions { zIndex: number; } +interface ScaleOptions { + defaultScale?: number; + resolution: number; +} + // Comes from ol >= 6.7, // https://github.com/openlayers/openlayers/blob/main/src/ol/format/KML.js#L320 const scaleForSize = (size: Size) => { @@ -168,7 +173,7 @@ class MapsetKmlFormat { transform( JSON.parse(circleGeometryCenter as string) as Coordinate, EPSG_4326, - featureProjection || EPSG_4326, + featureProjection ?? EPSG_4326, ), parseFloat(circleGeometryRadius as string), ); @@ -259,6 +264,13 @@ class MapsetKmlFormat { style?.setZIndex(parseInt(feature.get('zIndex') as string, 10)); } + const scaleOptions = (feature.get('pictureOptions') ?? + feature.get('scaleOptions')) as ScaleOptions | string; + if (scaleOptions && typeof scaleOptions === 'string') { + const parsed = JSON.parse(scaleOptions) as ScaleOptions; + feature.set('scaleOptions', parsed); + } + // if the feature is a Point and we are offline, we use default vector // style. // if the feature is a Point and has a name with a text style, we @@ -409,32 +421,18 @@ class MapsetKmlFormat { stroke = null; styles = (feat, resolution) => { - /* Options to be used for picture scaling with map, should have at least + /* Options to be used for feature scaling with map, should have at least * a resolution attribute (this is the map resolution at the zoom level when - * the picture is created), can take an optional constant for further scale + * the feature is created), can take an optional constant for further scale * adjustment. * e.g. { resolution: 0.123, defaultScale: 1 / 6 } */ - interface PictureOptions { - defaultScale?: number; - resolution: number; - } - - if (feat.get('pictureOptions')) { - let pictureOptions = feat.get('pictureOptions') as - | PictureOptions - | string; - if (typeof pictureOptions === 'string') { - pictureOptions = JSON.parse(pictureOptions) as PictureOptions; - } - (feat as FeatureType).set('pictureOptions', pictureOptions); - if (pictureOptions.resolution) { - image?.setScale( - (pictureOptions.resolution / resolution) * - (pictureOptions?.defaultScale ?? 1), - ); - } + const scaleOpts = feat.get('scaleOptions') as ScaleOptions; + if (scaleOpts && image instanceof Icon && scaleOpts.resolution) { + image.setScale( + (scaleOpts.resolution / resolution) * (scaleOpts.defaultScale ?? 1), + ); } return new Style({ @@ -744,10 +742,10 @@ class MapsetKmlFormat { } // Set map resolution to use for icon-to-map proportional scaling - if (feature.get('pictureOptions')) { + if (feature.get('pictureOptions') || feature.get('scaleOptions')) { clone.set( - 'pictureOptions', - JSON.stringify(feature.get('pictureOptions')), + 'scaleOptions', + JSON.stringify(feature.get('scaleOptions')), ); } } diff --git a/src/ol/utils/index.js b/src/ol/utils/index.js index 23dab6f1..38e985b7 100644 --- a/src/ol/utils/index.js +++ b/src/ol/utils/index.js @@ -1,2 +1,4 @@ export { default as getFeatureInfoAtCoordinate } from './getFeatureInfoAtCoordinate'; export { default as getGraphByZoom } from './getGraphByZoom'; +export { default as getMapsetPolygonPattern } from './getMapsetPolygonPattern'; +export { default as MapsetKmlFormat } from './MapsetKmlFormat'; From 1935bddcb6cc9481ae751df04cc1b1b50974731e Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 23 Oct 2025 18:56:25 +0200 Subject: [PATCH 02/10] chore: add scaleOptions for all geom types in MapsetKmalFormat --- src/ol/utils/MapsetKmlFormat.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ol/utils/MapsetKmlFormat.ts b/src/ol/utils/MapsetKmlFormat.ts index be1b5e49..21455917 100644 --- a/src/ol/utils/MapsetKmlFormat.ts +++ b/src/ol/utils/MapsetKmlFormat.ts @@ -740,14 +740,6 @@ class MapsetKmlFormat { // We set the scale as extended metadata because the in the KML is related to a 32px img, since ol >= 6.10. clone.set('iconScale', newStyle.image.getScale()); } - - // Set map resolution to use for icon-to-map proportional scaling - if (feature.get('pictureOptions') || feature.get('scaleOptions')) { - clone.set( - 'scaleOptions', - JSON.stringify(feature.get('scaleOptions')), - ); - } } // In case a fill pattern should be applied (use fillPattern attribute to store pattern id, color etc) @@ -766,6 +758,14 @@ class MapsetKmlFormat { clone.set('minZoom', parseFloat(feature.get('minZoom') as string)); } + // Set map resolution to use for feature-to-map proportional scaling + if (feature.get('pictureOptions') || feature.get('scaleOptions')) { + clone.set( + 'scaleOptions', + JSON.stringify(feature.get('scaleOptions')), + ); + } + // If only text is displayed we must specify an // image style with scale=0 if (newStyle.text && !newStyle.image) { From 808dfaf784bbb3e996af087c2010b5294c06cf3d Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 23 Oct 2025 18:57:01 +0200 Subject: [PATCH 03/10] chore(release): 3.4.6-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2926f09b..b853f27d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mobility-toolbox-js", "license": "MIT", "description": "Toolbox for JavaScript applications in the domains of mobility and logistics.", - "version": "3.4.5", + "version": "3.4.6-beta.0", "homepage": "https://mobility-toolbox-js.geops.io/", "exports": { ".": "./index.js", From 98b7496cb13dd9bd6954662a36cba59daecba60c Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 30 Oct 2025 14:59:32 +0100 Subject: [PATCH 04/10] feat(MapsetKmlFormat): add methods for reading and writing properties in KML strings --- src/ol/utils/MapsetKmlFormat.ts | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/ol/utils/MapsetKmlFormat.ts b/src/ol/utils/MapsetKmlFormat.ts index 21455917..163a6b62 100644 --- a/src/ol/utils/MapsetKmlFormat.ts +++ b/src/ol/utils/MapsetKmlFormat.ts @@ -142,7 +142,62 @@ const getLineIcon = ( }); }; +type zoomLimitsType = null | number[][]; + +function validateZoomLimits(zoomLimits: zoomLimitsType): boolean { + return ( + Array.isArray(zoomLimits) && + zoomLimits.every((item) => { + return ( + Array.isArray(item) && + item.length === 2 && + item.every((n) => { + return typeof n === 'number' && !Number.isNaN(n); + }) + ); + }) + ); +} + class MapsetKmlFormat { + /** + * Get Document properties. + * @param {String} kmlString A string representing a KML file. + * @returns {Object} An object containing the document properties (name, description, zoomLimits). + */ + public getDocumentProperties( + kmlString: string, + ): Record { + const kmlDoc = parse(kmlString); + let documentProperties: Record< + string, + number | object | string | zoomLimitsType + > = {}; + const documentNode = kmlDoc.getElementsByTagName('Document')[0]; + if (documentNode) { + const name = documentNode.getElementsByTagName('name')[0]?.textContent; + const description = + documentNode.getElementsByTagName('description')[0]?.textContent; + const zoomLimitsData = documentNode + .getElementsByTagName('ExtendedData')[0] + ?.getElementsByTagName('Data')[0]; + let zoomLimits: null | number[][] = null; + if (zoomLimitsData?.getAttribute('name') === 'zoomLimits') { + const value = + zoomLimitsData.getElementsByTagName('value')[0]?.textContent; + try { + zoomLimits = JSON.parse(value || '') as number[][]; + if (!validateZoomLimits(zoomLimits)) { + zoomLimits = null; + } + } catch { + zoomLimits = null; + } + } + documentProperties = { description, name, zoomLimits }; + } + return documentProperties; + } /** * Read a KML string. * @param {String} kmlString A string representing a KML file. @@ -856,6 +911,14 @@ class MapsetKmlFormat { // tag featString = featString.replace(//g, ''); + // Add KML document zoomLimits + if (layer.get('zoomLimits')) { + featString = featString.replace( + //, + `${JSON.stringify(layer.get('zoomLimits'))}`, + ); + } + // Add KML document name if (layer.get('name')) { featString = featString.replace( From b2ddb819fa8bd1485aeb52d271d6c450b44d3319 Mon Sep 17 00:00:00 2001 From: danji90 Date: Thu, 30 Oct 2025 15:00:23 +0100 Subject: [PATCH 05/10] chore(release): 3.5.0-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9032e205..44878f9c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mobility-toolbox-js", "license": "MIT", "description": "Toolbox for JavaScript applications in the domains of mobility and logistics.", - "version": "3.4.6", + "version": "3.5.0-beta.0", "homepage": "https://mobility-toolbox-js.geops.io/", "exports": { ".": "./index.js", From 4f15d6f26012c3e5a0d1ba9af4f0e99b3d10fed1 Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 3 Nov 2025 09:59:06 +0100 Subject: [PATCH 06/10] chore: make getDocumentProperty function more generic --- src/ol/utils/MapsetKmlFormat.ts | 86 +++++++++++++++------------------ 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/src/ol/utils/MapsetKmlFormat.ts b/src/ol/utils/MapsetKmlFormat.ts index 163a6b62..f652fd0a 100644 --- a/src/ol/utils/MapsetKmlFormat.ts +++ b/src/ol/utils/MapsetKmlFormat.ts @@ -142,62 +142,54 @@ const getLineIcon = ( }); }; -type zoomLimitsType = null | number[][]; - -function validateZoomLimits(zoomLimits: zoomLimitsType): boolean { - return ( - Array.isArray(zoomLimits) && - zoomLimits.every((item) => { - return ( - Array.isArray(item) && - item.length === 2 && - item.every((n) => { - return typeof n === 'number' && !Number.isNaN(n); - }) - ); - }) - ); -} - class MapsetKmlFormat { /** * Get Document properties. + * @param {String} propertyName The property name to get (name, description, zoomLimits). * @param {String} kmlString A string representing a KML file. * @returns {Object} An object containing the document properties (name, description, zoomLimits). */ - public getDocumentProperties( - kmlString: string, - ): Record { - const kmlDoc = parse(kmlString); - let documentProperties: Record< - string, - number | object | string | zoomLimitsType - > = {}; + public getDocumentProperty(propertyName: string, kmlString: string) { + if (!propertyName) { + return null; + } + + let kmlDoc: Document; + try { + kmlDoc = parse(kmlString); + } catch (error) { + console.error('Invalid KML string', error); + return null; + } + const documentNode = kmlDoc.getElementsByTagName('Document')[0]; - if (documentNode) { - const name = documentNode.getElementsByTagName('name')[0]?.textContent; - const description = - documentNode.getElementsByTagName('description')[0]?.textContent; - const zoomLimitsData = documentNode - .getElementsByTagName('ExtendedData')[0] - ?.getElementsByTagName('Data')[0]; - let zoomLimits: null | number[][] = null; - if (zoomLimitsData?.getAttribute('name') === 'zoomLimits') { - const value = - zoomLimitsData.getElementsByTagName('value')[0]?.textContent; - try { - zoomLimits = JSON.parse(value || '') as number[][]; - if (!validateZoomLimits(zoomLimits)) { - zoomLimits = null; - } - } catch { - zoomLimits = null; - } - } - documentProperties = { description, name, zoomLimits }; + if (!documentNode) { + return null; + } + + if (propertyName === 'name') { + return documentNode.getElementsByTagName('name')[0]?.textContent ?? null; + } + + if (propertyName === 'description') { + return ( + documentNode.getElementsByTagName('description')[0]?.textContent ?? null + ); } - return documentProperties; + + const propertiesData = documentNode + .getElementsByTagName('ExtendedData')[0] + ?.getElementsByTagName('Data'); + + return ( + Array.from(propertiesData || []) + .find((data) => { + return data.getAttribute('name') === propertyName; + }) + ?.getElementsByTagName('value')[0]?.textContent ?? null + ); } + /** * Read a KML string. * @param {String} kmlString A string representing a KML file. From 9fbce894847e33c2d7c7de97410ae2048d2fbd51 Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 3 Nov 2025 11:46:02 +0100 Subject: [PATCH 07/10] chore(release): 3.5.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 44878f9c..f3ee7b43 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mobility-toolbox-js", "license": "MIT", "description": "Toolbox for JavaScript applications in the domains of mobility and logistics.", - "version": "3.5.0-beta.0", + "version": "3.5.0-beta.1", "homepage": "https://mobility-toolbox-js.geops.io/", "exports": { ".": "./index.js", From 317560b56ad756e6aface1744ccb5e36c868105b Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 3 Nov 2025 11:48:36 +0100 Subject: [PATCH 08/10] chore: revert version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3ee7b43..44878f9c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mobility-toolbox-js", "license": "MIT", "description": "Toolbox for JavaScript applications in the domains of mobility and logistics.", - "version": "3.5.0-beta.1", + "version": "3.5.0-beta.0", "homepage": "https://mobility-toolbox-js.geops.io/", "exports": { ".": "./index.js", From 711a215a413c6fc7d3178c372c3b457b4f2f4afe Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 3 Nov 2025 11:49:18 +0100 Subject: [PATCH 09/10] chore(release): 3.5.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 44878f9c..f3ee7b43 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mobility-toolbox-js", "license": "MIT", "description": "Toolbox for JavaScript applications in the domains of mobility and logistics.", - "version": "3.5.0-beta.0", + "version": "3.5.0-beta.1", "homepage": "https://mobility-toolbox-js.geops.io/", "exports": { ".": "./index.js", From dd13012a700356a1c28c693b8bb1f74d820fc8f6 Mon Sep 17 00:00:00 2001 From: danji90 Date: Mon, 23 Feb 2026 10:03:16 +0100 Subject: [PATCH 10/10] chore: remove ticket specific code --- src/ol/utils/MapsetKmlFormat.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/ol/utils/MapsetKmlFormat.ts b/src/ol/utils/MapsetKmlFormat.ts index f652fd0a..636254c6 100644 --- a/src/ol/utils/MapsetKmlFormat.ts +++ b/src/ol/utils/MapsetKmlFormat.ts @@ -903,14 +903,6 @@ class MapsetKmlFormat { // tag featString = featString.replace(//g, ''); - // Add KML document zoomLimits - if (layer.get('zoomLimits')) { - featString = featString.replace( - //, - `${JSON.stringify(layer.get('zoomLimits'))}`, - ); - } - // Add KML document name if (layer.get('name')) { featString = featString.replace(