UNPKG

@geogirafe/lib-geoportal

Version:

GeoGirafe is a flexible application to build online geoportals.

193 lines (192 loc) 7.09 kB
import { fromCircle } from 'ol/geom/Polygon.js'; import { get as getProjection } from 'ol/proj.js'; import { getArea as getSphericalArea, getDistance as getSphericalDistance } from 'ol/sphere.js'; import { unByKey } from 'ol/Observable.js'; import { LineString, Point } from 'ol/geom.js'; import GeoConsts from '../geoconsts.js'; import { buffer } from 'ol/extent.js'; /** * Unsubscribe to all OpenLayer listeners. */ export const unByKeyAll = (eventKeys) => { eventKeys.forEach((eventKey) => unByKey(eventKey)); }; /** * @returns a layer in the map that match the given name (property name). */ export const getOlayerByName = (map, layerName) => { return map.getAllLayers().find((layer) => layer.get('name') === layerName); }; /** * Clone the properties of the given feature and delete ol properties to keep only the feature "app" properties. * Handle map server values served as object and serve them as "simple" values. */ export const removeUnwantedOlParams = (feature, keepGeom = false) => { const properties = { ...feature.getProperties() }; delete properties.boundedBy; if (!keepGeom) { delete properties[feature.getGeometryName()]; } // Handle map server values served as object. Object.keys(properties).forEach((key) => { const value = properties[key]; if (typeof value === 'object') { if (value['xsi:nil'] === 'true') { properties[key] = undefined; } else if (value['_content_']) { properties[key] = value['_content_']; } } }); return properties; }; /** * @returns A polygon generated from the circle. */ export const polygonFromCircle = (geometry) => { return fromCircle(geometry, GeoConsts.CIRCLE_TO_POLYGON_SIDES); }; /** * @param coordinates ol Coordinate list * @param projection Projection identifier * @returns the length between coordinates, considering the current map projection (projected or geographic) */ export const getDistance = (coordinates, projection) => { if (isProjectionInDegrees(projection)) { let totalLength = 0; coordinates.forEach((coordinate, idx) => { if (coordinates[idx + 1]) { totalLength += getSphericalDistance(coordinate, coordinates[idx + 1]); } }); return totalLength; } return new LineString(coordinates).getLength(); }; /** * @param polygon ol Polygon * @param projection Projection identifier * @returns the area of a polygon, considering the current map projection (projected or geographic) */ export const getAreaOfPolygon = (polygon, projection) => { if (isProjectionInDegrees(projection)) { return getSphericalArea(polygon, { projection: getProjection(projection) }); } return polygon.getArea(); }; export const getAreaOfCircle = (circle, projection) => { if (isProjectionInDegrees(projection)) { return getSphericalArea(circle, { projection: getProjection(projection) }); } return Math.PI * Math.pow(circle.getRadius(), 2); }; const isProjectionInDegrees = (proj) => { const projection = getProjection(proj); return projection?.getUnits() === 'degrees'; }; export const isCoordinateInDegrees = (coordinate) => { return coordinate[0] > -90 && coordinate[0] < 90 && coordinate[1] > -180 && coordinate[1] < 180; }; export const getSelectionBoxFromMapClick = (eventCoordinate, olMap, pixelTolerance) => { const pointExtent = [...eventCoordinate, ...eventCoordinate]; const pixelExtent = buffer(pointExtent, pixelTolerance); const mapExtent = [ ...olMap.getCoordinateFromPixel([pixelExtent[0], pixelExtent[1]]), ...olMap.getCoordinateFromPixel([pixelExtent[2], pixelExtent[3]]) ]; // Because the pixel origin is in the top left corner and the coordinate origin (in projected crs) is in the lower // left corner, the extent is switched to [xmin, ymin, xmax, ymax] return [ Math.min(mapExtent[0], mapExtent[2]), Math.min(mapExtent[1], mapExtent[3]), Math.max(mapExtent[0], mapExtent[2]), Math.max(mapExtent[1], mapExtent[3]) ]; }; export const reprojectGeometry = (geometry, sourceProjection, destinationProjection) => { try { if (typeof sourceProjection === 'string') { sourceProjection = getProjection(sourceProjection) ?? undefined; } if (typeof destinationProjection === 'string') { destinationProjection = getProjection(destinationProjection) ?? undefined; } if (!sourceProjection || !destinationProjection) { throw new Error(`Not able to reproject geometry, invalid or unknown projection used.`); } const reprojectedGeometry = geometry.clone(); return reprojectedGeometry.transform(sourceProjection, destinationProjection); } catch (e) { throw new Error(`Not able to reproject geometry: ${e}`, { cause: e }); } }; export const ensurePolygonIsProperlyClosed = (polygon) => { const coordinates = polygon.getCoordinates()[0]; let segments = [...coordinates]; if (coordinates.length > 2 && coordinates[0][0] != coordinates[coordinates.length - 1][0]) { segments = [...coordinates, coordinates[0]]; polygon.setCoordinates([segments]); } return segments; }; export const getHalfPoint = (coordinates) => { return new Point(new LineString(coordinates).getCoordinateAt(0.5)); }; export const getLabelStyle = (position, text, labelStyle) => { if (text.trim() != '') { const style = labelStyle.clone(); style.setGeometry(position); style.getText().setText(text); return style; } return undefined; }; export const getRadiusDataForCircle = (circle, defaultStyle, stroke) => { const radius = circle.getRadius(); const center = circle.getCenter(); const pointer = circle.getProperties()['pointer'] ?? [center[0] + radius, center[1]]; const radiusLine = [center, pointer]; const radiusLineStyle = defaultStyle.clone(); radiusLineStyle.setStroke(stroke); radiusLineStyle.getText().setText(''); radiusLineStyle.setGeometry(new LineString(radiusLine)); return { style: radiusLineStyle, radius: radius, radiusLine: radiusLine }; }; export const getLengthAsMetricText = (length) => { if (length === undefined) { return ''; } if (length <= 500) { return `${length.toFixed(2)} m`; } const lengthInKilometers = length / 1000; if (length <= 2000) { return `${lengthInKilometers.toFixed(3)} km`; } return `${lengthInKilometers.toFixed(2)} km`; }; export const getAreaAsMetricText = (area) => { if (area === undefined) { return ''; } if (area <= 10000) { return `${area.toFixed(2)} m²`; } return `${(area / 1000000).toFixed(2)} km²`; }; export const getAzimuthAsText = (azimuth) => { if (azimuth) { return `${azimuth.toFixed(0)}°`; } return ''; };