Leaflet Print Map – Legends, Title, Layer, Color

This article i.e Leaflet Print Map – Legends, Title, Layer, Color is for how can we take a beautiful map on paper from web by making it printable, with all map elements as map title and legends etc. Here we will use leaflet-image plugin from leaflet JavaScript library. This plugin uses the map and canvas HTML tag.

Leaflet Print Map – Legends, Title, Layer, Color

This plugin can be downloaded from https://github.com/mapbox/leaflet-image/blob/gh-pages/leaflet-image.js link. To implement this plugin on your system, you first need to create map, which can be done by following this article.

First of all add the leaflet library in your document by adding these scripts.

 <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css"/>
 <script  scr="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js" ></ script>

Thereafter, create a division using

Leaflet Print Map - Legends, Title, Layer, Color

After adding the leaflet-image plugin in document you can call the leafletimage() method, which takes map as input and calls to callback function.

This function create a canvas html tag sets its width and heigth. Which draws layer in same order as drawn on map i.e. tile, path and markers. Before calling this function you must create function to get legend and map title with leaflet.

Here we have create getMapHeading() function which takes context and canvas as input. So what is Content?

var context = canvas.getContext(contextType);

getContext()– method returns a drawing context on the canvas.

contextType-Is a DOMString containing the context identifier defining the drawing context associated to the canvas.  “2d”, leading to the creation of a CanvasRenderingContext2D object representing a two-dimensional rendering context.

canvas– element is used to draw graphics on a web page.

Map Title in Leaflet Map

Take the map title in a variable and measure its width. if its width is less than one forth of canvas width then set its width according to canvas width. else the tile is larger then split it.

function getMapHeading(context,canvas){
 var mapheading = $("#mapTitle").html();
 var pix = context.measureText(mapheading).width;
 if(pix<(canvas.width/4))
 {
 var xval = (canvas.width-pix*4)/2;
 context.font = "bold 35px proximanova-semibold-webfont";
 context.fillText(mapheading,xval,40);
 }
 else
 {
 mapheading = mapheading.split(" ");
 //console.log("mapheading",mapheading);
 //mapheading = mapheading.toString();
 pix = canvas.width/4;
 var line = "",nextline = "";
 for(var i=0; i<mapheading.length; i++)
 {
 if(context.measureText(line).width<pix)
 {
 line += mapheading[i] + " ";
 }
 else
 {
 nextline += mapheading[i] + " ";
 }
 }
 context.font = "bold 35px proximanova-semibold-webfont";
 context.fillText(line,25,40);
 if(nextline.length>0)
 {
 context.fillText(nextline,25,80);
 }
 }
 }

Map Legends in Leaflet Map Printable

Similarly function is created for legend as getLegeds(). In this function we have taken legend title, icon, range and containing div in variables. Check everything and recreate the context as you want it to be appeared on print.

Leaflet Print Map - Legends, Title, Layer, Color

function getLegends(context,canvas){
 var legendheading = $("#legendTitle").html();
 var paralegend = $('.paralegend');
 var legendclr = $('.paralegend i');
 var divlegend = $('.leaflet-control.leaflet-bottom.leaflet-left');
 var width = divlegend.width(),height = divlegend.height();
 var x =10,dx=20,dy=20;
 var y = canvas.height-height+15;
 var legendtext = [],legendcolor = [],rects = [];
 for(var i=0; i<paralegend.length;i++)
 {
 legendtext.push(paralegend[i].innerText);
 }
 for(var j=0; j<legendclr.length; j++)
 {
 legendcolor.push(legendclr[j].style.background);
 }
 for(var l=0;l<legendcolor.length;l++)
 {
 rects.push(new shape(x,y,dx,dy,legendcolor[l],legendtext[l]));
 y=y+25;
 }
 context.font = "bold 15px proximanova-semibold-webfont";
 context.fillText(legendheading,x,canvas.height-height);
 for(var k=0;k<rects.length;k++)
 {
 var sqr = rects[k];
 context.fillStyle = sqr.fill;
 context.fillRect(sqr.x,sqr.y,sqr.dx,sqr.dy);
 context.strokeStyle='#000';
 context.lineWidth=1;
 context.strokeRect(sqr.x,sqr.y,sqr.dx,sqr.dy);
 context.fillStyle = 'black';
 context.font = "15px proximanova-semibold-webfont";
 context.fillText(sqr.text,sqr.x+25,sqr.y+15);
 }
 }

Leaflet-image plugin for printing map – Leaflet Print Map – Legends, Title, Layer, Color

Now Call the leafletImage() function and provide the create map and call the callback function. In this callback you can call the getMapHeading() and getLegends() functions. For this function we have taken the image data in data variable by using getImageData() method. And The getImageData() method returns an ImageData object that copies the pixel data for the specified rectangle on a canvas.

So the rectangle is given as whole canvas. Then set the globalCompositionOperation as destination-over. The globalCompositeOperation property sets or returns how a source (new) image are drawn onto a destination (existing) image. The putImageData() puts the image data back onto the canvas. The drawImage method draws an image onto the canvas.

leafletImage(map, function(err, canvas) {
 var context = canvas.getContext("2d");
 getMapHeading(context,canvas);
 getLegends(context,canvas);
 var data = context.getImageData(0, 0, canvas.width, canvas.height);

//store the current globalCompositeOperation
 var compositeOperation = context.globalCompositeOperation;

//set to draw behind current content
 context.globalCompositeOperation = "destination-over";

//set background color
 //context.fillStyle = "grey";
 context.fillStyle = "#ddd";
 //draw background / rect on entire canvas
 context.fillRect(0, 0, canvas.width, canvas.height);

var dataURL = canvas.toDataURL("image/png");
 console.log(dataURL);
 context.clearRect (0,0,canvas.width, canvas.height);

//restore it with original / cached ImageData
 context.putImageData(data, 0,0);

//reset the globalCompositeOperation to what it was
 context.globalCompositeOperation = compositeOperation;

context.drawImage(canvas,0,0);
 print.href = dataURL;
 print.download = "map.png";
 });

finally On printing the map will look like
Leaflet Print Map - Legends, Title, Layer, Color
Leaflet Print Map – Legends, Title, Layer, Color

Hope you enjoyed this article and are now able to create Leaflet Print Map – Legends, Title, Layer, Color. If you find any problem in implementing a printable map, do comment below. Thanks.

Create beautiful dynamic Legend map – Leafletjs TopoJson

In this article we are going to add legends to choropleth map with topojson Data using leaflet. Legends are the element of map that provides information about map with the help of symbols. Here symbol can be colour, shapes, figures etc. The choropleth map gives information using colours. Lets play around with : Create beautiful Legend map – leafletjs topojson. If you are very new to Leafletjs then before going through this article you should look over to Getting started with Leafletjs article and how to render topojson with leaflet js.

Dynamic Legend map – Leafletjs TopoJson

Lets get started with code. For this first we need to create a method getColor(d). The method takes “d” as parameter, which takes a specific value from topojson data, and then returns the colour value (in form of colour) after comparison. For instance, if d is greater than 5000 then return red color i.e ‘#FF0000’ otherwise return blue colour i.e ‘#0000ff’. Here colour codes are given in hexadecimal value you can give RGB value or colour name.  We will create this function as:

function getColor(d) {
return d > 5000000 ? ‘#7a0177’ :
d > 200000? ‘#BD0026’ :
d > 80000? ‘#E31A1C’ :
d > 10000? ‘#FC4E2A’ :
d > 5000 ? ‘#FD8D3C’ :
d > 500 ? ‘#FEB24C’ :
d > 0 ? ‘#FED976’ :
‘#FFEDA0’;
}

Now to show the legend section on map, we need to create a division with the help of DomUtil and add that to the map. Here a variable name legend is created which is positioned to bottom right. The style “position: ‘bottomright’ “ is done using CSS.  L.control is a base class for implementing map controls from leaflet javascript library. This handles positioning. All other controls extend from this class.

var legend = L.control({position: ‘bottomright’});

The above function i.e getColor() will be called once we add Legends on Map. for that we need to create an event of adding legends on map.  onAdd() method, which is from leaflet’s control class returns the container DOM element for the control and add listeners on relevant map events. Here it takes value as function that returns HTML element (div) as like: 

legend.onAdd = function (map) { } 

Then DomUtil class has used.  But what is DOM (data object model), connects web pages to scripts. It is object oriented representation of web pages, which can be modified with scripting language like javaScript. DomUtil works with Dom tree. Here create() method has used which is from leaflet’s DomUtil class. This method returns a HTML element and takes parameter as tag name and class name. Tag name to create that element on document and class name style that element. Here HTML element is division and two classes are given as info and legend. An array name grades is created with value given by getColor(d) method.

var div = L.DomUtil.create(‘div’, ‘info legend’),
grades = [0,500,5000,10000,80000,200000,5000000];

To add field and colour in legend on map, a for loop has written. This shows variable i has initial value as zero and condition is as, “if variable i is less than length of array grades then loop will run and after one cycle increment will take place”.

HTML element div has styled inside loop having background colour values from getColor() method and &ndash is HTML entities used for typography.

for (var i = 0; i < grades.length; i++) {
div.innerHTML += ‘<i style=”background:’ + getColor(grades[i] + 1) + ‘”></i> ‘ + grades[i] + (grades[i + 1] ? ‘&ndash;’ + grades[i + 1] + ‘<br>’ : ‘+’);
}
return div;
};

The following statement adds the legends on map i.e:

legend.addTo(newMap);

As in create() method we have used info and legend class and that classes are designed inside style HTML tag i.e as :

<style>
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.legend {
background-color: “black”;
line-height: 25px;
color: #555;
width: auto;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
</style>

Here is how the output will look like. I had taken UK topojson file. If you have shapefile to geojson or kml file, you may look over to an article to convert shapefile to TopoJson or Geojson to Topojson Conversion. If you have Kml file then you can convert the kml file to Shapefile and then to TopoJson file.

dynamic Legend map - Leafletjs TopoJson
dynamic Legend map – Leafletjs TopoJson

This will finally make you to create dynamic legends with leafletjs library in Mapping system. I hope article helped you. If you find any problem in creating dynamic legends, do comment below in the box provided, we will discuss and solve the issue.