admin管理员组文章数量:1136157
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.
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.
Share Improve this question asked Mar 23, 2018 at 2:45 user3059217user3059217 5911 gold badge6 silver badges9 bronze badges 1- 2 Can you mark helpfull answer? – Stevan Tosic Commented Jan 7, 2019 at 14:26
12 Answers
Reset to default 102Try 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;
Adding answer for Next.js
Copy over marker icon from
node_modules/leaflet/dist/images
topublic/images
something like/images/marker-icon.png
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
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
});
In 2024 you can just use leaflet-defaulticon-compatibility.
npm install leaflet-defaulticon-compatibility --save
Make sure to import the compatibility package after leaflet!
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css'; // Re-uses images from ~leaflet package
import L from 'leaflet';
import 'leaflet-defaulticon-compatibility';
The position of your react-leaflet
imports should not matter. This setup also works well with NextJS 14.
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
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/';
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>
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.
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.
Because I was unable to find a full example that solved all of my issues, I'm posting my code. Working in January 2024 with the latest versions of leaflet
, react-leaflet
, react
, and next.js
. This example should allow the client to load markers (from the CDN), but also refresh the page even if it's being delivered from server-side contexts like next.js
.
import React, { useEffect, useState } from 'react';
export const Map = ({ mapMarkers, height }) => {
const [Leaflet, setLeaflet] = useState(null);
const [MapContainer, setMapContainer] = useState(null);
const [TileLayer, setTileLayer] = useState(null);
const [Marker, setMarker] = useState(null);
const [Popup, setPopup] = useState(null);
useEffect(() => {
import('react-leaflet').then((mod) => setMapContainer(mod.MapContainer));
import('react-leaflet').then((mod) => setTileLayer(mod.TileLayer));
import('react-leaflet').then((mod) => setMarker(mod.Marker));
import('react-leaflet').then((mod) => setPopup(mod.Popup));
import('leaflet').then((mod) => setLeaflet(mod));
}, []); // Run imports just once on mount
const [customIcon, setCustomIcon] = useState(null);
const [initialBounds, setInitialBounds] = useState(null);
useEffect(() => {
if (Leaflet && mapMarkers.length > 0) {
// Calculate the bounds based on marker positions
const markerBounds = mapMarkers.map(({ position }) => position);
const bounds = Leaflet.latLngBounds(markerBounds);
// Pad the bounds to add some padding to the viewport
const paddedBounds = bounds.pad(1); // Adjust the padding factor as needed
// Set initial bounds for the MapContainer
setInitialBounds(paddedBounds);
// Initialize Leaflet once the component is mounted on the client side, and provide icons.
const icon = new Leaflet.Icon({
iconUrl: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/images/marker-icon.png',
iconSize: [22, 32],
iconAnchor: [16, 32],
popupAnchor: [0, -32],
});
setCustomIcon(icon);
}
}, [Leaflet, mapMarkers]); // Run the effect whenever Leaflet or mapMarkers are updated
return (
MapContainer && initialBounds && (
<MapContainer
bounds={initialBounds}
style={{ width: '100%', height: height || '400px' }}
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
{customIcon &&
mapMarkers.map(({ position, popupContent }, index) => (
<Marker key={index} position={position} icon={customIcon}>
<Popup>{popupContent}</Popup>
</Marker>
))}
</MapContainer>
)
);
};
The component employs useEffect
hooks to avoid Server Side Rendering. Because of the dependency on Leaflet.js
, the map cannot be rendered server-side. Leaflet was built, and continues to be developed, for the context of rendering maps in standard browser environments. In such contexts, it is expected that Leaflet will have access to the Window object. This is categorically untrue in server side contexts, and so this component falls back on Client Side Rendering, using a CDN to deliver static assets (as Leaflet expects).
I have not taken the time to add types; please feel free to make that effort if you're so moved!
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='© <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;
The easiest solution, the best:
import Leaflet from 'leaflet';
Leaflet.Icon.Default.imagePath = '/images/'
本文标签: javascriptReactLeaflet marker files not foundStack Overflow
版权声明:本文标题:javascript - React-Leaflet marker files not found - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736954409a1957542.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论