ol-vector-layer
ol-vector-layer can render vector from various backend services. It should be used with together with ol-source-vector component.
Usage
Example 1
Example below shows how you can use ol-vector-layer and ol-source-vector to render some vector features from remote backend.
Load features simply by providing url value and format GeoJSON
<template>
<ol-map
:loadTilesWhileAnimating="true"
:loadTilesWhileInteracting="true"
style="height: 400px"
>
<ol-view
ref="view"
:center="center"
:rotation="rotation"
:zoom="zoom"
:projection="projection"
/>
<ol-tile-layer>
<ol-source-osm />
</ol-tile-layer>
<ol-vector-layer>
<ol-source-vector :url="url" :format="geoJson"> </ol-source-vector>
</ol-vector-layer>
</ol-map>
</template>
<script setup>
import { ref, inject } from "vue";
const center = ref([0, 0]);
const projection = ref("EPSG:4326");
const zoom = ref(3);
const rotation = ref(0);
const url = ref("https://openlayers.org/data/vector/ecoregions.json");
const format = inject("ol-format");
const geoJson = new format.GeoJSON();
</script>
Example 2
The Example below shows how you can copy features from a ol-vector-tile-layer
to a ol-vector-layer
. It also visualizes how you can use the Turf library in combination with vue3-openlayers.
Important Notes:
<template>
<form>
<label for="bufferRadius">Buffer Radius:</label>
<input type="number" id="bufferRadius" v-model="bufferRadius" />
</form>
<ol-map
:loadTilesWhileAnimating="true"
:loadTilesWhileInteracting="true"
style="height: 400px"
@pointermove="hoverFeature"
@click="selectFeature"
ref="mapRef"
>
<ol-view ref="view" :center="center" :rotation="rotation" :zoom="zoom" />
<ol-vector-tile-layer class-name="feature-layer">
<ol-source-vector-tile :url="url" :format="mvtFormat" />
<ol-style>
<ol-style-stroke color="#2255ee" :width="1" />
</ol-style>
</ol-vector-tile-layer>
<ol-vector-layer>
<ol-source-vector :features="highlightedFeatures" />
<ol-style>
<ol-style-stroke color="#bb2233" :width="2" />
</ol-style>
</ol-vector-layer>
<ol-vector-layer>
<ol-source-vector :features="selectedFeatures" />
<ol-style>
<ol-style-stroke color="#bb2233" :width="2" />
</ol-style>
</ol-vector-layer>
<ol-vector-layer v-if="bound" class-name="bound">
<ol-source-vector :features="[bound]" />
<ol-style>
<ol-style-stroke color="#33dd99" :width="3" />
</ol-style>
</ol-vector-layer>
</ol-map>
</template>
<script setup lang="ts">
import buffer from "@turf/buffer";
import { lineString } from "@turf/helpers";
import { MapBrowserEvent } from "ol";
import Feature, { type FeatureLike } from "ol/Feature";
import type MapRef from "ol/Map.js";
import type { Coordinate } from "ol/coordinate";
import GeoJSON from "ol/format/GeoJSON";
import {
LineString,
MultiLineString,
MultiPoint,
MultiPolygon,
Point,
Polygon,
} from "ol/geom";
import type { Layer } from "ol/layer";
import { transform } from "ol/proj";
import { computed, inject, ref, watch } from "vue";
const format = inject("ol-format");
const mvtFormat = new format.MVT({ featureClass: Feature });
const mapRef = ref<{ map: MapRef } | null>(null);
const center = ref([943955.9456952971, 6356667.343082143]);
const zoom = ref(18);
const rotation = ref(0);
const url = ref(
"https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/tile/{z}/{y}/{x}.pbf",
);
const selectedFeatures = ref<FeatureLike[]>([]);
const highlightedFeatures = ref<FeatureLike[]>([]);
const bound = ref<FeatureLike>();
const bufferRadius = ref<number>(10);
const highlightingTemplate = computed<Coordinate[]>(() => {
// get flat coordinates from all selected geometries (e. g. [13.40, 52.52, 13.32, 51.43, ...])
const allFlatCoordinates: Coordinate = [];
selectedFeatures.value.forEach((feature) => {
const geometry = feature.getGeometry() as
| Point
| MultiPoint
| Polygon
| MultiPolygon
| LineString
| MultiLineString;
allFlatCoordinates.push(...geometry.getFlatCoordinates());
});
// map flat coordinates to Coordinate array (e. g. [[13.40, 52.52], [13.32, 51.43], [...]])
return allFlatCoordinates
.reduce<Coordinate[]>((accumulator, _, currentIndex, array) => {
if (currentIndex % 2 === 0) {
accumulator.push(array.slice(currentIndex, currentIndex + 2));
}
return accumulator;
}, [])
.map((c) => transform(c, "EPSG:3857", "EPSG:4326"));
});
/**
* Only handle click / hover for the layer with class name "feature-layer"
*/
function layerFilter(layerCandidate: Layer) {
return layerCandidate.getClassName().includes("feature-layer");
}
/**
* show hovered feature in separate layer
*/
function hoverFeature(event: MapBrowserEvent<PointerEvent>) {
const map = mapRef.value?.map;
if (!map) {
return;
}
const features = map.getFeaturesAtPixel(event.pixel, {
hitTolerance: 10,
layerFilter,
});
highlightedFeatures.value = features[0] ? [features[0]] : [];
}
/**
* select features and combine them when shift key is pressed
*/
function selectFeature(event: MapBrowserEvent<PointerEvent>) {
const map = mapRef.value?.map;
if (!map) {
return;
}
// reset selection when shift key isn't pressed
if (!event.originalEvent.shiftKey) {
selectedFeatures.value = [];
}
// store selected feature
const features = map.getFeaturesAtPixel(event.pixel, {
hitTolerance: 10,
layerFilter,
});
if (!features.length) {
return;
}
const feature = features[0];
const featureIndex = selectedFeatures.value.indexOf(feature);
if (featureIndex == -1) {
selectedFeatures.value.push(feature);
} else {
selectedFeatures.value.splice(featureIndex, 1);
}
}
watch([highlightingTemplate, bufferRadius], () => {
if (highlightingTemplate.value.length === 0) {
bound.value = undefined;
} else {
const line = lineString(highlightingTemplate.value);
const bufferedHull = buffer(line, bufferRadius.value, {
units: "meters",
});
bound.value = new GeoJSON().readFeature(bufferedHull, {
dataProjection: "EPSG:4326",
featureProjection: "EPSG:3857",
});
}
});
</script>
Properties
className
- Type:
string
- Default:
ol-layer
A CSS class name to set to the layer element.
opacity
- Type:
number
- Default:
1
Opacity (0, 1).
visible
- Type:
boolean
- Default:
true
Visibility.
extent
- Type:
Array
The bounding extent for layer rendering. The layer will not be rendered outside of this extent.
zIndex
- Type:
number
The z-index for layer rendering. At rendering time, the layers will be ordered, first by Z-index and then by position.
minResolution
- Type:
number
The minimum resolution (inclusive) at which this layer will be visible.
maxResolution
- Type:
number
The maximum resolution (exclusive) below which this layer will be visible.
minZoom
- Type:
number
The minimum view zoom level (exclusive) above which this layer will be visible.
maxZoom
- Type:
number
The maximum view zoom level (inclusive) at which this layer will be visible.
renderBuffer
- Type:
number
- Default:
100
The buffer in pixels around the viewport extent used by the renderer when getting features from the vector source for the rendering or hit-detection. Recommended value: the size of the largest symbol, line width or label.
updateWhileAnimating
- Type:
Boolean
- Default:
false
When set to true, feature batches will be recreated during animations. This means that no vectors will be shown clipped, but the setting will have a performance impact for large amounts of vector data. When set to false, batches will be recreated when no animation is active.
updateWhileInteracting
- Type:
Boolean
- Default:
false
When set to true, feature batches will be recreated during interactions. See also updateWhileAnimating.