React Leaflet - Marker image fails to load
Asked Answered
J

3

6

Issue

I'm using leaflet v1.7.1 and react-leaflet v3.0.5 in my React project.

When I try out the setup example in React Router's "Setup" documentation page, the marker icon becomes a broken image as circled in red below:

marker broken image

From the React Router's documentation, this is what the marker should look like:

correct marker

Upon inspection, the src attribute of the <img> tag that holds the marker image should be https://unpkg.com/[email protected]/dist/images/marker-icon-2x.png. However, upon inspection, my <img>'s src attribute turns out to be gibberish-looking:

gibberish link

Replication

I've created a new sandbox which contains my code:

Edit on Code Sandbox

Alternatively, follow these steps to replicate the issue:

  1. npx create-react-app leaflet-test

  2. cd leaflet-test/

  3. npm i leaflet react-leaflet

  4. Open the project in code editor. Go to App.js and use the following code:

    import React from "react";
    import "./App.css";
    import "leaflet/dist/leaflet.css";
    import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
    
    const styles = {
      mapRoot: {
        height: 400,
      },
    };
    
    export default function App() {
      return (
        <MapContainer
          style={styles.mapRoot}
          center={[51.505, -0.09]}
          zoom={13}
          scrollWheelZoom={false}
        >
          <TileLayer
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          />
          <Marker position={[51.505, -0.09]}>
            <Popup>
              A pretty CSS3 popup. <br /> Easily customizable.
            </Popup>
          </Marker>
        </MapContainer>
      );
    }
    
  5. npm start

I'm not sure whether I've set-up Leaflet wrongly in React or it's a bug from Leaflet or React Leaflet. Thanks in advance!

Justness answered 17/1, 2021 at 8:5 Comment(3)
Maybe this thread will help you, good news is that its not your fault and it appears to be a common issue github.com/PaulLeCam/react-leaflet/issues/453Judicator
Thank you so much :D I've found a fix from that issue thread.Justness
No problem, happy you found the solution :)Judicator
S
9

I faced Same Issues but found out this solution lately, all we need to do is pass an icon prop to the Marker component.

import marker from '../../Assets/icons/Location.svg';
import { Icon } from 'leaflet'
const myIcon = new Icon({
 iconUrl: marker,
 iconSize: [32,32]
})

<MapContainer center={value} zoom={13} scrollWheelZoom={false}>
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <Marker position={value} icon={myIcon}>
        <Popup>
        Location :{data}
        </Popup>
      </Marker>
    </MapContainer>

Check My Solution on CodeSandBox!

Syllogism answered 16/11, 2021 at 3:5 Comment(0)
J
8

Thanks to FoundingBox's comment, it turns out that this is a bug of React Leaflet.

There is already a GitHub issue thread regarding this bug and this comment suggested the following solution:

OK. It turns out that the problem was caused by including the leaflet CSS in the component's imports.

I've now just included a link to the CDN hosted leaflet.css file and it's working OK, but it would be good if this could be patched to work with create-react-app webpack config.

In other words, here's the step by step guide:

  1. Remove import "leaflet/dist/leaflet.css"; from App.js. Do NOT import the Leaflet CSS from the node modules in any JS files.

  2. Go to public/index.html and include the CDN hosted leaflet.css by pasting the following code in the <head> section of the HTML file:

    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
      integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
      crossorigin=""/>
    

    (Note: This link uses v1.7.1 of Leaflet. Visit Leaflet's documentation to find the code of linking the latest version of Leaflet)

Justness answered 17/1, 2021 at 9:15 Comment(1)
Working solution for the latest react-leaflet versions. Thanks bro!!Xuanxunit
M
6

For reference, this is due to webpack rewriting URL's in CSS, whereas Leaflet uses it to detect the paths to its icon images.

See the details in Leaflet issue #4968.

When using Leaflet through a CDN, the Leaflet CSS is not fiddled with, so it works correctly.

You can still use it through webpack, but you should either use only custom icons, or explicitly tell Leaflet where to find the images for its default icon:

import L from 'leaflet';
delete L.Icon.Default.prototype._getIconUrl;

L.Icon.Default.mergeOptions({
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});

I also made specifically a plugin for this case: leaflet-defaulticon-compatibility

Retrieve all Leaflet Default Icon options from CSS, in particular all icon images URL's, to improve compatibility with bundlers and frameworks that modify URL's in CSS.

import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css'; // Re-uses images from ~leaflet package
import * as L from 'leaflet';
import 'leaflet-defaulticon-compatibility';
Misfortune answered 17/1, 2021 at 13:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.