7

I'm trying to create mvt using postgis by following this tutorial

If understand correctly ST_AsMVT is used to create a layer and generated layer will have id. same id can be used to apply styles.

SELECT ST_AsMVT(q, 'buildings', 4096, 'geom')
FROM (
  SELECT id, name, type,
    ST_AsMvtGeom(
      geometry,
      BBox(16597, 11273, 15),
      4096,
      256,
      true
    ) AS geom
  FROM import.osm_buildings
  WHERE geometry && BBox(16597, 11273, 15)
  AND ST_Intersects(geometry, BBox(16597, 11273, 15))
) AS q;

Will create a layer named admin with id admin. styling can be applied by using this id - from index.html

{
  "id": "building",
  "source": "osm",
  "source-layer": "buildings",
  "type": "fill",
  "paint": {
    "fill-color": "#D8CEC3",
    "fill-outline-color": "#C5C0BB",
    "fill-opacity": 1
  }
},

How can we create a single layer with multiple id's so we can style them separately.

I'm complete in newbie to PostGIS and Tiles stuff any other approaches and suggestions are welcome

2
  • I believe you can just use UNION SELECT to select from the separate tables, so that you end up with one MVT file, with different id and source-layer, so that the styling will work differently for each one. Mar 6, 2019 at 19:12
  • Hi, Thanks for reply. I am not sure it will generate specific ID [i'm just assuming that]. if you look at openmaptiles [github.com/openmaptiles/openmaptiles/tree/master/layers]. They did not specify any id in the code [or may be i'm missing some thing]. Mar 11, 2019 at 5:38

2 Answers 2

7

You can use UNION to combine the queries.

Your server can then concat the binaries before sending them out. I found out that doing this in SQL took to long and increased the compute time to much. You can stack the UNION queries for more objects.

Here is an example of the query I used:

(
SELECT 'road' as name, ST_AsMVT(q, 'road', 4096, 'geom') as tile
FROM (
  SELECT id, name, class,
    ST_Simplify(ST_AsMvtGeom(
      geometry,
      BBox(${x}, ${y}, ${z}),
      4096,
      256,
      true
    ), ${currentTolerance}) AS geom
  FROM import.osm_roads
  WHERE geometry && BBox(${x}, ${y}, ${z})
  AND ST_Intersects(geometry, BBox(${x}, ${y}, ${z}))
  ) as q
)
UNION
(
SELECT 'building' as name, ST_AsMVT(q, 'building', 4096, 'geom') as tile
FROM (
  SELECT id, name, class,
    ST_Simplify(ST_AsMvtGeom(
      geometry,
      BBox(${x}, ${y}, ${z}),
      4096,
      256,
      true
    ), ${currentTolerance}) AS geom
  FROM import.osm_buildings
  WHERE geometry && BBox(${x}, ${y}, ${z})
  AND ST_Intersects(geometry, BBox(${x}, ${y}, ${z}))
 ) as q
)

The server would then concat the binaries. For example using NodeJS:

var buffers = [];
for (var i = 0; i < result.rows.length; i++) {
  buffers.push(result.rows[i].tile);
}
var finalbuffer = Buffer.concat(buffers)
res.send(finalbuffer);

To view them in MapboxGL:

{
  "id": "road",
  "source": "osm",
  "source-layer": "road",
  "type": "line",
  "layout": {
    "line-join": "round",
    "line-cap": "round"
  },
  "paint": {
    "line-color": "#FF8888",
    "line-width": 2,
    "line-opacity": 0.75
  }
},
{
  "id": "building",
  "source": "osm",
  "source-layer": "building",
  "type": "fill",
  "paint": {
    "fill-color": "#D8CEC3",
    "fill-outline-color": "#C5C0BB",
    "fill-opacity": 1
  }
}

To view using OpenLayers:

function(feature, resolution){
  var styles = [];
  var featureclass = feature.get('class');
  // use layer attribute similar to 'source-layer' above (building and road)
  var layer = feature.get('layer');
  // If it has the class 'yes' or 'house'
  if( layer == 'building' && ['yes','house'].includes(featureclass) ){
    styles.push(new Style({
        fill: new Fill({
          color: '#000000',
          opacity: 0
        }),
        stroke: new Stroke({
          color: '#FF0000',
          width: 1
        }),
        zIndex: 0,
      }));
  }
  // add tests for more styles
  return styles;
}

Here an example of the view using MapboxGL: MapboxGL with MVT rendering

4
select (
    SELECT ST_AsMVT(tile, 'bou', 4096, 'geom') AS tile
    FROM (
        SELECT w.fname, w.fscale
            , ST_AsMVTGeom(w.geom, Box2D(ST_MakeEnvelope(120.23, 30.2343, 120.5859, 30.5859, 3857)), 4096, 0, true) AS geom
        FROM bou w
    ) tile
    WHERE tile.geom IS NOT NULL 
)||(
    SELECT ST_AsMVT(tile, 'tran', 4096, 'geom') AS tile
    FROM (
        SELECT w.fname, w.fscale
            , ST_AsMVTGeom(w.geom, Box2D(ST_MakeEnvelope(120.23, 30.2343, 120.5859, 30.585, 3857)), 4096, 0, true) AS geom
        FROM tran w  where fscale < 14
    ) tile
    WHERE tile.geom IS NOT NULL 
) as mvt
1
  • It is recommended to describe your code.
    – wondim
    Sep 5, 2020 at 12:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.