OpenLayers mapping
Adding both metric and imperial scalelines

Posted: Oct 7, 2022 by Dave Gough

Vehicle odometer showing miles and kilometers per hour

Image: Downtowngal.

Two scalelines?

Within Europe both imperial & metric measuring scales are used. Integrating both types of scalelines is fundamental to providing mapping applications when catering for the European market.

When using the OpenLayers map library to create an online map, adding both a metric and imperial scaleline to the same map is awkward, whereas using the Leaflet map library it comes by default.

I struggled to find a simple working example or any guidance online to achieve two scalelines with OpenLayers. After a fair amount of experimentation around how OpenLayers handles map controls & positioning, I got it working so I thought I would share.

Example

The map below is a working example of the effect; see the bottom left corner of the map as you use the zoom control, top left:

Let's code it

The concept is simple: Add a map, add two scalelines below the map, then style both scalelines upwards over the map.

The code below assumes you already have an HTML document. You can place all of this code together in the body element in the order presented. This is unlikely the optimum positioning for your build, but it will work to get you going...

First, add the OpenLayers libraries:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.1.0/ol.css" />   
<script src="https://cdn.jsdelivr.net/npm/ol@v7.1.0/dist/ol.js"></script>


Now you will want a div element to contain the map and two div elements to hold your two scalelines:

<div id="map"></div>
<div id="scaleline-metric" class="scaleline-external"></div>
<div id="scaleline-imperial" class="scaleline-external"></div>


Add some CSS to style the map. This CSS will also move the two scaleline div elements back up over the map:

<style>                                                                                                                              

#map {                                                                                                                              
  height: 180px;                                                                                                                    
  width: 100%;                                                                                                                      
  z-index:0;                                                                                                                        
}                                                                                                                                   
                                                                                                                                             
/* Move the scaleline div elements back up over the map */                                                                                    
.scaleline-external{                                                                                                                
  position: relative;                                                                                                               
  width: fit-content;                                                                                                               
  top: -47px;                                                                                                                       
  padding-top:2px;                                                                                                                  
}                                                                                                                                   
                                                                                                                                              /* Override default OpenLayers absolute position behaviour */                                                                                
.ol-scale-line{                                                                                                                     
  position: relative;                                                                                                               
}
                                                                                                                                   
</style>


Finally, add some Javascript to initiate the map and add both scalelines:

<script>

// Initiate the map                                                                                                                           

var map = new ol.Map({                                                                                                            
  target: 'map',                                                                                                                  
  layers: [                                                                                                                       
    new ol.layer.Tile({                                                                                                           
      source: new ol.source.XYZ(                                                                                                  
        {                                                                                                                         
          urls : [                                                                                                                
            "https://stamen-tiles-a.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png",                                                 
            "https://stamen-tiles-b.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png",                                                 
            "https://stamen-tiles-c.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png",                                                 
            "https://stamen-tiles-d.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png"                                                  
          ]                                                                                                                       
      })                                                                                                                          
                                                                                                                                                  })                                                                                                                            
  ],                                                                                                                              
  view: new ol.View({                                                                                                             
    center: ol.proj.fromLonLat([-2.7, 51]),                                                                                       
    zoom: 9                                                                                                                       
  })                                                                                                                              
});

// Create the scalelines within the two div elements

var scaleLineMetric = new ol.control.ScaleLine({                                                                                  
  units: ['metric'],                                                                                                              
  target: document.getElementById("scaleline-metric")                                                                             
});                                                                                                                                           var scaleLineImperial = new ol.control.ScaleLine({                                                                                
  units: ['imperial'],                                                                                                            
  target: document.getElementById("scaleline-imperial")                                                                           
});

// Add the scaleline controls to the map
                                                                                       
map.addControl(scaleLineMetric);                                                                                                  
map.addControl(scaleLineImperial);                                                                                                

</script>