In this part, we will show you how to add interactivity to the map by using OpenLayers and Vue.js. We will create a simple pop-up window that displays the feature’s attributes when clicked on the map and also highlight the feature on map.
To get full source code for this tutorial, click here.
To check the live demo for this tutorial, click here.
This blog post is the fourth part in OpenLayers-VueJS integration series. In part three, we implemented Legend for layers in layer panel.
In this tutorial, we have created a vue component that implements a popup with a table and pagination. It listens to a ‘singleclick’ event on an OpenLayers map and retrieves features at the clicked coordinates. The retrieved features’ properties are displayed in a q-table in the popup. The popup also has a pagination component which allows users to navigate through multiple features retrieved from the same click. The popup is added as an overlay to the OpenLayers map. When the popup is closed, its highlight layer, which is used to highlight the selected feature, is cleared.
OpenLayers VueJS integration series:
1. Integrating OpenLayers Map with VueJS: Create Map – Part 1
2. Integrating OpenLayers Map with VueJS: Create Layers Panel – Part 2
3. Integrating OpenLayers Map with VueJS: Create Implement Style and legend for vector layer – Part_3
4. Integrating OpenLayers Map With VueJS: Open Feature Information Popup On Click – Part 4
5. Integrating OpenLayers Map with VueJS: Recreating the project with Vite, Pinia and TypeScript-Part 5
1. Define Popup.vue component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<template> <div id="popup" class="ol-popup"> <a href="#" id="popup-closer" class="ol-popup-closer"></a> <div id="popup-content"> <q-table :title="title" :rows="rows" :columns="columns" row-key="key" :separator="separator" v-model:pagination="table_pagination" /> <q-pagination v-model="current" color="purple" :max="maxPage" :max-pages="10" boundary-numbers @update:modelValue="onPageChange" ></q-pagination> </div> </div> </template> |
2. Import the necessary dependencies in the newly created component.
1 2 3 4 |
import Overlay from "ol/Overlay"; import Feature from "ol/Feature"; import { Vector as VectorSource } from 'ol/source'; import { VectorImage } from 'ol/layer'; |
3. Define the data state object:
Data state object is required for maintaining state while opening feature popup or switching from one feature to another in pagination
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
data() { return { title: "", rows: [], columns: [], current: 1, maxPage: 0, featureProps: [], separator: 'cell', table_pagination: { page: 1 }, highlight_layer: '' } } |
4. Define addClick() method:
This function adds a click handler to a OpenLayers map. It creates a highlight layer for vector images, an overlay for anchoring a popup to the map, and a click handler for hiding the popup. When a user clicks on the map, the code iterates through the features found at the clicked coordinates, maintains state for the title and feature properties, and renders them in a Q-table in the popup. The code also adds a feature to the highlight layer for the clicked feature.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/** * Adding code to for opening popup on click */ addClick () { // Create vector layer for highlighting the feature on popup click let highlight_layer = new VectorImage({ source: new VectorSource({ }) }); this.map.addLayer(highlight_layer); let container = document.getElementById('popup'); let closer = document.getElementById('popup-closer'); /** * Create an overlay to anchor the popup to the map. */ const overlay = new Overlay({ element: container, autoPan: { animation: { duration: 250, }, }, }); /** * Add a click handler to hide the popup. * @return {boolean} Don't follow the href. */ closer.onclick = function () { highlight_layer.getSource().clear(); this.table_pagination = { page: 1 }; this.current = 1; overlay.setPosition(undefined); closer.blur(); return false; }; this.title = 'dummy'; this.map.addOverlay(overlay); /** * Add a click handler to the map to render the popup. */ let that = this; this.map.on('singleclick', function (evt) { // Clear highlight_layer features on every click that.current = 1; highlight_layer.getSource().clear(); that.featureProps = []; that.maxPage = 0; // Iterating through array of features found on clicked coordinates of map evt.target.forEachFeatureAtPixel(evt.pixel, (feature, layer) => { // Maintaining states such as title, feature properties for features on click and rendering them on q-table in popup let featureProp = {}; featureProp.title = layer.get('name'); featureProp.columns = [{name: 'key', label: 'Key', field: 'key'}, {name: 'value', label: 'Value', field: 'value'}] featureProp.rows = []; featureProp.geom = ''; let props = feature.getProperties(); for (let x in props) { if (x != 'geometry') { featureProp.rows.push({ key: x.toUpperCase(), value: props[x] }) } else { featureProp.geom = props[x]; } } that.featureProps.push(featureProp); that.maxPage += 1 }); if (that.featureProps.length) { that.title = that.featureProps[0].title; that.columns = that.featureProps[0].columns; that.rows = that.featureProps[0].rows; let feature = new Feature({ geometry: that.featureProps[0].geom }); highlight_layer.getSource().addFeature(feature); const coordinate = evt.coordinate; overlay.setPosition(coordinate); } }); that.highlight_layer = highlight_layer; }, |
5. Define onPageChange(i) method:
This function changes the feature information and highlights the feature on pagination click. It clears the previous highlight feature and updates the title, columns, and rows based on the selected page number. It then adds a new feature to the highlight layer with the geometry from the selected feature.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
onPageChange(i) { /** *Changing the feature info and highlight feature on pagination click */ this.highlight_layer.getSource().clear(); this.table_pagination = { page: 1 }; this.title = this.featureProps[i-1].title; this.columns = this.featureProps[i-1].columns; this.rows = this.featureProps[i-1].rows; let feature = new Feature({ geometry: this.featureProps[i-1].geom }); this.highlight_layer.getSource().addFeature(feature); } |
I hope this tutorial will create a good foundation for you. If you want tutorials on another GIS topic or you have any queries, please send an email at contact@spatial-dev.guru.
Pingback: Integrating OpenLayers Map with VueJS: Create Layers Panel – Part 2 - Spatial Dev Guru
Pingback: Integrating OpenLayers Map with VueJS: Implement Style and legend for vector layer – Part 3 - Spatial Dev Guru
Pingback: Integrating OpenLayers Map with VueJS: Recreating the project with Vite, Pinia and TypeScript-Part 5 - Spatial Dev Guru
Pingback: Integrating OpenLayers Map with VueJS: Create Map - Part 1 - Spatial Dev Guru