Leaflet Marker not found production env
Solution 1
This is a known bug in Leaflet, the root issue is that Leaflet's icon image location is been wrongly referenced during bundling.
You can verify that this is your issue, buy validating this parameter (in run time): L.Icon.Default.prototype._getIconUrl()
.
The correct value should be <some_directory>/leaflet/dist/images/
.
However if this bug is happening to you, it's value is: data:image/png;base64,iVBO....K5CYII=")undefined
There are different solutions (work around) depending on which bundle-loader you are using (Vanila WebPack, Angular-Cli - superset of WebPack, etc...).
You can see the original issue here (as well as different solutions depending on your bandle-loader):
https://github.com/Leaflet/Leaflet/issues/4968
If you are using Angular-Cli this solution will work for you. Add this code somewhere before setting the Maker:
import { icon, Marker } from 'leaflet';
const iconRetinaUrl = 'assets/marker-icon-2x.png';
const iconUrl = 'assets/marker-icon.png';
const shadowUrl = 'assets/marker-shadow.png';
const iconDefault = icon({
iconRetinaUrl,
iconUrl,
shadowUrl,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
tooltipAnchor: [16, -28],
shadowSize: [41, 41]
});
Marker.prototype.options.icon = iconDefault;
(this code will change the broken Marker's url, to a valid image from your assets folder).
And add this code at you angular.json (for Angular version >= 6.x) or at your angular-cli.json (for Angular version <= 5.x):
"assets":
[
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "node_modules/leaflet/dist/images/", // you may need to change this path, according to your files structure
"output": "./assets/"
}
] ...
(this code will copy the original Marker images to the /assets
folder so angular-cli could load them)
Solution 2
import "leaflet/dist/images/marker-shadow.png";
if using webpack, just import the image
Solution 3
Below code worked for me
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")
});
Solution 4
Working in Angular 10
For me worked copy paste PNGs files to assets and one command
ngOnInit() { L.Icon.Default.ImagePath = "assets/leaflet/" }
For Angular 13 with Leaflet 1.7
ngOnInit() { L.Icon.Default.imagePath = "assets/leaflet/" }
Solution 5
I ran into a similar issue using Parcel
as the bundler in combination with TypeScript
and Leaflet v1.4
(installed via npm
, as well as its typings) and solved it using Gil's answer in a slightly different way.
import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';
import L, {
LatLngExpression,
FeatureGroup,
TileLayerOptions,
LayerEvent,
LeafletMouseEvent,
Marker,
Layer,
icon,
LayerGroup,
GeoJSON
} from 'leaflet';
import 'leaflet-draw';
import iconRetinaUrl from './assets/marker-icon-2x.png';
import iconUrl from './assets/marker-icon.png';
import shadowUrl from './assets/marker-shadow.png';
// Assign the imported image assets before you do anything with Leaflet.
Marker.prototype.options.icon = icon({
iconRetinaUrl,
iconUrl,
shadowUrl,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
tooltipAnchor: [16, -28],
shadowSize: [41, 41],
});
And in another file, I added the required declarations so TypeScript
allows me to import png
images, e.g.
declare module "*.png" {
const content: string;
export default content;
}
Also notice that, in case you use a Leaflet plugin that requires access to these images, you may need to explicitly assign it too, e.g. the Leaflet draw plugin required it as well. Example:
map.addLayer(drawLayer);
const drawControl = new L.Control.Draw({
draw: {
circle: false,
circlemarker: false,
marker: {
icon: Marker.prototype.options.icon, // Assign icon explicitly
},
},
edit: {
featureGroup: drawLayer,
},
});
map.addControl(drawControl);
map.on(L.Draw.Event.CREATED, event => {
const layer = (event as LayerEvent).layer;
drawLayer.addLayer(layer);
});
Related videos on Youtube
maluss
Updated on April 26, 2022Comments
-
maluss about 2 years
I got a problem with leaflet.
Everything is working fine in development, but in production, my app isn't able to locate the
marker-icon.png
andmarker-shadow.png
images.It is looking for the path
assets/station/images/marker-icon.png
Leaflet js is including like this in my html.erb file
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.5/leaflet.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.5/leaflet.css" />
If someone can help!
-
IvanSanchez over 7 yearsWhich version of Leaflet? How do you deploy the Leaflet JS and CSS files? Where do those files come from (framework, manual download, etc)?
-
maluss over 7 yearsI've edit my post!
-
Alex G Rice over 7 yearsPlease review my answer below, and upvote or mark as as accepted if it helped you.
-
-
ghybs almost 6 yearsWhile this could be a nice explanation for Angular, notice that OP never mentioned using a JS bundler, their incorrect path is not a data URI, and includes old (0.x) Leaflet assets from CDN.
-
Admin over 4 yearsAre you sure this is offering anything new that the other answers are not already offering?
-
user43284 over 4 yearsIs it a nice one-line fix.
-
Juanma Font about 4 yearsThis solution is simple, and will fix with all angular versions, fantastic
-
Mahesh Vemula about 4 yearsgot error with above code snippet. Error: "TS2591: Cannot find name 'require'. Do you need to install type definitions for node? Try
npm i @types/node
and then addnode
to the types field in your tsconfig" -
Kelvin Cayman almost 4 yearsAwesome. This fixed my issue. I am using ngx-leaflet. Thanks!
-
Philipp Doerner over 3 yearsI concur with user43284 - Lesser code that is simpler is in my opinion better and cleaner. I can confirm this worked for Angular10
-
evendiagram about 3 yearsThis fix works for a vite (rollup) & vue3 build. Go into
node_modules/leaflet/dist/images
and pluck those three marker png files. Stick them inpublic/assets
and build away. -
edjm almost 3 yearsI'm not clear, where are you saying to add this bit of code to?
-
Thorvald almost 3 years@NashGC can you elaborate on how you did this with Nuxt? I'm importing leaflet locally into one single component instead of using a plugin, where did you place this block of code?
-
NashGC almost 3 years@Thorvald, I've used it in mounted() method of a map component. (component where I use map)
-
Thorvald over 2 years@NashGC This does work for me.. however my marker disappears in Safari browsers. Any idea how this would be fixed? I'm on leaflet 1.7.1, vue2-leaflet 2.7.0
-
Denis Molodtsov over 2 yearsgetting error
Property '_getIconUrl' does not exist on type 'Default'
Using create-react-app with TypeScript -
dlg_ over 2 yearsThanks, it worked for me too ... but without the require function. I just added iconUrl: "/webroot/assets/js/leaflet/images/marker-icon.png", and so on ... of course fitting to my base url.
-
Dinesh Shekhawat almost 2 yearsShould have been the accepted answer. This works like a charm. Thanks!