javascriptvue.jsleaflet

Leaflet JS custom marker icon not showing


I am working on a personal project using LeafletJS and Vue3. I want to change the default marker icon so I copied the png file directly into the same file as my script and created a new Icon as shown below.

import leaflet from "leaflet";

let DefaultIcon = new leaflet.Icon({
  iconUrl: './Banner.png',
  iconSize: [50, 50]
})

export default class Info {
  constructor(
    name = "", notes = "", icon = DefaultIcon
  ){
    this.name = name;
    this.notes = notes;
    this.icon = icon;
  }
...

and when I create the marker I access this icon...

...
  constructor(data) {
    this.id = data.id;
    this.info = new Info(data.info.name, data.info.notes);
    console.log("Icon", this.info.icon)

    if (mapStore.map != null) {
      this.object = new leaflet.marker(
        [data.lat, data.lng], 
        {
          icon: this.info.icon,
          draggable: true,
          riseOnHover: true
        }
      ).addTo(mapStore.map)
    }
...

This was all working fine using the default blue marker icon before I specified icon: this.info.icon in the options. Now the markers still appear (I can see their tooltips) but there is no icon. I'm absolutely stumped on what could be causing this. The log statement shows that data.info.name is a leaflet.Icon with the proper path and everything.

I've tried setting the path as an absolute path from the project root, a relative path from the script location, and providing option values when initializing the Icon. I also tried to initialize DefaultIcon without the new keyword, just because thats what I saw here (although I don't really know why there's no new keyword in that example), but I got an error about initialization hooks. I would expect the default blue marker icon to be replaced with my Banner.png marker icon, but instead there is no marker icon at all. Why isn't it the icon rendering on the map?


Solution

  • Since you are using a Front-End framework with a build step (here Vue 3), it is very likely that your built assets do not have the same file structure as your project source code: your files are bundled, copied into a destination folder, and media assets may have their name modified (typically fingerprinting for cache busting).

    Hence when Leaflet uses the iconUrl: './Banner.png' to populate the Marker Icon <img src> attribute, the path is broken: your image is not at thst location on your server.

    To have the build engine process your image as the rest of the media assets, and retrieve its final path and name, make sure to import or require it:

    let DefaultIcon = new leaflet.Icon({
      iconUrl: require('./Banner.png'), // require the image, the build engine will prohide the final path and name
      iconSize: [50, 50]
    })
    

    Or:

    import myImgPath from './Banner.png'
    
    let DefaultIcon = new leaflet.Icon({
      iconUrl: myImgPath,
      iconSize: [50, 50]
    })