Skip to main content

Static Maps


protomaps.js can also be used to render non-interactive maps via the Canvas API. This does not require Leaflet or any other dependencies. the Static class takes the same arguments as a leafletLayer:

  • url: a Z/X/Y endpoint or a PMTiles archive.
  • paint_rules, label_rules: let you customize the appearance of the map.

The simplest possible code for rendering a static map:

<canvas id="map" style="width:600px;height:400px"></canvas><script>  let map = new protomaps.Static({url:"{z}/{x}/{y}.pbf?key=YOUR_API_KEY"})  let canvas = document.getElementById("map")  map.drawCanvas(canvas,[22.1777,114.1635],10)</script>


The example above "owns" the target canvas - it modifies the canvas width and height based on the screen's pixel density, and fills the entire canvas with the drawing command. For more low level control, use drawContext, to achieve layouts such as map insets (example)

<canvas id="map" style="width:600px;height:400px"></canvas><script>    let canvas = document.getElementById("map")
    // set the actual dimensions of canvas based on pixel density    canvas.width = window.devicePixelRatio * 600    canvas.height = window.devicePixelRatio * 400
    let context = canvas.getContext('2d')    context.scale(window.devicePixelRatio,window.devicePixelRatio)    context.fillStyle = "cadetblue"    context.fillRect(0,0,600,400)    let map = new Static({url:"{z}/{x}/{y}.pbf?key=YOUR_API_KEY"})    context.translate(50,50)
    // drawContext is async, so we need to wait for it to finish    map.drawContext(context,256,256,[22.1777,114.1635],8).then(() => {        context.fillStyle = "aquamarine"        context.translate(200,50)        context.fillRect(-10,-10,276,276)        map.drawContext(context,256,256,[22.1777,114.1635],10)    })</script>

D3 integration#

D3.js is a powerful library for creating visualizations in the browser. It can be used to display geographic data, but does not have any built-in facilities for displaying labeled basemaps. d3-tile can be used to display basemap tiles, but these are limited to resolution-dependent, non-customizable raster images.

protomaps.js can be used to create a canvas basemap for d3.js data in the Mercator projection using the drawCanvasBounds method: See the example

Example of a basic d3.js script for displaying GeoJSON:

let object = {    type:'Feature',    geometry:{type:'LineString',coordinates:[[-122.3939,37.7951],[-122.4351,37.7627]]}}let width = 800let height = 600var projection = d3.geoMercator()let val = projection.fitExtent([[50,50],[width-50,height-50]],object)var path = d3.geoPath().projection(projection)let svg ="#overlay")svg.selectAll("path").data([object]).enter()    .append("path")    .attr("d",path)

the projection object that has been fitted to the data can then be used to calculate the top-left and bottom-right corners, in geographic coordinates, via invert. These corners are then passed to drawCanvasBounds:

let map = new protomaps.Static({url:'{z}/{x}/{y}.pbf?key=1003762824b9687f'})let top_left = projection.invert([0,0])let bottom_right = projection.invert([width,height])map.drawCanvasBounds("#basemap").node(),top_left,bottom_right,width)