Skip to content

Serving Custom Tiles using Martin

LucasDworschak edited this page Aug 6, 2024 · 1 revision

Martin can basically serve tiles using 2 different ways: Views and Functions

Views

The most simple way is to just create a view of the necessary data you want to serve and specify this view in your config.yaml file.

Example: peak view:

CREATE VIEW peaks AS 
	SELECT planet_osm_point.name,
	    planet_osm_point.tags->'ele'::text AS ele,
	    planet_osm_point.way -- necessary field for coordinates
   FROM planet_osm_point
  WHERE planet_osm_point."natural" = 'peak'::text;

peak config:

postgres:

  ...
  
  tables:
    peaks:
      schema: public
      table: peaks
      srid: 3857
      geometry_column: way
      geometry_type: POINT
      properties:
        name: text
        ele: int

...

Although this option can be used to provide the data very fast with limited configurations needed, it also doesn't give you too many options in tuning how much is served at which zoom levels.

Functions

The alternative to views are functions as tile sources (https://maplibre.org/martin/sources-pg-functions.html)

In Postgres you can specify functions that are to be executed. In those functions more freedom is given in how detailed you want to configure your query. Martin requires the function to have 3 integer parameters (z,x,y values for the tile you are currently requesting) and a bytea as a return type. The bytea is written by the ST_AsMVT function that is available in postgres/postgis. Additionally it is also possible to specify a fourth parameter where you can pass through additional values to your function.

Example: peak function:

CREATE OR REPLACE
    FUNCTION peak_tile(z integer, x integer, y integer)
    RETURNS bytea AS $$
DECLARE
    mvt bytea;
BEGIN
    -- NOTE it is possible to add if branches here for better individual configurations
    SELECT INTO mvt ST_AsMVT(tile, 'peak_tile', 4096, 'geom', 'id') FROM (
        SELECT
            id, name, long, lat,
            ele,
           
            -- transform the point into the current vector tile -> x/y points lie within (0,4096)
            -- this is necessary for vector tiles on a flat map like leaflet
            ST_AsMVTGeom(
                ST_Transform(way, 3857),
                ST_TileEnvelope(z,x,y),
                4096, 64, true
            ) as geom

        FROM peaks
        -- only select points where the current position and current tile bbox overlap
        WHERE ST_TRANSFORM(way,4674) && ST_Transform(ST_TileEnvelope(z,x,y), 4674)
        ORDER BY ele DESC
        -- possible to use z parameter here to to differentiate how much is returned per zoom level
        LIMIT 1
    ) as tile;

  RETURN mvt;
END
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;

peak config:

postgres:

  ...
  
  functions:
    peak_tile:
      schema: public
      function: peak_tile
      minzoom: 7
      properties:
        name: text
        long: double
        lat: double
        ele: int

...
Clone this wiki locally