Skip to content

Commit

Permalink
Adds minimal split logic for loading vector tiles from a WMTS
Browse files Browse the repository at this point in the history
  • Loading branch information
bazottie committed Dec 6, 2024
1 parent 3e1f869 commit 2e37831
Show file tree
Hide file tree
Showing 7 changed files with 560 additions and 152 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@
:opacity="layer.opacity"
/>

<map-layer-wmts
v-for="(layer, index) in wmtsLayers"
:key="layer.id"
:before="wmsLayerIds[index - 1]"
:options="layer"
:opacity="layer.opacity"
/>
<mapbox-scale-control />
<map-zoom :extent="zoomExtent" />
<MapMouseMove @mousemove="onMouseMove" />
Expand All @@ -117,6 +124,7 @@
import { mapActions, mapGetters } from 'vuex'
import AppShell from './components/AppShell/AppShell'
import MapLayer from './components/MapComponents/MapLayer.js'
import MapLayerWmts from './components/MapComponents/MapLayerWmts.js'
import MapZoom from './components/MapComponents/MapZoom.js'
import MapLayerInfo from './components/MapComponents/MapLayerInfo'
import MapboxDrawControl from '~/components/MapboxDrawControl/MapboxDrawControl'
Expand Down Expand Up @@ -147,6 +155,7 @@
components: {
AppShell,
MapLayer,
MapLayerWmts,
MapZoom,
MapLayerInfo,
MapboxDrawControl,
Expand Down Expand Up @@ -189,7 +198,7 @@
computed: {
...mapGetters('app', [ 'viewerName', 'appNavigationOpen', 'appNavigationWidth', 'viewerUserAgreement', 'viewerPrivacyStatement', 'acknowledgments' ]),
...mapGetters('map', [ 'drawnFeatures', 'drawMode', 'wmsLayerIds', 'wmsLayers', 'filteredLayerId', 'mapCenter', 'mapZoom', 'zoomExtent', 'selectedLayerForSelection', 'activeFlattenedLayers', 'wmsApiLayer', 'multipleSelection' ]),
...mapGetters('map', [ 'drawnFeatures', 'drawMode', 'wmsLayerIds', 'wmsLayers','wmtsLayers', 'wmtsSources', 'filteredLayerId', 'mapCenter', 'mapZoom', 'zoomExtent', 'selectedLayerForSelection', 'activeFlattenedLayers', 'wmsApiLayer', 'multipleSelection' ]),
...mapGetters('data', [ 'timeExtent', 'flattenedLayers', 'displayLayers' ]),
formattedTimeExtent() {
return this.formatTimeExtent(this.timeExtent)
Expand Down
157 changes: 157 additions & 0 deletions src/components/MapComponents/MapLayerWmts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { isNil } from "~/lib/helpers.js";

export default {
name: "v-mapbox-layer",

inject: [ "getMap" ],

render: () => null,

props: {
options: {
type: Object,
default: () => ({}),
},

// Allows to place a layer before another
before: {
type: String,
default: undefined,
},

clickable: {
type: Boolean,
default: false,
},

opacity: {
type: Number,
required: false,
validator: (val) => val >= 0 && val <= 1,
},
},

data: () => ({
isInitialized: false,
}),

methods: {
deferredMountedTo() {
if (!this.isInitialized) {
this.renderLayer();
this.isInitialized = true;
}
},

renderLayer() {
this.removeLayer();
this.addLayer();
},

addLayer() {
const map = this.getMap();
if (this.before && map.getLayer(this.before)) {
map.addLayer(this.options.layer, this.before)
} else if (map.getLayer('gl-draw-polygon-fill-inactive.cold')) {
map.addLayer(this.options.layer, 'gl-draw-polygon-fill-inactive.cold')
} else {
map.addLayer(this.options.layer)
}

if (this.clickable) {
const layerId = this.options.layer.id;
map.on("click", layerId, this.clickFn);
map.on("mouseenter", layerId, this.mouseEnterFn);
map.on("mouseleave", layerId, this.mouseLeaveFn);
}


if (!isNil(this.opacity)) {
this.setOpacity();
}
},

removeSource() {
const map = this.getMap();
if (map) {
const sourceKey = this.options.source.key;
const source = map.getSource(sourceKey);
if (source) {
map.removeSource(sourceKey);
}
}
},

removeLayer() {
const map = this.getMap();
if (map) {
const layerId = this.options.layer.id;
const layer = map.getLayer(layerId);
if (layer) {
map.removeLayer(layerId);
if (this.clickable) {
map.off("click", layerId, this.clickFn);
map.off("mouseenter", layerId, this.mouseEnterFn);
map.off("mouseleave", layerId, this.mouseLeaveFn);
}
}
}
},

clickFn(e) {
this.$emit("click", e);
},

mouseEnterFn() {
const map = this.getMap();
map.getCanvas().style.cursor = "pointer";
},

mouseLeaveFn() {
const map = this.getMap();
map.getCanvas().style.cursor = "";
},

setOpacity() {
const map = this.getMap();
const { id, type } = this.options.layer;
map.setPaintProperty(id, `${ type }-opacity`, this.opacity);
},
},

mounted() {
const map = this.getMap();
// We can immediately initialize if we have the map ready

if (map) {
map.addSource(this.options.source.key, this.options.source);
this.renderLayer();
this.isInitialized = true;
}
},

destroyed() {
this.removeLayer();
this.removeSource();
},

watch: {
options: {
deep: true,
handler() {
this.renderLayer();
},
},

opacity() {
this.setOpacity();
},
before(onTopLayer) {
const map = this.getMap();
map.moveLayer(this.options.layer.id, onTopLayer);
if (!onTopLayer) {
map.moveLayer(this.options.layer.id, "gl-draw-polygon-fill-inactive.cold");
}
},
},
};
68 changes: 58 additions & 10 deletions src/lib/get-capabilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ export async function getWmsCapabilities(service) {

}

export async function getWmtsCapabilities(service) {
const servicePath = `${ service.origin }${ service.pathname }`;
const { data } = await axios(
`${ servicePath }?service=WMTS&request=GetCapabilities`
);
return new DOMParser().parseFromString(data, "text/xml");
}


export function getSupportedOutputFormats(type, capabilities) {

//wfs
Expand Down Expand Up @@ -137,19 +146,19 @@ export function isRasterLayer(type, capabilities, layer) {
return keywords.includes('GeoTIFF')
}

export function getLayerProperties(capabilities, layer) {
/**
* function that reads the wms capabilities response of the workpspace
* 1. find the given layer
* 2. extracts:
* -wmsVersion
* -bbox of layer
* -keywords (that contain the service type)
* -service type of layer (wfs or wcs)
* -time extent of layer
*
* * */

* 2. extracts:
* - wmsVersion
* - bbox of layer
* - keywords (that contain the service type)
* - service type of layer (wfs or wcs)
* - time extent of layer
* @param {Object} capabilities - XML response of capabilities
* @param {string} layer - layer name
*/
export function getLayerProperties(capabilities, layer) {
const wmsVersion = pipe(
() => capabilities.querySelector('WMS_Capabilities'),
el => el.getAttribute('version'),
Expand Down Expand Up @@ -201,4 +210,43 @@ export function getLayerProperties(capabilities, layer) {
return { serviceType, timeExtent, wmsVersion, bbox }
}

/**
* function that reads the wms capabilities response of the workpspace
* 1. find the given layer
* 2. extracts:
* - wmsVersion
* - bbox of layer
* - keywords (that contain the service type)
* - service type of layer (wfs or wcs)
* - time extent of layer
* @param {Object} capabilities - XML response of capabilities
* @param {('WMS'|'WMTS')} type - type of service
* @param {Object} layerObject - layer name
*/
export function getWmtsLayerProperties(capabilities, layerObject) {
const version = pipe(
() => capabilities.querySelector(`Capabilities`),
(el) => el.getAttribute("version")
)();
const workspaceLayer = layerObject.layer.split(":")
const layer = workspaceLayer.pop();
const workspace = workspaceLayer.pop();

const keywords = pipe(
() => [
capabilities.querySelector("KeywordList") ||
capabilities.querySelector("Keywords"),
],
getTags("Keyword"),
map(getTagContent)
)();

const serviceType = [ "features", "wfs", "FEATURES", "WFS" ].some((val) =>
keywords.includes(val)
)
? "wfs"
: [ "WCS", "GeoTIFF", "wcs" ].some((val) => keywords.includes(val))
? "wcs"
: null;
return { version, keywords, serviceType, workspace, layer };
}
Loading

0 comments on commit 2e37831

Please sign in to comment.