UNPKG

vue3-openlayers

Version:
1,533 lines 993 kB
"use strict"; const vue = require("vue"); const Feature = require("ol/Feature"); const Geometry = require("ol/geom/Geometry"); const Geolocation = require("ol/Geolocation"); const Map = require("ol/Map"); const Overlay = require("ol/Overlay"); const proj4$2 = require("ol/proj/proj4"); const Projection$1 = require("ol/proj/Projection"); const View = require("ol/View"); const proj = require("ol/proj"); const source = require("ol/source"); const AnimatedCluster = require("ol-ext/layer/AnimatedCluster"); const Graticule = require("ol/layer/Graticule"); const HeatmapLayer = require("ol/layer/Heatmap"); const ImageLayer = require("ol/layer/Image"); const LayerGroup = require("ol/layer/Group"); const TileLayer = require("ol/layer/Tile"); const TileSource = require("ol/source/Tile"); const VectorLayer = require("ol/layer/Vector"); const VectorTileLayer = require("ol/layer/VectorTile"); const VectorImageLayer = require("ol/layer/VectorImage"); const TileLayer$1 = require("ol/layer/WebGLTile"); const WebGLVectorLayer = require("ol/layer/WebGLVector"); const BingMaps = require("ol/source/BingMaps"); const VectorSource = require("ol/source/Vector"); const ImageSource = require("ol/source/Image"); const Cluster = require("ol/source/Cluster"); const Static = require("ol/source/ImageStatic"); const ImageWMS = require("ol/source/ImageWMS"); const OSM = require("ol/source/OSM"); const StadiaMaps = require("ol/source/StadiaMaps"); const WMTSSource = require("ol/source/WMTS"); const TileGridWMTS = require("ol/tilegrid/WMTS"); const TileArcGISRest = require("ol/source/TileArcGISRest"); const tilegrid = require("ol/tilegrid"); const TileDebug = require("ol/source/TileDebug"); const GeoTIFF = require("ol/source/GeoTIFF"); const TileJSON = require("ol/source/TileJSON"); const TileWMS = require("ol/source/TileWMS"); const ol = require("ol"); const VectorTileSource = require("ol/source/VectorTile"); const XYZ = require("ol/source/XYZ"); const extent = require("ol/extent"); const Attribution = require("ol/control/Attribution"); const Bar = require("ol-ext/control/Bar"); const Button = require("ol-ext/control/Button"); const ContextMenu = require("ol-contextmenu"); const FullScreen = require("ol/control/FullScreen"); const LayerSwitcher = require("ol-ext/control/LayerSwitcher"); const LayerSwitcherImage = require("ol-ext/control/LayerSwitcherImage"); const MousePosition = require("ol/control/MousePosition"); const OverviewMap = require("ol/control/OverviewMap"); const PrintDialog = require("ol-ext/control/PrintDialog"); const Profile = require("ol-ext/control/Profile"); const Rotate = require("ol/control/Rotate"); const ScaleLine = require("ol/control/ScaleLine"); const Search = require("ol-ext/control/Search"); const Swipe = require("ol-ext/control/Swipe"); const Toggle = require("ol-ext/control/Toggle"); const VideoRecorder = require("ol-ext/control/VideoRecorder"); const MapZone = require("ol-ext/control/MapZone"); const Zoom = require("ol/control/Zoom"); const ZoomSlider = require("ol/control/ZoomSlider"); const ZoomToExtent = require("ol/control/ZoomToExtent"); const Circle = require("ol/geom/Circle"); const LineString = require("ol/geom/LineString"); const MultiLineString = require("ol/geom/MultiLineString"); const MultiPoint = require("ol/geom/MultiPoint"); const MultiPolygon = require("ol/geom/MultiPolygon"); const Point$1 = require("ol/geom/Point"); const Polygon = require("ol/geom/Polygon"); const Style = require("ol/style/Style"); const Draw = require("ol/interaction/Draw"); const Modify = require("ol/interaction/Modify"); const CircleStyle = require("ol/style/Circle"); const Fill = require("ol/style/Fill"); const Stroke = require("ol/style/Stroke"); const interaction = require("ol/interaction"); const Icon = require("ol/style/Icon"); const Text = require("ol/style/Text"); const FlowLine = require("ol-ext/style/FlowLine"); const SelectCluster = require("ol-ext/interaction/SelectCluster"); const DragBox = require("ol/interaction/DragBox"); const DragRotate = require("ol/interaction/DragRotate"); const DragRotateAndZoom = require("ol/interaction/DragRotateAndZoom"); const Link = require("ol/interaction/Link"); const Select = require("ol/interaction/Select"); const Pointer = require("ol/interaction/Pointer"); const Snap = require("ol/interaction/Snap"); const Transform = require("ol-ext/interaction/Transform"); const selectconditions = require("ol/events/condition"); const functions = require("ol/functions"); const MouseWheelZoom = require("ol/interaction/MouseWheelZoom"); const Synchronize = require("ol-ext/interaction/Synchronize"); const Drop = require("ol-ext/featureanimation/Drop"); const animations = require("ol/easing"); require("ol-ext/featureanimation/FeatureAnimation"); const Fade = require("ol-ext/featureanimation/Fade"); const Path = require("ol-ext/featureanimation/Path"); const Shake = require("ol-ext/featureanimation/Shake"); const Slide = require("ol-ext/featureanimation/Slide"); const Teleport = require("ol-ext/featureanimation/Teleport"); const Zoom$1 = require("ol-ext/featureanimation/Zoom"); const geom = require("ol/geom"); const format = require("ol/format"); const loadingstrategy = require("ol/loadingstrategy"); require("ol-contextmenu/ol-contextmenu.css"); require("ol-ext/dist/ol-ext.css"); require("ol/ol.css"); function _interopNamespaceDefault(e) { const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } }); if (e) { for (const k2 in e) { if (k2 !== "default") { const d2 = Object.getOwnPropertyDescriptor(e, k2); Object.defineProperty(n, k2, d2.get ? d2 : { enumerable: true, get: () => e[k2] }); } } } n.default = e; return Object.freeze(n); } const extent__namespace = /* @__PURE__ */ _interopNamespaceDefault(extent); const selectconditions__namespace = /* @__PURE__ */ _interopNamespaceDefault(selectconditions); const animations__namespace = /* @__PURE__ */ _interopNamespaceDefault(animations); const geom__namespace = /* @__PURE__ */ _interopNamespaceDefault(geom); const format__namespace = /* @__PURE__ */ _interopNamespaceDefault(format); const loadingstrategy__namespace = /* @__PURE__ */ _interopNamespaceDefault(loadingstrategy); const _sfc_main$1n = /* @__PURE__ */ vue.defineComponent({ __name: "OlFeature", props: { properties: {} }, setup(__props, { expose: __expose }) { const props = __props; const vectorSource = vue.inject("vectorSource"); const vectorLayer = vue.inject( "vectorLayer", null ); const heatmapLayer = vue.inject("heatmapLayer", null); const layer = heatmapLayer || vectorLayer; const animation = vue.inject( "animation", null ); const feature = vue.ref( new Feature({ ...props.properties }) ); vue.watch( () => props.properties, // Needed as props.properties is optional (properties) => { if (properties instanceof Geometry) { feature.value.setGeometry(properties); feature.value.setProperties({}); } else if (typeof properties !== "undefined") { feature.value.setGeometry(void 0); feature.value.setProperties(properties); } else { feature.value.setGeometry(void 0); feature.value.setProperties({}); } } ); vue.watch( () => vectorSource, (newVal, oldVal) => { oldVal?.value?.removeFeature(feature.value); newVal?.value?.addFeature(feature.value); newVal?.value?.changed(); } ); vue.onMounted(() => { if (animation?.value) { layer?.value?.animateFeature(feature.value, animation.value); } vue.nextTick(() => { vectorSource?.value?.addFeature(feature.value); }); }); vue.onUnmounted(() => { vectorSource?.value?.removeFeature(feature.value); }); vue.provide("feature", feature); vue.provide("stylable", feature); __expose({ feature }); return (_ctx, _cache) => { return vue.renderSlot(_ctx.$slots, "default"); }; } }); function checkAndUpdateStylePropDef(options) { if ("styles" in options) { const { styles, ...rest } = vue.toRefs(vue.reactive(options)); return { style: styles, ...rest }; } else { return options; } } function usePropsAsObjectProperties(props) { const instance = vue.getCurrentInstance(); let globalOptions = { debug: false }; if (instance) { globalOptions = vue.inject("ol-options", globalOptions); } const revisedProps = checkAndUpdateStylePropDef(props); const properties = vue.reactive(revisedProps); if (globalOptions?.debug) { console.debug("[Vue3-OpenLayers Debug] PROPS", { in: props, out: properties }); } return properties; } const COMMON_EVENTS = ["change", "error", "propertychange"]; const LAYER_EVENTS = [ "change:extent", "change:maxResolution", "change:maxZoom", "change:minResolution", "change:minZoom", "change:opacity", "change:source", "change:visible", "change:zIndex", "postrender", "prerender", "sourceready" ]; const TILE_SOURCE_EVENTS = [ "tileloadend", "tileloaderror", "tileloadstart" ]; const IMAGE_SOURCE_EVENTS = [ "imageloadend", "imageloaderror", "imageloadstart" ]; const VECTOR_SOURCE_EVENTS = [ "addfeature", "changefeature", "clear", "featuresloadend", "featuresloaderror", "featuresloadstart", "removefeature" ]; function useOpenLayersEvents(feature, eventNames) { const instance = vue.getCurrentInstance(); let globalOptions = { debug: false }; if (instance) { globalOptions = vue.inject("ol-options", globalOptions); } function updateOpenLayersEventHandlers() { [...COMMON_EVENTS, ...eventNames].forEach((eventName) => { let unwrappedFeature; if (vue.isRef(feature)) { unwrappedFeature = feature.value; } else { unwrappedFeature = feature; } unwrappedFeature.on(eventName, (...args) => { if (globalOptions?.debug) { console.debug("[Vue3-OpenLayers Debug] EVENT", eventName, { eventName, args, source: feature }); } instance?.emit(eventName, ...args); }); }); } if (instance) { vue.onMounted(() => { updateOpenLayersEventHandlers(); }); } return { updateOpenLayersEventHandlers }; } const _sfc_main$1m = /* @__PURE__ */ vue.defineComponent({ ...{ inheritAttrs: false }, __name: "OlGeoLocation", props: { tracking: { type: Boolean, default: true }, trackingOptions: { default: () => ({ enableHighAccuracy: true }) }, projection: { default: "EPSG:3857" } }, emits: ["change", "error", "propertychange", "change:accuracy", "change:accuracyGeometry", "change:altitude", "change:altitudeAccuracy", "change:heading", "change:position", "change:projection", "change:speed", "change:tracking", "change:trackingOptions"], setup(__props, { expose: __expose }) { const props = __props; const properties = usePropsAsObjectProperties(props); const geoLoc = vue.computed(() => new Geolocation(properties)); useOpenLayersEvents(geoLoc, [ "change:accuracy", "change:accuracyGeometry", "change:altitude", "change:altitudeAccuracy", "change:heading", "change:position", "change:projection", "change:speed", "change:tracking", "change:trackingOptions" ]); const position = vue.ref([]); const accuracy = vue.ref(0); const altitude = vue.ref(0); const altitudeAccuracy = vue.ref(0); const speed = vue.ref(0); const heading = vue.ref(0); const accuracyGeometry = vue.ref(null); __expose({ geoLoc, position, accuracy, altitude, altitudeAccuracy, speed, heading, accuracyGeometry }); return (_ctx, _cache) => { return vue.renderSlot(_ctx.$slots, "default", { position: position.value, speed: speed.value, heading: heading.value, accuracy: accuracy.value, altitude: altitude.value, altitudeAccuracy: altitudeAccuracy.value, accuracyGeometry: accuracyGeometry.value }); }; } }); function mergeProperties(existingProperties, newProperties) { for (const key in newProperties) { if (Object.prototype.hasOwnProperty.call(newProperties, key)) { if (newProperties[key] !== void 0) { existingProperties[key] = newProperties[key]; } } } return existingProperties; } const _sfc_main$1l = /* @__PURE__ */ vue.defineComponent({ __name: "OlMap", props: { controls: {}, pixelRatio: {}, interactions: {}, keyboardEventTarget: {}, layers: {}, maxTilesLoading: {}, moveTolerance: {}, overlays: {}, target: {}, view: {}, instance: {} }, emits: ["change", "error", "propertychange", "change:layerGroup", "change:size", "change:target", "change:view", "click", "dblclick", "singleclick", "loadstart", "loadend", "pointerdrag", "pointermove", "movestart", "moveend", "postrender", "precompose", "postcompose", "rendercomplete"], setup(__props, { expose: __expose, emit: __emit }) { const props = __props; const emit = __emit; const properties = usePropsAsObjectProperties({ ...props, instance: void 0 }); const mapRef = vue.ref(void 0); let map = props.instance || new Map({ ...properties }); vue.watch( properties, () => { const p2 = props.instance ? mergeProperties(properties, props.instance.getProperties()) : properties; map?.setProperties(p2); }, { immediate: true } ); vue.onMounted(() => { if (!props.instance) { map?.setTarget(mapRef.value); } }); vue.onBeforeUnmount(() => { if (!props.instance) { map?.setTarget(void 0); } }); vue.onUnmounted(() => { map = void 0; }); vue.provide("map", map); const forEachFeatureAtPixel = (pixel, callback, options) => map?.forEachFeatureAtPixel(pixel, callback, options); const getCoordinateFromPixel = (pixel) => map?.getCoordinateFromPixel(pixel); const render = () => map?.render(); const updateSize = () => map?.updateSize(); map.on("change", (event) => emit("change", event)); map.on("error", (event) => emit("error", event)); map.on("propertychange", (event) => emit("propertychange", event)); map.on("click", (event) => emit("click", event)); map.on("change:size", (event) => emit("change:size", event)); map.on("change:target", (event) => emit("change:target", event)); map.on("change:view", (event) => emit("change:view", event)); map.on("dblclick", (event) => emit("dblclick", event)); map.on("singleclick", (event) => emit("singleclick", event)); map.on("pointerdrag", (event) => emit("pointerdrag", event)); map.on("pointermove", (event) => emit("pointermove", event)); map.on("movestart", (event) => emit("movestart", event)); map.on("moveend", (event) => emit("moveend", event)); map.on("postrender", (event) => emit("postrender", event)); map.on("precompose", (event) => emit("precompose", event)); map.on("postcompose", (event) => emit("postcompose", event)); map.on("rendercomplete", (event) => emit("rendercomplete", event)); map.on("loadstart", (event) => { map?.getTargetElement().classList.add("ol-map"); map?.getTargetElement().classList.add("ol-map-loading"); map?.getTargetElement().classList.remove("ol-map-fully-loaded"); emit("loadstart", event); }); map.on("loadend", (event) => { map?.getTargetElement().classList.add("ol-map-fully-loaded"); map?.getTargetElement().classList.remove("ol-map-loading"); emit("loadend", event); }); __expose({ map, mapRef, forEachFeatureAtPixel, getCoordinateFromPixel, render, updateSize }); return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", { ref_key: "mapRef", ref: mapRef }, [ vue.renderSlot(_ctx.$slots, "default") ], 512); }; } }); const _sfc_main$1k = /* @__PURE__ */ vue.defineComponent({ ...{ inheritAttrs: false }, __name: "OlOverlay", props: { id: {}, element: {}, offset: {}, position: {}, positioning: {}, stopEvent: { type: Boolean, default: true }, insertFirst: { type: Boolean, default: true }, autoPan: { type: [Boolean, Object] }, className: {} }, emits: ["change", "error", "propertychange", "change:element", "change:map", "change:offset", "change:position", "change:positioning"], setup(__props, { expose: __expose }) { const props = __props; const map = vue.inject("map"); const htmlContent = vue.ref(); const properties = usePropsAsObjectProperties(props); const overlay = vue.shallowRef(new Overlay(properties)); useOpenLayersEvents(overlay, [ "change:element", "change:map", "change:offset", "change:position", "change:positioning" ]); const getOffset = () => overlay.value.getOffset(); const getPosition = () => overlay.value.getPosition(); const getPositioning = () => overlay.value.getPositioning(); const panIntoView = (optPanIntoViewOptions) => overlay.value.panIntoView(optPanIntoViewOptions); const setElement = (element) => overlay.value.setElement(element); const setOffset = (offset) => overlay.value.setOffset(offset); const setPosition = (position) => overlay.value.setPosition(position); const setPositioning = (positioning) => overlay.value.setPositioning(positioning); function removeOverlay(ov) { const removed = map?.removeOverlay(ov); if (!removed) { console.warn("couldn't find matching overlay to remove", overlay.value); } } vue.onMounted(() => { map?.addOverlay(overlay.value); }); vue.onUnmounted(() => removeOverlay(overlay.value)); vue.watch( () => properties, (newValue) => { for (const key in newValue) { const keyInObj = key; if (newValue[keyInObj] !== void 0) { overlay.value.set(key, newValue[keyInObj]); } } }, { deep: true } ); vue.watchEffect( () => { setElement(htmlContent.value); }, { flush: "post" } ); __expose({ overlay, htmlContent, getOffset, getPosition, getPositioning, panIntoView, setElement, setOffset, setPosition, setPositioning }); return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", { ref_key: "htmlContent", ref: htmlContent }, [ vue.renderSlot(_ctx.$slots, "default", { position: _ctx.position }) ], 512); }; } }); function globals(defs2) { defs2("EPSG:4326", "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees"); defs2("EPSG:4269", "+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees"); defs2("EPSG:3857", "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"); for (var i2 = 1; i2 <= 60; ++i2) { defs2("EPSG:" + (32600 + i2), "+proj=utm +zone=" + i2 + " +datum=WGS84 +units=m"); defs2("EPSG:" + (32700 + i2), "+proj=utm +zone=" + i2 + " +south +datum=WGS84 +units=m"); } defs2.WGS84 = defs2["EPSG:4326"]; defs2["EPSG:3785"] = defs2["EPSG:3857"]; defs2.GOOGLE = defs2["EPSG:3857"]; defs2["EPSG:900913"] = defs2["EPSG:3857"]; defs2["EPSG:102113"] = defs2["EPSG:3857"]; } var PJD_3PARAM = 1; var PJD_7PARAM = 2; var PJD_GRIDSHIFT = 3; var PJD_WGS84 = 4; var PJD_NODATUM = 5; var SRS_WGS84_SEMIMAJOR = 6378137; var SRS_WGS84_SEMIMINOR = 6356752314e-3; var SRS_WGS84_ESQUARED = 0.0066943799901413165; var SEC_TO_RAD = 484813681109536e-20; var HALF_PI = Math.PI / 2; var SIXTH = 0.16666666666666666; var RA4 = 0.04722222222222222; var RA6 = 0.022156084656084655; var EPSLN = 1e-10; var D2R$1 = 0.017453292519943295; var R2D = 57.29577951308232; var FORTPI = Math.PI / 4; var TWO_PI = Math.PI * 2; var SPI = 3.14159265359; var primeMeridian = {}; primeMeridian.greenwich = 0; primeMeridian.lisbon = -9.131906111111; primeMeridian.paris = 2.337229166667; primeMeridian.bogota = -74.080916666667; primeMeridian.madrid = -3.687938888889; primeMeridian.rome = 12.452333333333; primeMeridian.bern = 7.439583333333; primeMeridian.jakarta = 106.807719444444; primeMeridian.ferro = -17.666666666667; primeMeridian.brussels = 4.367975; primeMeridian.stockholm = 18.058277777778; primeMeridian.athens = 23.7163375; primeMeridian.oslo = 10.722916666667; const units = { mm: { to_meter: 1e-3 }, cm: { to_meter: 0.01 }, ft: { to_meter: 0.3048 }, "us-ft": { to_meter: 1200 / 3937 }, fath: { to_meter: 1.8288 }, kmi: { to_meter: 1852 }, "us-ch": { to_meter: 20.1168402336805 }, "us-mi": { to_meter: 1609.34721869444 }, km: { to_meter: 1e3 }, "ind-ft": { to_meter: 0.30479841 }, "ind-yd": { to_meter: 0.91439523 }, mi: { to_meter: 1609.344 }, yd: { to_meter: 0.9144 }, ch: { to_meter: 20.1168 }, link: { to_meter: 0.201168 }, dm: { to_meter: 0.1 }, in: { to_meter: 0.0254 }, "ind-ch": { to_meter: 20.11669506 }, "us-in": { to_meter: 0.025400050800101 }, "us-yd": { to_meter: 0.914401828803658 } }; var ignoredChar = /[\s_\-\/\(\)]/g; function match(obj, key) { if (obj[key]) { return obj[key]; } var keys = Object.keys(obj); var lkey = key.toLowerCase().replace(ignoredChar, ""); var i2 = -1; var testkey, processedKey; while (++i2 < keys.length) { testkey = keys[i2]; processedKey = testkey.toLowerCase().replace(ignoredChar, ""); if (processedKey === lkey) { return obj[testkey]; } } } function projStr(defData) { var self2 = {}; var paramObj = defData.split("+").map(function(v2) { return v2.trim(); }).filter(function(a2) { return a2; }).reduce(function(p2, a2) { var split = a2.split("="); split.push(true); p2[split[0].toLowerCase()] = split[1]; return p2; }, {}); var paramName, paramVal, paramOutname; var params2 = { proj: "projName", datum: "datumCode", rf: function(v2) { self2.rf = parseFloat(v2); }, lat_0: function(v2) { self2.lat0 = v2 * D2R$1; }, lat_1: function(v2) { self2.lat1 = v2 * D2R$1; }, lat_2: function(v2) { self2.lat2 = v2 * D2R$1; }, lat_ts: function(v2) { self2.lat_ts = v2 * D2R$1; }, lon_0: function(v2) { self2.long0 = v2 * D2R$1; }, lon_1: function(v2) { self2.long1 = v2 * D2R$1; }, lon_2: function(v2) { self2.long2 = v2 * D2R$1; }, alpha: function(v2) { self2.alpha = parseFloat(v2) * D2R$1; }, gamma: function(v2) { self2.rectified_grid_angle = parseFloat(v2) * D2R$1; }, lonc: function(v2) { self2.longc = v2 * D2R$1; }, x_0: function(v2) { self2.x0 = parseFloat(v2); }, y_0: function(v2) { self2.y0 = parseFloat(v2); }, k_0: function(v2) { self2.k0 = parseFloat(v2); }, k: function(v2) { self2.k0 = parseFloat(v2); }, a: function(v2) { self2.a = parseFloat(v2); }, b: function(v2) { self2.b = parseFloat(v2); }, r: function(v2) { self2.a = self2.b = parseFloat(v2); }, r_a: function() { self2.R_A = true; }, zone: function(v2) { self2.zone = parseInt(v2, 10); }, south: function() { self2.utmSouth = true; }, towgs84: function(v2) { self2.datum_params = v2.split(",").map(function(a2) { return parseFloat(a2); }); }, to_meter: function(v2) { self2.to_meter = parseFloat(v2); }, units: function(v2) { self2.units = v2; var unit = match(units, v2); if (unit) { self2.to_meter = unit.to_meter; } }, from_greenwich: function(v2) { self2.from_greenwich = v2 * D2R$1; }, pm: function(v2) { var pm = match(primeMeridian, v2); self2.from_greenwich = (pm ? pm : parseFloat(v2)) * D2R$1; }, nadgrids: function(v2) { if (v2 === "@null") { self2.datumCode = "none"; } else { self2.nadgrids = v2; } }, axis: function(v2) { var legalAxis = "ewnsud"; if (v2.length === 3 && legalAxis.indexOf(v2.substr(0, 1)) !== -1 && legalAxis.indexOf(v2.substr(1, 1)) !== -1 && legalAxis.indexOf(v2.substr(2, 1)) !== -1) { self2.axis = v2; } }, approx: function() { self2.approx = true; } }; for (paramName in paramObj) { paramVal = paramObj[paramName]; if (paramName in params2) { paramOutname = params2[paramName]; if (typeof paramOutname === "function") { paramOutname(paramVal); } else { self2[paramOutname] = paramVal; } } else { self2[paramName] = paramVal; } } if (typeof self2.datumCode === "string" && self2.datumCode !== "WGS84") { self2.datumCode = self2.datumCode.toLowerCase(); } return self2; } class PROJJSONBuilderBase { static getId(node) { const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID"); if (idNode && idNode.length >= 3) { return { authority: idNode[1], code: parseInt(idNode[2], 10) }; } return null; } static convertUnit(node, type = "unit") { if (!node || node.length < 3) { return { type, name: "unknown", conversion_factor: null }; } const name = node[1]; const conversionFactor = parseFloat(node[2]) || null; const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID"); const id = idNode ? { authority: idNode[1], code: parseInt(idNode[2], 10) } : null; return { type, name, conversion_factor: conversionFactor, id }; } static convertAxis(node) { const name = node[1] || "Unknown"; let direction; const abbreviationMatch = name.match(/^\((.)\)$/); if (abbreviationMatch) { const abbreviation = abbreviationMatch[1].toUpperCase(); if (abbreviation === "E") direction = "east"; else if (abbreviation === "N") direction = "north"; else if (abbreviation === "U") direction = "up"; else throw new Error(`Unknown axis abbreviation: ${abbreviation}`); } else { direction = node[2] ? node[2].toLowerCase() : "unknown"; } const orderNode = node.find((child) => Array.isArray(child) && child[0] === "ORDER"); const order = orderNode ? parseInt(orderNode[1], 10) : null; const unitNode = node.find( (child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT") ); const unit = this.convertUnit(unitNode); return { name, direction, // Use the valid PROJJSON direction value unit, order }; } static extractAxes(node) { return node.filter((child) => Array.isArray(child) && child[0] === "AXIS").map((axis) => this.convertAxis(axis)).sort((a2, b2) => (a2.order || 0) - (b2.order || 0)); } static convert(node, result = {}) { switch (node[0]) { case "PROJCRS": result.type = "ProjectedCRS"; result.name = node[1]; result.base_crs = node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS")) : null; result.conversion = node.find((child) => Array.isArray(child) && child[0] === "CONVERSION") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "CONVERSION")) : null; const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS"); if (csNode) { result.coordinate_system = { type: csNode[1], axis: this.extractAxes(node) }; } const lengthUnitNode = node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT"); if (lengthUnitNode) { const unit2 = this.convertUnit(lengthUnitNode); result.coordinate_system.unit = unit2; } result.id = this.getId(node); break; case "BASEGEOGCRS": case "GEOGCRS": result.type = "GeographicCRS"; result.name = node[1]; const datumOrEnsembleNode = node.find( (child) => Array.isArray(child) && (child[0] === "DATUM" || child[0] === "ENSEMBLE") ); if (datumOrEnsembleNode) { const datumOrEnsemble = this.convert(datumOrEnsembleNode); if (datumOrEnsembleNode[0] === "ENSEMBLE") { result.datum_ensemble = datumOrEnsemble; } else { result.datum = datumOrEnsemble; } const primem = node.find((child) => Array.isArray(child) && child[0] === "PRIMEM"); if (primem && primem[1] !== "Greenwich") { datumOrEnsemble.prime_meridian = { name: primem[1], longitude: parseFloat(primem[2]) }; } } result.coordinate_system = { type: "ellipsoidal", axis: this.extractAxes(node) }; result.id = this.getId(node); break; case "DATUM": result.type = "GeodeticReferenceFrame"; result.name = node[1]; result.ellipsoid = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID")) : null; break; case "ENSEMBLE": result.type = "DatumEnsemble"; result.name = node[1]; result.members = node.filter((child) => Array.isArray(child) && child[0] === "MEMBER").map((member) => ({ type: "DatumEnsembleMember", name: member[1], id: this.getId(member) // Extract ID as { authority, code } })); const accuracyNode = node.find((child) => Array.isArray(child) && child[0] === "ENSEMBLEACCURACY"); if (accuracyNode) { result.accuracy = parseFloat(accuracyNode[1]); } const ellipsoidNode = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID"); if (ellipsoidNode) { result.ellipsoid = this.convert(ellipsoidNode); } result.id = this.getId(node); break; case "ELLIPSOID": result.type = "Ellipsoid"; result.name = node[1]; result.semi_major_axis = parseFloat(node[2]); result.inverse_flattening = parseFloat(node[3]); node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT"), result) : null; break; case "CONVERSION": result.type = "Conversion"; result.name = node[1]; result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null; result.parameters = node.filter((child) => Array.isArray(child) && child[0] === "PARAMETER").map((param) => this.convert(param)); break; case "METHOD": result.type = "Method"; result.name = node[1]; result.id = this.getId(node); break; case "PARAMETER": result.type = "Parameter"; result.name = node[1]; result.value = parseFloat(node[2]); result.unit = this.convertUnit( node.find( (child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT") ) ); result.id = this.getId(node); break; case "BOUNDCRS": result.type = "BoundCRS"; const sourceCrsNode = node.find((child) => Array.isArray(child) && child[0] === "SOURCECRS"); if (sourceCrsNode) { const sourceCrsContent = sourceCrsNode.find((child) => Array.isArray(child)); result.source_crs = sourceCrsContent ? this.convert(sourceCrsContent) : null; } const targetCrsNode = node.find((child) => Array.isArray(child) && child[0] === "TARGETCRS"); if (targetCrsNode) { const targetCrsContent = targetCrsNode.find((child) => Array.isArray(child)); result.target_crs = targetCrsContent ? this.convert(targetCrsContent) : null; } const transformationNode = node.find((child) => Array.isArray(child) && child[0] === "ABRIDGEDTRANSFORMATION"); if (transformationNode) { result.transformation = this.convert(transformationNode); } else { result.transformation = null; } break; case "ABRIDGEDTRANSFORMATION": result.type = "Transformation"; result.name = node[1]; result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null; result.parameters = node.filter((child) => Array.isArray(child) && (child[0] === "PARAMETER" || child[0] === "PARAMETERFILE")).map((param) => { if (param[0] === "PARAMETER") { return this.convert(param); } else if (param[0] === "PARAMETERFILE") { return { name: param[1], value: param[2], id: { "authority": "EPSG", "code": 8656 } }; } }); if (result.parameters.length === 7) { const scaleDifference = result.parameters[6]; if (scaleDifference.name === "Scale difference") { scaleDifference.value = Math.round((scaleDifference.value - 1) * 1e12) / 1e6; } } result.id = this.getId(node); break; case "AXIS": if (!result.coordinate_system) { result.coordinate_system = { type: "unspecified", axis: [] }; } result.coordinate_system.axis.push(this.convertAxis(node)); break; case "LENGTHUNIT": const unit = this.convertUnit(node, "LinearUnit"); if (result.coordinate_system && result.coordinate_system.axis) { result.coordinate_system.axis.forEach((axis) => { if (!axis.unit) { axis.unit = unit; } }); } if (unit.conversion_factor && unit.conversion_factor !== 1) { if (result.semi_major_axis) { result.semi_major_axis = { value: result.semi_major_axis, unit }; } } break; default: result.keyword = node[0]; break; } return result; } } class PROJJSONBuilder2015 extends PROJJSONBuilderBase { static convert(node, result = {}) { super.convert(node, result); if (result.coordinate_system && result.coordinate_system.subtype === "Cartesian") { delete result.coordinate_system; } if (result.usage) { delete result.usage; } return result; } } class PROJJSONBuilder2019 extends PROJJSONBuilderBase { static convert(node, result = {}) { super.convert(node, result); const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS"); if (csNode) { result.coordinate_system = { subtype: csNode[1], axis: this.extractAxes(node) }; } const usageNode = node.find((child) => Array.isArray(child) && child[0] === "USAGE"); if (usageNode) { const scope = usageNode.find((child) => Array.isArray(child) && child[0] === "SCOPE"); const area = usageNode.find((child) => Array.isArray(child) && child[0] === "AREA"); const bbox = usageNode.find((child) => Array.isArray(child) && child[0] === "BBOX"); result.usage = {}; if (scope) { result.usage.scope = scope[1]; } if (area) { result.usage.area = area[1]; } if (bbox) { result.usage.bbox = bbox.slice(1); } } return result; } } function detectWKT2Version(root) { if (root.find((child) => Array.isArray(child) && child[0] === "USAGE")) { return "2019"; } if (root.find((child) => Array.isArray(child) && child[0] === "CS")) { return "2015"; } if (root[0] === "BOUNDCRS" || root[0] === "PROJCRS" || root[0] === "GEOGCRS") { return "2015"; } return "2015"; } function buildPROJJSON(root) { const version = detectWKT2Version(root); const builder = version === "2019" ? PROJJSONBuilder2019 : PROJJSONBuilder2015; return builder.convert(root); } function detectWKTVersion(wkt2) { const normalizedWKT = wkt2.toUpperCase(); if (normalizedWKT.includes("PROJCRS") || normalizedWKT.includes("GEOGCRS") || normalizedWKT.includes("BOUNDCRS") || normalizedWKT.includes("VERTCRS") || normalizedWKT.includes("LENGTHUNIT") || normalizedWKT.includes("ANGLEUNIT") || normalizedWKT.includes("SCALEUNIT")) { return "WKT2"; } if (normalizedWKT.includes("PROJCS") || normalizedWKT.includes("GEOGCS") || normalizedWKT.includes("LOCAL_CS") || normalizedWKT.includes("VERT_CS") || normalizedWKT.includes("UNIT")) { return "WKT1"; } return "WKT1"; } var NEUTRAL = 1; var KEYWORD = 2; var NUMBER = 3; var QUOTED = 4; var AFTERQUOTE = 5; var ENDED = -1; var whitespace = /\s/; var latin = /[A-Za-z]/; var keyword = /[A-Za-z84_]/; var endThings = /[,\]]/; var digets = /[\d\.E\-\+]/; function Parser(text) { if (typeof text !== "string") { throw new Error("not a string"); } this.text = text.trim(); this.level = 0; this.place = 0; this.root = null; this.stack = []; this.currentObject = null; this.state = NEUTRAL; } Parser.prototype.readCharicter = function() { var char = this.text[this.place++]; if (this.state !== QUOTED) { while (whitespace.test(char)) { if (this.place >= this.text.length) { return; } char = this.text[this.place++]; } } switch (this.state) { case NEUTRAL: return this.neutral(char); case KEYWORD: return this.keyword(char); case QUOTED: return this.quoted(char); case AFTERQUOTE: return this.afterquote(char); case NUMBER: return this.number(char); case ENDED: return; } }; Parser.prototype.afterquote = function(char) { if (char === '"') { this.word += '"'; this.state = QUOTED; return; } if (endThings.test(char)) { this.word = this.word.trim(); this.afterItem(char); return; } throw new Error(`havn't handled "` + char + '" in afterquote yet, index ' + this.place); }; Parser.prototype.afterItem = function(char) { if (char === ",") { if (this.word !== null) { this.currentObject.push(this.word); } this.word = null; this.state = NEUTRAL; return; } if (char === "]") { this.level--; if (this.word !== null) { this.currentObject.push(this.word); this.word = null; } this.state = NEUTRAL; this.currentObject = this.stack.pop(); if (!this.currentObject) { this.state = ENDED; } return; } }; Parser.prototype.number = function(char) { if (digets.test(char)) { this.word += char; return; } if (endThings.test(char)) { this.word = parseFloat(this.word); this.afterItem(char); return; } throw new Error(`havn't handled "` + char + '" in number yet, index ' + this.place); }; Parser.prototype.quoted = function(char) { if (char === '"') { this.state = AFTERQUOTE; return; } this.word += char; return; }; Parser.prototype.keyword = function(char) { if (keyword.test(char)) { this.word += char; return; } if (char === "[") { var newObjects = []; newObjects.push(this.word); this.level++; if (this.root === null) { this.root = newObjects; } else { this.currentObject.push(newObjects); } this.stack.push(this.currentObject); this.currentObject = newObjects; this.state = NEUTRAL; return; } if (endThings.test(char)) { this.afterItem(char); return; } throw new Error(`havn't handled "` + char + '" in keyword yet, index ' + this.place); }; Parser.prototype.neutral = function(char) { if (latin.test(char)) { this.word = char; this.state = KEYWORD; return; } if (char === '"') { this.word = ""; this.state = QUOTED; return; } if (digets.test(char)) { this.word = char; this.state = NUMBER; return; } if (endThings.test(char)) { this.afterItem(char); return; } throw new Error(`havn't handled "` + char + '" in neutral yet, index ' + this.place); }; Parser.prototype.output = function() { while (this.place < this.text.length) { this.readCharicter(); } if (this.state === ENDED) { return this.root; } throw new Error('unable to parse string "' + this.text + '". State is ' + this.state); }; function parseString(txt) { var parser = new Parser(txt); return parser.output(); } function mapit(obj, key, value) { if (Array.isArray(key)) { value.unshift(key); key = null; } var thing = key ? {} : obj; var out = value.reduce(function(newObj, item) { sExpr(item, newObj); return newObj; }, thing); if (key) { obj[key] = out; } } function sExpr(v2, obj) { if (!Array.isArray(v2)) { obj[v2] = true; return; } var key = v2.shift(); if (key === "PARAMETER") { key = v2.shift(); } if (v2.length === 1) { if (Array.isArray(v2[0])) { obj[key] = {}; sExpr(v2[0], obj[key]); return; } obj[key] = v2[0]; return; } if (!v2.length) { obj[key] = true; return; } if (key === "TOWGS84") { obj[key] = v2; return; } if (key === "AXIS") { if (!(key in obj)) { obj[key] = []; } obj[key].push(v2); return; } if (!Array.isArray(key)) { obj[key] = {}; } var i2; switch (key) { case "UNIT": case "PRIMEM": case "VERT_DATUM": obj[key] = { name: v2[0].toLowerCase(), convert: v2[1] }; if (v2.length === 3) { sExpr(v2[2], obj[key]); } return; case "SPHEROID": case "ELLIPSOID": obj[key] = { name: v2[0], a: v2[1], rf: v2[2] }; if (v2.length === 4) { sExpr(v2[3], obj[key]); } return; case "EDATUM": case "ENGINEERINGDATUM": case "LOCAL_DATUM": case "DATUM": case "VERT_CS": case "VERTCRS": case "VERTICALCRS": v2[0] = ["name", v2[0]]; mapit(obj, key, v2); return; case "COMPD_CS": case "COMPOUNDCRS": case "FITTED_CS": // the followings are the crs defined in // https://github.com/proj4js/proj4js/blob/1da4ed0b865d0fcb51c136090569210cdcc9019e/lib/parseCode.js#L11 case "PROJECTEDCRS": case "PROJCRS": case "GEOGCS": case "GEOCCS": case "PROJCS": case "LOCAL_CS": case "GEODCRS": case "GEODETICCRS": case "GEODETICDATUM": case "ENGCRS": case "ENGINEERINGCRS": v2[0] = ["name", v2[0]]; mapit(obj, key, v2); obj[key].type = key; return; default: i2 = -1; while (++i2 < v2.length) { if (!Array.isArray(v2[i2])) { return sExpr(v2, obj[key]); } } return mapit(obj, key, v2); } } var D2R = 0.017453292519943295; function d2r(input) { return input * D2R; } function applyProjectionDefaults(wkt2) { const normalizedProjName = (wkt2.projName || "").toLowerCase().replace(/_/g, " "); if (!wkt2.long0 && wkt2.longc && (normalizedProjName === "albers conic equal area" || normalizedProjName === "lambert azimuthal equal area")) { wkt2.long0 = wkt2.longc; } if (!wkt2.lat_ts && wkt2.lat1 && (normalizedProjName === "stereographic south pole" || normalizedProjName === "polar stereographic (variant b)")) { wkt2.lat0 = d2r(wkt2.lat1 > 0 ? 90 : -90); wkt2.lat_ts = wkt2.lat1; delete wkt2.lat1; } else if (!wkt2.lat_ts && wkt2.lat0 && (normalizedProjName === "polar stereographic" || normalizedProjName === "polar stereographic (variant a)")) { wkt2.lat_ts = wkt2.lat0; wkt2.lat0 = d2r(wkt2.lat0 > 0 ? 90 : -90); delete wkt2.lat1; } } function processUnit(unit) { let result = { units: null, to_meter: void 0 }; if (typeof unit === "string") { result.units = unit.toLowerCase(); if (result.units === "metre") { result.units = "meter"; } if (result.units === "meter") { result.to_meter = 1; } } else if (unit && unit.name) { result.units = unit.name.toLowerCase(); if (result.units === "metre") { result.units = "meter"; } result.to_meter = unit.conversion_factor; } return result; } function toValue(valueOrObject) { if (typeof valueOrObject === "object") { return valueOrObject.value * valueOrObject.unit.conversion_factor; } return valueOrObject; } function calculateEllipsoid(value, result) { if (value.ellipsoid.radius) { result.a = value.ellipsoid.radius; result.rf = 0; } else { result.a = toValue(value.ellipsoid.semi_major_axis); if (value.ellipsoid.inverse_flattening !== void 0) { result.rf = value.ellipsoid.inverse_flattening; } else if (value.ellipsoid.semi_major_axis !== void 0 && value.ellipsoid.semi_minor_axis !== void 0) { result.rf = result.a / (result.a - toValue(value.ellipsoid.semi_minor_axis)); } } } function transformPROJJSON(projjson, result = {}) { if (!projjson || typeof projjson !== "object") { return projjson; } if (projjson.type === "BoundCRS") { transformPROJJSON(projjson.source_crs, result); if (projjson.transformation) { if (projjson.transformation.method && projjson.transformation.method.name === "NTv2") { result.nadgrids = projjson.transformation.parameters[0].value; } else { result.datum_params = projjson.transformation.parameters.map((param) => param.value); } } return result; } Object.keys(projjson).forEach((key) => { const value = projjson[key]; if (value === null) { return; } switch (key) { case "name": if (result.srsCode) { break; } result.name = value; result.srsCode = value; break; case "type": if (value === "GeographicCRS") { result.projName = "longlat"; } else if (value === "ProjectedCRS" && projjson.conversion && projjson.conversion.method) { result.projName = projjson.conversion.method.name; } break; case "datum": case "datum_ensemble": if (value.ellipsoid) { result.ellps = value.ellipsoid.name; calculateEllipsoid(value, result); } if (value.prime_meridian) { result.from_greenwich = value.prime_meridian.longitude * Math.PI / 180; } break; case "ellipsoid": result.ellps = value.name; calculateEllipsoid(value, result); break; case "prime_meridian": result.long0 = (value.longitude || 0) * Math.PI / 180; break; case "coordinate_system": if (value.axis) { result.axis = value.axis.map((axis) => { const direction = axis.direction; if (direction === "east") return "e"; if (direction === "north") return "n"; if (direction === "west") return "w"; if (direction === "south") return "s"; throw new Error(`Unknown axis direction: ${direction}`); }).join("") + "u"; if (value.unit) { const { units: units2, to_meter } = processUnit(value.unit); result.units = units2; result.to_meter = to_meter; } else if (value.axis[0] && value.axis[0].unit) { const { units: units2, to_meter } = processUnit(value.axis[0].unit); result.units = units2; result.to_meter = to_meter; } } break; case "id": if (value.authority && value.code) { result.title = value.authority + ":" + value.code; } break; case "conversion": if (value.method && value.method.name) { result.projName = value.method.name; } if (value.parameters) { value.parameters.forEach((param) => { const paramName = param.name.toLowerCase().replace(/\s+/g, "_"); const paramValue = param.value; if (param.unit && param.unit.conversion_factor) { result[paramName] = paramValue * param.unit.conversion_factor; } else if (param.unit === "degree") { result[paramName] = paramValue * Math.PI / 180; } else { result[paramName] = paramValue; } }); } break; case "unit": if (value.name) { result.units = value.name.toLowerCase(); if (result.units === "metre") { result.units = "meter"; } } if (value.conversion_factor) { result.to_meter = value.conversion_factor; } break; case "base_crs": transformPROJJSON(value, result); result.datumCode = value.id ? value.id.authority + "_" + value.id.code : value.name; break; } }); if (result.latitude_of_false_origin !== void 0) { result.lat0 = result.latitude_of_false_origin; } if (result.longitude_of_false_origin !== void 0) { result.long0 = result.longitude_of_false_origin; } if (result.latitude_of_standard_parallel !== void