vue.jsvuejs3leafletvue-leaflet

Vue 3 leaflet doesnt load map correctly


I'm making a custom map for leaflet using vue 3. It only loads 4 tiles in a row( loads more tiles when i zoom, but within that same area, equivalent to the initial 4 tiles) - it does seem to load more tiles when i pan the map, as seen in the "Network" tab: pan-right-print

I honestly cant figure out what is going on. This is the component's code:

<template>
  <div class="mapContainer">
    <l-map ref="map" :zoom="zoom" :center="center" :max-zoom="3" :min-zoom="0" :useGlobalLeaflet="false">
      <l-tile-layer :url="getWsUrl()" layer-type="base" name="WorldMap" :no-wrap="true" :zoomOffset="1"></l-tile-layer>
    </l-map>
  </div>
</template>

<script setup lang="ts">
import 'leaflet/dist/leaflet.css'
import { LMap, LTileLayer } from '@vue-leaflet/vue-leaflet'
import { onMounted, ref, nextTick } from 'vue'
import { type PointTuple } from 'leaflet'

const getWsUrl = (): string => {
  return '/maps/iluambar/{z}/{x}/{y}.png'
}

onMounted(() => {
  nextTick(() => {
    /* if (map.value) {
            // How to ref a reference to map?!
        } */
  })
})
const zoom = ref(3)
const center = ref<PointTuple>([10, 10])
const map = ref<typeof LMap>()

</script>

<style >
.mapContainer {
  width: 100%;
  height: 600px;
}

.leaflet-div-icon {
  background: steelblue;
  color: rgba(255, 255, 255, 0.5);
  border-radius: 80%;
  font-weight: bold;
  font-size: large;
  text-align: center;
  line-height: 21px;
}
</style>

The package.json is as follows:

{
  "name": "mapviewer",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": "^20.19.0 || >=22.12.0"
  },
  "scripts": {
    "dev": "vite",
    "build": "run-p type-check \"build-only {@}\" --",
    "preview": "vite preview",
    "build-only": "vite build",
    "type-check": "vue-tsc --build",
    "lint": "eslint . --fix",
    "format": "prettier --write src/"
  },
  "dependencies": {
    "pinia": "^3.0.3",
    "vue": "^3.5.18",
    "vue-leaflet": "^0.1.0",
    "vue-router": "^4.5.1"
  },
  "devDependencies": {
    "@tsconfig/node22": "^22.0.2",
    "@types/leaflet": "^1.9.4",
    "@types/node": "^22.16.5",
    "@vitejs/plugin-vue": "^6.0.1",
    "@vue-leaflet/vue-leaflet": "^0.10.1",
    "@vue/eslint-config-prettier": "^10.2.0",
    "@vue/eslint-config-typescript": "^14.6.0",
    "@vue/tsconfig": "^0.7.0",
    "eslint": "^9.31.0",
    "eslint-plugin-vue": "~10.3.0",
    "jiti": "^2.4.2",
    "leaflet": "^1.9.4",
    "npm-run-all2": "^8.0.4",
    "prettier": "3.6.2",
    "typescript": "~5.8.0",
    "vite": "^7.0.6",
    "vite-plugin-vue-devtools": "^8.0.0",
    "vue-tsc": "^3.0.4"
  }
}

I've referred to the solution here: Can't load Leaflet inside Vue component

And followed - loosely - this project: https://github.com/jhkluiver/Vue3Leaflet/blob/main/vue3-quasar-leaflet/src/components/VueLeafletMap.vue

Also tried map.invalidateSize() suggested in multiple post here on SO.

Also attempted this solution using OptionsAPI instead of CompositionAPI - thought i might have missed something related to the life cycle for the application:

<template>
  <div id="mapContainer"></div>
</template>

<script lang="ts">
import "leaflet/dist/leaflet.css";
import { map, tileLayer } from "leaflet";
import { onMounted, onBeforeUnmount } from "vue";

export default {
  name: "WorldMap",
  setup() {
    let container : L.Map | null = null;

    onMounted(() => {
      container = map("mapContainer").setView([10, 10], 3).setMaxZoom(3).setMinZoom(0);

      tileLayer("/maps/iluambar/{z}/{x}/{y}.png", {}).addTo(container);
    });

    onBeforeUnmount(() => {
        if (container)
            container.remove();
    });
  }
};
</script>

<style scoped>
#mapContainer {
  width: 100vw;
  height: 100vh;
}
</style>

It yield the same results.

Edit: I updated the image (cropped used another method) It shows the map all scrambled too. Scrambled map


Solution

  • It turns out it was a bug on the tile cutter. The order in witch it cropped the tiles was incorrect and i didn't notice while giving a look at them "manually".
    I encourage you to double check the tiles if something like this happens to you.
    The code works fine as is.