pwshub.com

Custom Markers with Leaflet

As I continue to dig into Leaflet, I was recently asked about custom markers based on data, so for example, some locations for a store may use one icon while others use another. I did some digging, and while it turns out Leaflet has deep support for customizing markers, it does take a little bit of work. Here's what I found.

First off, this is the default marker:

Blue marker on a map

Out of the box, this is it. Period. I can appreciate the library wanting to keep its size to a minimum, but I was a bit surprised. That being said, the library provides really flexible support for creating your own markers. The first thing I found was the tutorial, Markers With Custom Icons. In this tutorial, they describe the process of creating an instance of the icon class and specifying resources for the icon and shadow. Technically, this looked incredibly simple, and again, flexible, but the immediate issue I ran into was... ok, where do I find more icons?

I did some more digging and came across this open-source project, leaflet-color-markers, which provides a set of markers in the same style as the original, but in a variety of colors. Their read.me demonstrates the usage like so:

var greenIcon = new L.Icon({
  iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
  shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  shadowSize: [41, 41]
});
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map);

Now... I'm hesitant to suggest making use of raw.githubusercontent.com, as I've always heard that it wasn't meant to be used in production applications. That being said, for today I will, and keep in mind that you can take the asset (for example, marker-icon-2x-green.png) and download it to your website.

I tested this myself and it worked fine, but I wanted the smaller size icons, not the one demonstrated above. I simply copied the URL (https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png), but then the four size/anchor properties stopped working well.

That made sense - I mean, I had a different size icon, and my first thought was, well, I'll just keep tweaking numbers till I get it right, but then I went back to the Leaflet docs, specifically for Icon, and noticed this part:

In order to customize the default icon, just change the properties of L.Icon.Default.prototype.options (which is a set of Icon options).

On a whim, I simply entered L.Icon.Default.prototype.options in my console, and got the following:

{
  "iconUrl": "marker-icon.png",
  "iconRetinaUrl": "marker-icon-2x.png",
  "shadowUrl": "marker-shadow.png",
  "iconSize": [
    25,
    41
 ],
  "iconAnchor": [
    12,
    41
 ],
  "popupAnchor": [
    1,
    -34
 ],
  "tooltipAnchor": [
    16,
    -28
 ],
  "shadowSize": [
    41,
    41
 ]
}

Woot. So with these defaults, I was able to figure out how to combine that project's custom colors with the 'regular' size markers and set the right values.

I'm not quite done yet. One more cool aspect of the Leaflet tutorial on custom markers was how they demonstrated that you could define your own custom icon class, and then make new instances with only slight tweaks. This is taken right from their tutorial:

var LeafIcon = L.Icon.extend({
    options: {
        shadowUrl: 'leaf-shadow.png',
        iconSize: [38, 95],
        shadowSize: [50, 64],
        iconAnchor: [22, 94],
        shadowAnchor: [4, 62],
        popupAnchor: [-3, -76]
 }
});
var greenIcon = new LeafIcon({iconUrl: 'leaf-green.png'}),
    redIcon = new LeafIcon({iconUrl: 'leaf-red.png'}),
    orangeIcon = new LeafIcon({iconUrl: 'leaf-orange.png'});

I took this approach, and merged it with the icons from the GitHub project, and came up with this snippet:

let ColorIcon =  L.Icon.extend({
    options: {
        shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png',
        iconSize: [25, 41],
        shadowSize: [41, 41],
        iconAnchor: [12, 41],
        popupAnchor: [1, -34]
 }
});
let greenIcon = new ColorIcon({iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png'});
let redIcon = new ColorIcon({iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png'});

Here is an example using it:

L.marker([30.471165, -91.147385], 
 {icon: greenIcon}).addTo(map).bindPopup("Baton Rouge");

This was all maybe twenty or so minutes of digging, so not too bad at all. Here's a complete CodePen:

  See the Pen Leaflet with Custom Icons by Raymond Camden (@cfjedimaster) on CodePen.

A Sample Application

Let's demonstrate this with a (kinda) real-world scenario. For the next map, I'll call a function that returns a list of stores and whether or not they are currently open:

async function getStores() {
    return [
 { lat: 30.1, lng: -92.09, desc: '<b>Store One</b><br>Open 9-5 M-F', open:true },
 { lat: 30.3, lng: -92.06, desc: '<b>Store Two</b><br>Open 9-5 M-F', open: true },
 { lat: 30.1, lng: -91.8, desc: '<b>Store Three</b><br>Open 9-1 M-F', open:false }
 ];
}

And with the same custom markers I demonstrated above, I'll use them like so:

let stores = await getStores();
for(let store of stores) {
    let marker = greenIcon;
    if(!store.open) marker = redIcon;
     L.marker([store.lat, store.lng], {icon:marker}).addTo(map).bindPopup(store.desc);
}

It is fairly simple, and you can imagine multiple different icons in play based on the data for your locations. Here's the demo:

  See the Pen Leaflet with Custom Icons by Raymond Camden (@cfjedimaster) on CodePen.

I think I said this in a previous post, but I love how easy Leaflet is, and when I do run into something that isn't quite as easy, I feel like it always provides a way to get to what I need. That's a sign of a good library!

Source: raymondcamden.com

Related stories
1 month ago - As I continue to play with, and really freaking enjoy Leaflet, I thought it would be interesting to show a demo of using CSV data with it. This also coincides with an interesting dataset I got from the Data is Plural newsletter, a...
1 month ago - This blog has been around for a while (twenty one years currently) so it isn't too uncommon for me to revisit old topics and demos and rebuild them. I think today's post may be something of an outlier though. Way back in 2010, early 2010,...
1 month ago - Leaflet is a handy, lightweight, performant JavaScript library for creating responsive and interactive maps for the web. The post Leaflet adoption guide: Overview, examples, and alternatives appeared first on LogRocket Blog.
1 month ago - Real user monitoring tracks and records user sessions on a website or application. It provides insights into user experiences by measuring load times, errors, and overall performance. Real user monitoring (RUM) tools offer a comprehensive...
3 weeks ago - It’s September and we’ve got a fresh set of resources for our fellow web developers. This month, we’ve got tools from various categories, including a plugin to check a WordPress plugin, a React component library for WordPress admin...
Other stories
33 minutes ago - Hina Kharbey talks about how the roles of a mentor versus a coach differ, as well as the situations that work best for having each one. The post Leader Spotlight: The difference between mentoring and coaching, with Hina Kharbey appeared...
3 hours ago - Fixes 41 bugs (addressing 595 👍). node:http2 server and gRPC server support, ca and cafile support in bun install, Bun.inspect.table, bun build --drop, iterable SQLite queries, iterator helpers, Promise.try, Buffer.copyBytesFrom, and...
7 hours ago - This guide provides a foundational understanding of Redux and why you should use it for state management in a React app. The post Understanding Redux: A tutorial with examples appeared first on LogRocket Blog.
10 hours ago - Discover some of the best Node.js web scraping libraries, including Axios and Superagent, and techniques for how to use them. The post The best Node.js web scrapers for your use case appeared first on LogRocket Blog.
13 hours ago - Infinite runner games have been a favorite for gamers and developers alike due to their fast-paced action and replayability. These games often feature engaging mechanics like endless levels, smooth character movement, and dynamic...