Search code examples
reactjsleafletreact-leaflet

Leaflet marker rendering but showing the "broken image" placeholder


Here is what it looks like:

1

My code:

Map.js

//the next 3 lines changes nothing kept it in bc I found this online as a potential solution
//and didn't want to get this suggested
import L from 'leaflet';
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.imagePath = "/";

function Map() {

 let position = [x, y];

 return (
   <div>
     <div id="mapid">
       <MapContainer className="leaflet" center={position} zoom={13} scrollWheelZoom={true}>
         <TileLayer
           attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
           url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
         />
          <Marker position={position}>
            <Popup>
              A pretty CSS3 popup. <br /> Easily customizable.
            </Popup>
          </Marker>
        </MapContainer>
      </div>
    </div>

  );
};

index.css

.leaflet {
  height: 500px;
  width: 100%;
}

#mapid {
  height: 500px;
  margin-top: 50px;
  margin-bottom: 150px;
}

img.leaflet-marker-icon {
   background-image: 
   url('<url>');
}

I do not really understand how the marker is rendering and not rendering at the same time, it does not make sense.

Obviously, I am trying to render something that is causing some image to not render but I do not see which it would be.

The code is pretty much straight up from the example code: https://leafletjs.com/examples/quick-start/. Which is why I am confused.

I have included the style and script tags in index.html already.


Solution

  • If you pay really close attention, you actually have 2 broken image placeholders shown in your screenshot:

    • one that is wider than the Marker icon image: that is for the default Leaflet icon shadow image:

    leaflet marker icon shadow image

    • the other one is more difficult to discern, it fits the shown icon image size: that is for the actual default Leaflet blue icon image that is specified in the src attribute of the <img> tag. But we can see a blue icon because you have specified it as a background image (but it is still broken, hence the browser still shows the placeholder)

    The root cause is that your build engine (most likely webpack, since you use React) rewrites the URL's in Leaflet CSS file, which interferes with how Leaflet uses it to detect the path to its images.

    See Leaflet/Leaflet#4968 and PaulLeCam/react-leaflet#453 for more details.

    As for workarounds, you have 2 possible easy options:

    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';
    
    • use this code snippet somewhere in your project (you may need to properly configure your webpack loaders):
    import 'leaflet/dist/leaflet.css';
    import * as 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'),
    });