Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 75 additions & 30 deletions src/ol/utils/MapsetKmlFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -138,6 +143,53 @@ const getLineIcon = (
};

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 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) {
return null;
}

if (propertyName === 'name') {
return documentNode.getElementsByTagName('name')[0]?.textContent ?? null;
}

if (propertyName === 'description') {
return (
documentNode.getElementsByTagName('description')[0]?.textContent ?? null
);
}

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.
Expand Down Expand Up @@ -168,7 +220,7 @@ class MapsetKmlFormat {
transform(
JSON.parse(circleGeometryCenter as string) as Coordinate,
EPSG_4326,
featureProjection || EPSG_4326,
featureProjection ?? EPSG_4326,
),
parseFloat(circleGeometryRadius as string),
);
Expand Down Expand Up @@ -259,6 +311,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
Expand Down Expand Up @@ -409,32 +468,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({
Expand Down Expand Up @@ -742,14 +787,6 @@ class MapsetKmlFormat {
// We set the scale as extended metadata because the <scale> 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')) {
clone.set(
'pictureOptions',
JSON.stringify(feature.get('pictureOptions')),
);
}
}

// In case a fill pattern should be applied (use fillPattern attribute to store pattern id, color etc)
Expand All @@ -768,6 +805,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) {
Expand Down
Loading