Leaflet: Lean, Mean Javascript Maps

A few weeks back I tweeted about some fun stuff we were doing with the Leaflet javascript map library. For those who may not know about it, Leaflet is a new(ish) library from Cloudmade (http://leaflet.cloudmade.com/). What’s really great about this library is that is really really lean. Like 24Kb on the wire. Of course this means that instead of handling every possible thing in every browser, the developers focused on a reasonable subset of functionality, and make the assumption you’re using a reasonably modern browser.

How Lean is Lean?

As I said, we’re talkin’ 24Kb total and it’s all in one file, which means one request. This makes it ideal for use in mobile web applications. Compared to the Esri Compact javascript api, which is 114Kb itself, AND makes 11 additional requests for more Dojo pieces and parts, totaling out to ~145Kb, Leaflet is substantially leaner. And since there is less javascript running… it’s also faster.

Leaning on the Browser: CSS3

Another noticeable difference is that Leaflet leans heavily on CSS3. This alone is good because CSS3 operations (transforms etc.) are native so they are MUCH faster than doing the same thing via javascript. And, on iOS, CSS3 transforms are hardware accelerated, which means super smooth panning and zooming. Relying on CSS3 also removes a ton of code – of course if your end users are rocking Internet Explorer 6, this may be sub-optimal. (What isn’t sub-optimal in IE6??). Luckily for us all, the vast majority of smartphones use a webkit browser Winking smile

ArcGIS Server Goodies

Ok, so that’s set the stage – leaflet is good and shiny, but how do we (die-hard Esri geogeeks) integrate services hosted on ArcGIS Server? We write code! (mostly)

Tiled Map Services

Tiled map services are really easy to use in Leaflet and don’t require any coding. Since Leaflet has a TileLayer, and assumes we’re all using the One-True-Projection (did I say there were limitations?) all we need to do is hand the TileLayer constructor the url to the tile service.

var streetMapUrl = 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}';
var streetMapLayer = new L.TileLayer(streetMapUrl, { maxZoom: 19, attribution: 'Tiles: © Esri' });

The thing to note here is that the CloudMade tile urls have the parameters ordered differently ({z}/{x}/{y}) than an ArcGIS Server tile cache ({z}/{y}/{x}). That’s it!

ArcGIS Dynamic Map Services

This does require some code (over in GitHub if you want to peek). I ended up creating two types of layers that use ArcGIS Dynamic map services. The first one I build is based off the ImageOverlay class. The AgsDynamicLayer class takes the url to a map service, and will make requests for map images that cover the visible extent (just like the ArcGISDynamicLayer in the javascript and Flex APIs). You can specify which layers in the map service to show, as well as setup definition queries.

var sitesLayer = new L.AgsDynamicLayer(
    'http://ags2.dtsagile.com/ArcGIS/rest/services/LiveFeeds/WxMappr/MapServer',
    { maxZoom: 19,
        attribution: "NOAA",
        opacity: 1,
        layers: 'show:2' });
_map.addLayer(sitesLayer);

This is a *minimalist* implementation – if you want to use this, and it’s missing a feature you want – add it! Since it’s using the REST API, this is really just about creating Urls, so it’s simple. Also – this example is using a demo NEXRAD service, so don’t use it in your apps. Ok, you actually could and we likely would not notice, but we move stuff around a lot so it will likely break at some really inconvenient time, and then your boss will be all up in your face etc. etc. In short – be cool. Moving on…

Turns out that this works quite well in desktop browsers, but crashes Safari on iOS after a bunch (like 50) pan/zoom operations. Not quite sure why this is, but hopefully someone can take a peek at the code and have an “Ah HA!” moment and fix this.

SO – since that did not work on mobile browsers, and I saw that there was a TileLayer.WMS class in the repo, I thought I’d go that route – assuming that whatever was causing Safari on iOS to puke would not be an issue. Thus the TileLayer.AGSDynamic class (yeah yeah – I just noticed the inconsistent casing). This has the same parameters etc as the AgsDynamic layer, but instead of making a request for a single image covering the current visible extent, it makes a bunch of requests for images that line up with tiles.

var nexrad = new L.TileLayer.AGSDynamic(
            'http://ags2.dtsagile.com/ArcGIS/rest/services/LiveFeeds/WxMappr/MapServer',
                 {  maxZoom: 19,
                    attribution: "NEXRAD",
                    opacity: 0.5,
                    layers: 'show:18',
                    cacheBuster: true });
_map.addLayer(nexrad);

This is cool because now you’ll have consistent urls,  which means you’ll play nice with caching and once an image is loaded your pan/zoom operations don’t have to re-load it. However, the first layer I used this with is a NEXRAD feed that updates every 5 minutes, so I added a cacheBuster property which basically tacks a random number on the back of the request to force new images every time. Down the line I’d probably make another custom layer that has a timer and only changes this random string every 5 minutes. Unfortunately, this layer still causes Safari on iOS to crash (doh!)

Here’s a simple screen grab of leaflet, loaded with the Esri Streetmap tile cache, NEXRAD data coming in via TileLayer.AGSDynamic and windfields coming in via AgsDynamic.

ll-ags

Lets Play!

I’m going to push up some simple demo’s later today (and will update this post) but until then   UPDATE: Live demo’s of can be found at http://demo.dtsagile.com/leaflet

You can fork our Leaflet repo at GitHub or just grab code, and use the agstile.html and ags-dynamic.html files includes in /debug/map. Once we (or someone) sorts out why these are crashing Safari, we’ll submit a pull request and hopefully get this into the main branch of the Leaflet source.

16 thoughts on “Leaflet: Lean, Mean Javascript Maps

  1. agafonkin

    Thanks for a good review!

    By the way, regarding projections — Leaflet also support 4326 and 3395 besides 3857 (see Map crs option), and it’s quite easy to write a custom CRS definition (see src/geo/crs folder for sources).

    Reply
  2. Todd Jackson

    Great post! I was intending to do a post myself regarding the very same subject – integrating esri based layers in Leaflet, but I will be able to refer to your example now :)

    I recently did a post on the GeoJSON support in Leaflet and had a similar sense of how lean the solution becomes.

    Reply
  3. Pingback: Leaflet – A New Direction In Interactive Web Maps « GIS Confidential

  4. Jeremy Carlson

    This gets me thinking—sounds like I could maybe use Leaflet for showing a map when I don’t need to be able to edit it, but possibly tie into ARCGIS.com tools when I need the editing capabilities? I like Leaflet’s leanness, but being able to draw directly on the map—that’s good stuff.

    Reply
    1. Dave Bouwman Post author

      Jeremy,

      That’s about right – although you can do some pretty cool stuff with Leaflet, if you need vector editing to an ArcGIS Server back-end then the Esri Javascript API is the way to go. If you just need to add points on a phone, then Leaflet and a simple xhr call to a FeatureService is also very doable.

      Cheers,

      Dave

      Reply
  5. Pingback: ArcGIS Image Services and Leaflet | geoMusings

    1. Dave Bouwman Post author

      Martin,

      So, this code is not a full wrapper for the REST API, like the Esri JS API, so you’ll need to write your own ajax request / response handlers to do the query and then show the info in a pop-up window in Leaflet. It’s not particularly difficult, but it’s more work than the Esri JS API.

      Cheers,

      Dave

      Reply
  6. Brett

    I know I’m jumping in on this way too late but is anyone having issues with using popups on this fork. I’ve tried adding a simple popup to the agsdynamic example and am getting L.popup() is not a function.

    Reply
    1. Dave Bouwman Post author

      We have not been keeping that fork up to date by any means (too much Esri related work) so you’re likely better forking the latest from leaflet and dropping in the layers we created.

      I *believe* I got the AGSDynamic layer working with leaflet master in July??? I was for a quickie demo but no changes were required that I recall.

      This fall we *hope* to be getting back to some internal development which will use leaflet, so we’ll be updating everything at that time.

      Cheers,

      Dave

      Reply
  7. Pingback: Leaflet.js | FREE CULTURE & FREE TOOLS

  8. George

    Newbie question – I would like to create simple map viewer mobile app that would allow us to view our map data in the field. We would just need a basic base map, over which we would be able to plot raster data (derived from geotiff, but we have flexibility in output), and from line drawings (originating in CAD, again can come out as shape files or similar). The user should be able to see/center the map on their position. I would welcome being pointed in the right direction. Advice welcome!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>