Insert context menu in Leaflet map

981 views Asked by At

I want to ask about Vue 3, how to insert a custom context menu in a Leaflet map? I'm using [email protected], @vue-leaflet/[email protected] and trying to use [email protected]. My code looks like this:

<template>
    <div class="map">
        <l-map ref="map" v-model:zoom="zoom" :center="[49.2265592, 16.5957531]">
            <l-tile-layer
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                layer-type="base"
                name="OpenStreetMap"
            ></l-tile-layer>
        </l-map>
    </div>
</template>

<script>
import "leaflet/dist/leaflet.css";
import { LMap, LTileLayer } from "@vue-leaflet/vue-leaflet";
// import L from 'leaflet';
// import "leaflet-contextmenu";

export default {
    components: {
        LMap,
        LTileLayer,
    },
    data() {
        return {
            zoom: 13,
        };
    },
};
</script>

What I would like to do is something like:

L.map.contextmenu = true;
L.map.contextmenuItems = [{
    text: 'Show coordinates',
}];

However, I can't figure out how and where to write this. Any feedback would be appreciated.

2

There are 2 answers

0
DaBler On BEST ANSWER

I have figured out how to use [email protected] in @vue-leaflet/[email protected]. The key is passing options (:options="mapOptions") to the leaflet map constructor, which can be done declaratively. The code is like:

<template>
    <div class="map">
        <l-map ref="map" v-model:zoom="zoom" :center="[49.2265592, 16.5957531]" :options="mapOptions">
            <l-tile-layer
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                layer-type="base"
                name="OpenStreetMap"
            ></l-tile-layer>
        </l-map>
    </div>
</template>

<script>
import "leaflet/dist/leaflet.css";
import { LMap, LTileLayer } from "@vue-leaflet/vue-leaflet";
import 'leaflet-contextmenu';
import 'leaflet-contextmenu/dist/leaflet.contextmenu.min.css';

export default {
    components: {
        LMap,
        LTileLayer,
    },
    data() {
        return {
            zoom: 13,
            mapOptions: {
                contextmenu: true,
                contextmenuWidth: 140,
                contextmenuItems: [
                {
                    text: 'Show coordinates',
                    callback: ()=> alert('Coordinates callback')
                }
                ]
            },
        };
    },
};
</script>

I hope this helps someone else.

8
Chaser On

Unfortunately I cant tell you much about @vue-leaflet/vue-leaflet directly, since I never used it. However, you said "Any feedback would be appreciated.", so I'd like to present you a slightly different approach. Usually I include Leaflet directly in my Vue Apps like this:

First I create a ref to my map element - just like you did:

<div ref="mapEl"></div>

Then I get that ref using Vues ref function:

import { ref } from 'vue';
const mapEl = ref();

You can pass the refs value - which contains the HTMLElement - directly in Leaflets constructor. I'm doing this right in the onMounted hook

const map = leaflet.map(mapEl.value, {
    contextmenu: true,
    contextmenuWidth: 140,
    contextmenuItems: [
      {
        text: 'Show coordinates',
        callback: ()=> alert('Coordinates callback')
      }
    ]
});
// Other options you want to apply

Don't forget to import Leaflet and the contextmenu plugin:

import leaflet from 'leaflet';
import 'leaflet-contextmenu';
import 'leaflet-contextmenu/dist/leaflet.contextmenu.min.css';

The full code could look like this:

<template>
  <div ref="mapEl"></div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import leaflet from 'leaflet';
import 'leaflet-contextmenu';
import 'leaflet-contextmenu/dist/leaflet.contextmenu.min.css';

const mapEl = ref();

onMounted(()=> {
const map = leaflet.map(mapEl.value, {
  contextmenu: true,
  contextmenuWidth: 140,
  contextmenuItems: [
    {
      text: 'Show coordinates',
      callback: ()=> alert('Coordinates callback')
    }
  ]
});
// Other options you want to apply
});
</script>

I hope this will solve your problem. Good luck on your app! :)