31

I've got very simple code to display a map using react-leaflet and place a marker on it. However, i get the following two errors in my browser console

GET http://localhost:8080/marker-icon-2x.png 404 (Not Found)

GET http://localhost:8080/marker-shadow.png 404 (Not Found)

I tried to fix this issue by downloading those two images and placing them at the root. It works. However, how can i change the URL the react-leaflet marker element looks for the marker images? I'd like to store them in "./images" rather than at the root.

user3059217
  • 521
  • 1
  • 6
  • 9

9 Answers9

93

Try to do this :)

React leaflet for some reason do not include images and you will need to reset default icons image.

Below is some working example, I hope it will solve your issue.

You also can add icons from one of public link

https://cdnjs.com/libraries/Leaflet.awesome-markers

import React, { Component } from 'react';
import L from 'leaflet';
import {
    Map, TileLayer, Marker, Popup
} from 'react-leaflet'
import 'leaflet/dist/leaflet.css';
import './style.css';


import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';

let DefaultIcon = L.icon({
    iconUrl: icon,
    shadowUrl: iconShadow
});

L.Marker.prototype.options.icon = DefaultIcon;
Stevan Tosic
  • 6,561
  • 10
  • 55
  • 110
  • 13
    Thanks! I had an additional problem with those markers while zooming out: they "moved" and became inaccurate. You can fix this by adding 'iconSize: [25,41], iconAnchor: [12,41]' to your DefaultIcon – EngJon Dec 22 '20 at 18:01
  • 1
    Thanks, Was trying to figure it out for few days. – Sai Krishnadas Oct 05 '21 at 05:35
  • 2
    Can't believe that a 2018 answer will help me more than the recent ones. – JkAlombro Jun 19 '22 at 15:34
15

Here is the solution that worked for me:

I added the following lines in the top of the file:

import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import L from 'leaflet';

delete L.Icon.Default.prototype._getIconUrl;

L.Icon.Default.mergeOptions({
    iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png').default,
    iconUrl: require('leaflet/dist/images/marker-icon.png').default,
    shadowUrl: require('leaflet/dist/images/marker-shadow.png').default
});
Daniel James
  • 381
  • 1
  • 5
  • 15
  • 3
    Thanks! The .default did the trick for me. Somehow I found my needed answer here :) – The Shmoo Sep 24 '21 at 18:32
  • 1
    I worked. I just copied this code and it worked. I have no idea why. Thank you. – MateuszC Nov 18 '21 at 22:26
  • 1
    This worked a couple of months ago and now it gives a long list of errors starting with `Uncaught Error: iconUrl not set in Icon options (see the docs).`. Ends with `The above error occurred in the component:`. Any idea what to make it work again. – Nipuna Apr 27 '22 at 09:08
12

Adding answer for Next.js

  1. Copy over marker icon from node_modules/leaflet/dist/images to public/images something like /images/marker-icon.png

  2. Create Leaflet icon reference and use the reference in Marker

const icon = L.icon({ iconUrl: "/images/marker-icon.png" });

// some other code

<Marker key={obj.id} position={position} icon={icon}>

// rest of the code
ch4nd4n
  • 4,110
  • 2
  • 21
  • 43
6

It seems not all stuff is properly integrated together when using react, leaflet and react-leaflet. I had the same problem and found this

https://github.com/PaulLeCam/react-leaflet/issues/453

You need to setup leafelet itself again, as something brokes after importing leaflet.css.

Hope it helps

develucas
  • 161
  • 1
  • 1
4

Copy all images from leaflet package to the public directory:

cp node_modules/leaflet/dist/images/* {PUBLIC_WEB_DIRECTORY}/leaflet_images/

Fix the path in Leaflet

import L from 'leaflet';
L.Icon.Default.imagePath='leaflet_images/';
ninja
  • 337
  • 3
  • 2
2

Elaborated answer from @ch4nd4n's answer and adapted for leaflet (v1.8.0) for reactjs (v17).

import iconMarker from 'leaflet/dist/images/marker-icon.png'
import iconRetina from 'leaflet/dist/images/marker-icon-2x.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'

Then,

const icon = L.icon({ 
    iconRetinaUrl:iconRetina, 
    iconUrl: iconMarker, 
    shadowUrl: iconShadow 
});

Add icon prop to the Marker component.

<Marker key={index} position={[loc.lat, loc.long]} icon={icon}>
    <Popup><h3>{loc.name}</h3> {loc.address}</Popup>
</Marker>
Nipuna
  • 162
  • 10
1

What ended up fixing this for me was removing:

import 'leaflet/dist/leaflet.css';

from the file in which my map components was in. I ended up importing leaflet css through the create-react-app index.html file and my marker was able to load alongside my map. Hope this helps anyone stuck.

a-maccormack
  • 86
  • 1
  • 7
  • Well, it's better for abstraction to keep the css import in your map component. Let's say you remove the map from your project; do you have to worry about scrubbing the entire codebase to look for map-related resources to remove as well? – Kalnode May 01 '23 at 13:17
0

Similar solution to @Daniel-James But for TypeScript.

//CSS and marker image fix for Leaflet map
import "leaflet/dist/leaflet.css";
import iconMarker from "leaflet/dist/images/marker-icon.png";
import iconRetina from "leaflet/dist/images/marker-icon-2x.png";
import iconShadow from "leaflet/dist/images/marker-shadow.png";
import L from "leaflet";
L.Icon.Default.mergeOptions({
  iconRetinaUrl: iconRetina,
  iconUrl: iconMarker,
  shadowUrl: iconShadow,
});

Add this code to the imports section of your script.

Explanation

As far as I understand, Leaflet is typically used from CDN, but in the case of using react we'll be using node modules instead. Therefore we need to re-point the CSS to that of the node module, and also repoint the default icons to point towards the node module too.

Sancarn
  • 2,575
  • 20
  • 45
0

For anyone attempting to use leaflet in an expo react native app, the marker image also won't load. A workaround is to use expo-asset, npx expo install expo-asset, and then place an icon in the assets folder. Then you'll need to get a uri using expo-asset and use that as the iconUrl for the leaflet icon.

import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import { Asset } from "expo-asset";

import React from "react";
import { StyleSheet } from "react-native";

const WebMap = () => {
  const icon = require('../../../assets/icon.png');
  const iconURI = Asset.fromModule(icon).uri;

  const leafletIcon = new L.Icon({
    iconUrl: iconURI,
    iconSize: [30, 30],
    iconAnchor: [22, 94],
    popupAnchor: [-3, -76],
  });
  return (
      <MapContainer
        center={[51.505, -0.09]}
        zoom={13}
        scrollWheelZoom={true}
        style={styles.container}
      >
        <TileLayer
          url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        />
        <Marker position={[51.505, -0.09]} icon={leafletIcon}>
          <Popup>
            A pretty CSS3 popup. <br /> Easily customizable.
          </Popup>
        </Marker>
      </MapContainer>
  );
};

const styles = StyleSheet.create({
  container: {
    width: "500px",
    height: "500px",
  },
});

export default WebMap;
K. Shores
  • 875
  • 1
  • 18
  • 46