Skip to content

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

vue
<template>
  <ol-map
    :loadTilesWhileAnimating="true"
    :loadTilesWhileInteracting="true"
    style="height: 400px"
  >
    <ol-view
      ref="view"
      :center="center"
      :zoom="zoom"
      :projection="projection"
      :constrainRotation="16"
    />

    <ol-vector-layer background="#1a2b39" ref="vectorSourceRef">
      <ol-source-vector :url="url" :format="geoJson">
        <ol-style :overrideStyleFunction="styleFn"></ol-style>
      </ol-source-vector>
    </ol-vector-layer>

    <ol-interaction-dragbox
      :condition="shiftKeyOnly"
      @boxstart="log('boxstart', $event)"
      @boxdrag="log('boxdrag', $event)"
      @boxend="log('boxend', $event)"
      @boxcancel="log('boxcancel', $event)"
    ></ol-interaction-dragbox>
  </ol-map>
</template>

<script setup lang="ts">
import type { Feature } from "ol";
import { Fill, Style } from "ol/style";
import { shiftKeyOnly } from "ol/events/condition";
import { ref, inject } from "vue";
import type { DragBoxEvent } from "ol/interaction/DragBox";

const center = ref([0, 0]);
const projection = ref("EPSG:4326");
const zoom = ref(0);
const url = ref("https://openlayers.org/data/vector/ecoregions.json");
const format = inject("ol-format");
const geoJson = new format.GeoJSON();

function styleFn(feature: Feature) {
  return new Style({
    fill: new Fill({
      color: feature.get("COLOR_BIO") || "#eeeeee",
    }),
  });
}

function log(eventType: string, event: DragBoxEvent) {
  console.log(eventType, event);
}
</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:

  • You can use the { featureClass: Feature } option, when defining the ol-source-vector-tile format to Control the Type of Features visible in the Map
  • Turf is only Compatible with EPSG:4326. Openlayers uses EPSG:3857, so you need to convert between them.
vue
<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" :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 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).

background

  • Type: BackgroundColor

A css color, or a function called with a view resolution returning a css color.

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.