Red Green Repeat Adventures of a Spec Driven Junkie

Google Maps & Leaflet Reference

I had to start on a conversion going from Google Maps service (and it’s API) to an open street maps based solution Mapzen, which uses Leaflet.js for its front end.

Converting from one mapping solution to another takes a bit of work, so this is a reference for common map features and how to implement them in each system.

Google Maps

Google maps is a great maps service, its API is extensive. The API must be used with the service.

Open Street Maps

Open street maps based map services are great as they are free to use. Mapzen uses Open Street Maps to provide map tiles and uses leaflet.js to view and control the map.

Features Covered

Below is a list for common features of Google Maps & Open Street Maps services using Leaflet.js.

  • API keys/tokens
  • Maps
    • Creating map
    • Centering map
    • Map controls (zoom)
    • Turning off ‘scrollwheel’
    • Modals
  • Markers
    • Creating marker
    • Changing marker icons
    • Dynamically changing marker icons
    • Dragging markers dynamically
    • Changing marker draggablility
  • Event Callbacks
    • Map Event to Page Elements
    • Page Event to Map Elements

API keys

Each service will have their own authentication method. Refer to their documentation. Common ways for Google Maps documentation and MapZen documentation:

  • Google Maps:
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=google_maps_api_key"></script>
  • MapZen
L.Mapzen.apiKey = 'mapzen_api_key';

Maps

Creating map in page

All maps need load external libraries and styles. A specific <div> element for the map on the page is also required. Basic page layout:

<head>
    <link rel="stylesheet" href="https://mapzen.com/js/mapzen.css">
    <script src="https://mapzen.com/js/mapzen.min.js"></script>
    <style>
     .map {
         height: 160px;
         width: 100%;
         position: relative;
     }
     html,body{margin: 0; padding: 0;}
    </style>
    <script>
     L.Mapzen.apiKey = 'mapzen-API_KEY';
     var lat = 40.748649, lng = -73.985659;
    </script>
</head>
<body>
    <div id="map"></div>
</body>
  • Google maps
var googleMap = google.maps.Map(div_element, options);
  • Leaflet.js - Mapzen
var leafletMap = L.Mapzen.map(div_element);

This is the most important step in the process. Once maps are displaying properly on a page, it’s all about tweaking the map and other options.

Specifying a View in a Map

Set a map to display a specific latitude & longitude, and a zoom level.

New York City has a latitude and longitude coordinates of: 40.748422322629565, -73.98462921380998 respectively, specifically the intersection of the Empire State Building.

  • Google Maps
googleMap.setCenter({ lat: val, lng: val});
  • Leaflet.js
leafletMap.setView([lat, lng], zoom);

Map Controls

  • Google Maps

    Zoom (and StreetView) controls are on by default. To turn them off, set disableDefaultUI to true on map creation:

var mapOptions    = { disableDefaultUI: true }
var googleMapsMap = new google.maps.Map(div_element, mapOptions);
  • Leaflet

    Leaflet maps by default do not have their zoom controls, so they have to be explicitly enabled. Leaflet approach is to create a control object, then add the control to the map.

zoomControl = L.control.zoom({ position: bottomright }); // Create zoom control:
leafletMap.addControl(zoomControl);                      // Add created zoomControl to the leafletMap object

Scrollwheel zoom

Prevent (or enable) zooming in when scrolling down a page using the mouse wheel.

This is configured as an option at map creation time:

  • Google Maps
googleMap = new google.maps.Map('div_element', { scrollwheel: false });
  • Leaflet
leafletMap = L.Mapzen.map('div', { scrollWheelZoom: false });

Modals

Both map solutions need a little extra code around placing a map in a modal. Essentially, there needs to be a map refresh when the modal is shown so it is drawn properly.

  • Google Maps

    A map needs to have an event trigger executed when the modal is shown. source

$("#modalId").on('shown', function(e) {
  google.maps.event.trigger(gooleMapsMap, 'resize');
  createMap.setCenter(createMarker.position);
});
  • Leaflet

    To refresh a leaflet map, use the map’s .invalidateSize() method on the map. source

$("#modalID").on('shown', function(e) {
  mapzenMap.invalidateSize();
});

Markers

One of the most useful aspect for any map is adding a marker to specify locations.

Create marker object

  • Google Maps
googleMapsMarker = new google.maps.Marker({ position: { lat: val, lng: val }, map: map_object });
  • Leaflet

    Markers have to be created and then attached to the map object:

leafletMarker = L.marker([lat_val, lng_val]); // create marker
leafletMarker.addTo(leafletMap);              // Attach marker to map

Marker icons

Changing a marker’s icon is a great way to highlight different locations on a map.

Google Maps and Leaflet can create markers from URL, such as: http://www.googlemapsmarkers.com/. This provides markers of any color specifiable by RGB values (i.e. 009900).

  • Google Maps
googleMapsMarker = new google.maps.Marker({ position: { lat: val, lng: val }, map: googleMap, icon: icon_url });
  • Leaflet

    Leaflet takes the approach of creating the marker, then attaching it to the map.

var iconURL = 'http://www.googlemapsmarkers.com/v1/f7b512/',
    icon    = L.icon({ iconUrl: iconURL }),        // Create icon from a URL
    marker  = L.marker([lat,lng], { icon: icon }); // Create marker icon
    marker.addTo(map);                             // Add icon to map

Leaflet marker settings

When using a custom marker with Leaflet, its iconAnchor attribute must be specified so a marker’s visual tip matches the actual latitude and longitude on the map. This is an issue when using both Google Maps and a Leaflet map on the same page.

var icon = L.icon({ iconUrl: iconURL, iconSize: [x,y], iconAnchor[anchor_x, anchor_y]});

The below image uses a marker to display the same coordinates in Google Maps and Leaflet using a custom marker icon and no icon anchor:

![leaflet marker without offset](https://www.dropbox.com/s/3dybs2yl09idqt6/leaflet_marker_without_offset.png?raw=1 “Leaflet Marker without Offset)

When the Leaftlet marker iconAnchor is configured to match the marker:

leaflet marker with offset

Notice how the Leaflet marker matches perfectly with the Google Maps marker.

Dynamically Change Mark Icon after creation

  • Google Maps

    A marker’s icon can be changed easily just by specifying a new icon URL in the marker’s setIcon function.

var newIconURL = 'http://www.googlemapsmarkers.com/v1/009900/';
googleMapsMarker.setIcon(newIconURL);
  • Leaflet

    A new marker icon can be specified with a new icon object.

var newIconURL = 'http://www.googlemapsmarkers.com/v1/009900/',
    newIcon    = L.icon({ iconUrl: newIconURL });

marker.setIcon(newIcon);

Draggable Markers

For the times where a marker needs to be interactive, like allowing a user to specify a marker location.

  • Google Maps
draggableGoogleMapsMarker = new google.maps.Marker({ position: { lat: lat, lng: lng }, draggable: true });
  • Leaflet

    Create the marker with option: draggable: true.

draggableLeafletMarker = L.marker([lat, lng], { draggable: true });

Dynamically Draggable Markers

  • Google Maps
googleMarker.getDraggable();           // query on marker's draggability state
googleMarker.setDraggable(true/false); // set marker's draggablility to true/false
  • Leaflet

    If a marker is undraggable, its draggability state can be changed at run time:

leafletMarker.dragging.enabled; // query marker's draggability state
leafletMarker.dragging.enable;  // make a marker draggable
leafletMarker.dragging.disable; // prevent a marker from being draggable

Callbacks

Map Event to Page Element

This is to generate a callback from a marker to another element on the page. Say, displaying the current latitude and longitude marker coordinates in the page.

  • Google Maps

    A event must be associated between the marker, the event type, and function what will be executed on the event.

function googleMapsUpdateLatLngField(marker) {
  var latField = document.getElementById('lat'),
      lngField = document.getElementById('lng');

  latField.value = parseFloat(marker.latLng.lat());
  lngField.value = parseFloat(marker.latLng.lng());
};

google.maps.event.addListener(googleMapsMarker, 'drag', googleMapsUpdateLatLngField);
  • Leaflet

    A marker’s .on() callback has to be assigned to a function to execute on the action.

function leafletFunctionOnDrag(event) {
  var marker = event.target,
      lat_field = document.getElementById('latitude'),
      lng_field = document.getElementById('longitude');

   latField.value = parseFloat(marker.getLatLng().lat);
   lngField.value = parseFloat(marker.getLatLng().lng);
};

marker.on('drag', leafletFunctionOnDrag);

Page Event to Map Element

This is to have an HTML element on the page callback into a map element, like a marker. For example, change the current marker location based on the current coordinates in the text field on a key press.

  • Google Maps
<script>
  function updateGoogleMapsMarkersInMaps() {
    var latField = document.getElementById('lat'),
        lngField = document.getElementById('lng'),
        inputLatLng = { lat: parseFloat(latField.value),
                        lng: parseFloat(lngField.value) };

    googleMapsMarker.setPosition(inputLatLng);
    googleMapsMap.setCenter(inputLatLng);
  };
</script>

Latitude <input id='lat'  type='text' onkeydown='updateGoogleMapsMarkersInMaps()'>
Longitude <input id='lng' type='text' onkeydown='updateGoogleMapsMarkersInMaps()'
  • Leaflet
<script>
function updateMapzenMarkersInMaps() {
  var latField = document.getElementById('lat'),
      lngField = document.getElementById('lng'),
      inputLatLng = { lat: parseFloat(latField.value),
                      lng: parseFloat(lngField.value) };

  mapzenMap.setView(inputLatLng); mapzenMarker.setLatLng(inputLatLng);
};
</script>

Latitude <input id='lat'  type='text' onkeydown='updateMapzenMarkersInMaps()'>
Longitude <input id='lng' type='text' onkeydown='updateMapzenMarkersInMaps()'

Demo

Let’s bring major concepts together and have a demo on this page!

Below are both a Google Map and Mapzen map with a marker.

  • When the marker is dragged, the Latitude and Longitude fields are populated with their respective values.

  • When the field value changes, the markers in the map move to the new location specified.

Latitude Longitude