Skip to content

Plugins Guide

If you like to add a specific component wrapper based on an external library deviating from ol or ol-ext, please follow this guide.

Source Plugins

If you like to add a specific map source (e. g. for vector or tile data), you can create your own component and integrate it with vue3-openlayers. Therefore the source component should be placed within a layer component. This allows you to inject either tileLayer, imageLayer, vectorLayer or heatmapLayer from the parent component. It gives you the ability to apply your source on this layer.

The example below demonstrates how a source called FooSource could be implemented:

vue
<template>
  <div v-if="false"></div>
</template>

<script setup lang="ts">
import type { Ref } from "vue";
import { inject, watch, onMounted, onUnmounted, shallowRef } from "vue";

// import the source to be wrapped in a component.
import FooSource, { type Options } from "foo-source";

// import the layer type, the source is applied to.
// It is defined by the parent component and injected below.
import type TileLayer from "ol/layer/Tile";
// import type ImageLayer from "ol/layer/Image";
// import type VectorLayer from "ol/layer/Vector";

// Define the options, the wrapper component can receive.
// In best case, they will be passed 1:1 from the original source.
const props = withDefaults(defineProps<Options>(), {
  // you can define some default values here
});

// Inject the reference to the layer, the source will be applied to.
// The provide comes from a parent component
const layer = inject<Ref<TileLayer<FooSource>> | null>("tileLayer");
// const layer = inject<ImageLayer<FooSource> | null>("imageLayer");
// const layer = inject<Ref<VectorLayer<FooSource>> | null>("vectorLayer");
// const layer = inject<Ref<HeatmapLayer> | null>("heatmapLayer");

// Store a shallowRef of the Source, so it can be watched for changes.
const source = shallowRef(new FooSource(props));

// Watch for source changes and re-apply the source to the layer.
watch(source, () => {
  layer?.value?.setSource(source.value);
});

// Watch for layer changes and re-apply the source to the layer.
watch(layer, () => {
  layer?.value?.setSource(source.value);
});

// Apply the source once the component is mounted.
onMounted(() => {
  layer?.value?.setSource(source.value);
});

// Cleanup when component is destroyed.
onUnmounted(() => {
  layer?.value?.setSource(null);
});

// Expose the layer and source, so it can be used as a `ref=""` on the element
defineExpose({
  layer,
  source,
});
</script>

For a live example, please checkout this demo.

Animation Plugins

The composable useAnimation can and should be used to wrap features animations in a vue component. It will inject needed layers and connect the animation with it.

vue
<template>
  <slot></slot>
</template>

<script setup lang="ts">
import MyAnimation from "./my-animation";
import useAnimation from "@/composables/useAnimation";

const props = withDefaults(
  defineProps<{
    speed?: number;
    // ...
   }>(),
  {
    speed: 0,
  },
);

const exposed = useAnimation(MyAnimation, props);

defineExpose(exposed);
</script>

MapControl Plugins

The composable useControl can and should be used to wrap features map controls in a vue component. It handles adding / removing a control to the map or a control bar.

vue
<template>
  <div v-if="false"></div>
</template>
<script setup lang="ts">
import { useAttrs } from "vue";
import useControl from "@/composables/useControl";
import MyControl from "./my-control";

const props = withDefaults(
  defineProps<{
    className?: string;
    // ...
  }>(),
  {
    className: "ol-my-control",
  },
);

const attrs = useAttrs();
const { control } = useControl(MyControl, props, attrs);

defineExpose({
  control,
});
</script>

Geometry Plugins

The composable useGeometry can and should be used to wrap geometries in a vue component. It injects the parent feature component and applies a geometry. It also watches for geometry changes and updates the features.

vue
<template>
  <div v-if="false"></div>
</template>

<script setup lang="ts">
import MyGeometry from "./my-geometry";
import useGeometry from "@/composables/useGeometry";

const props = withDefaults(
  defineProps<{
    someProperty: number[];
  }>(),
  {},
);

const geometry = useGeometry(MyGeometry, props);

defineExpose({
  geometry,
});
</script>

Other Composables

The following composables are exposed to support 3rd-party libs.

usePropsAsObjectProperties

This composable is used to proxy vue component props and:

  • log them in debug mode
  • make them reactive
  • convert prop styles int style since style cannot be used as HTML attribute since it conflicts wit native style attribute.
ts
const props = withDefaults(defineProps<{
  title: string;
  styles: string[]
}>(), {
  styles: []
});

const properties = usePropsAsObjectProperties(props);
// properties.styles is undefined
// properties.style is of type string[]

useOpenLayersEvents

This composable is used to be able to pass-through all original events to the current component.

ts
// ...
import { useOpenLayersEvents } from "@/composables/useOpenLayersEvents";

// prevent warnings caused by event pass-through via useOpenLayersEvents composable
defineOptions({
  inheritAttrs: false,
});

useOpenLayersEvents(draw, ["drawstart", "drawend"]);