Add new property values to vector tiles layer feature

192 views Asked by At

Im using @mapbox/vector-tile to read VectorTiles from a .mbtiles file. Now, for feature of the tile layers, I need to add a new property value. Currently I have, for example, id: 123, name: "abc" in my properties, and I want to add age: "33". I'm able to read the properties, but I'm not able to add new ones. This is the code I have:

const express = require("express");
const path = require("path");
const vtpbf = require('vt-pbf')
const MBTiles = require('@mapbox/mbtiles');
const { VectorTile } = require('@mapbox/vector-tile');
const Pbf = require('pbf');

const app = new express();

app.get('/tiles/:z/:x/:y.vector.pbf', async (req, res) => {
    let { z, x, y } = req.params;

    new MBTiles(path.join(__dirname, `shapes_uf.mbtiles`) + "?mode=ro", function(err, mbtiles) {
        mbtiles.getInfo(function(err, info) {
          const layerName = info.vector_layers[0].id;
            if (err) {
          return res.status(400).send(`Make sure ${path.basename(fileName)} is valid MBTiles.`)
        }

            mbtiles.getTile(z, x, y, function (err, data, headers) {

                if (err) {
                    return res.status(404).send(err.message)
                } else {
                    const tile = new VectorTile(new Pbf(data))

                    const featureLength = tile.layers[layerName].length;

                    for (let x = 0; x < featureLength; x += 1) {
                        console.log("current properties: ", tile.layers[layerName].feature(x).properties)
                        tile.layers[layerName].feature(x).properties["age"] = "33";
                        // nothing changed here!
                    }

                  res
                    .setHeader(
                      'Content-Type',
                      'application/x-protobuf'
                    )
                    .status(200).send(data)
                    }
            });
        });
    })
})

const port = process.env.PORT || 3000;

app.listen(port, () => {
    console.log("Server listening on ", port);
});

Thanks!

1

There are 1 answers

0
Cristiano Sarmento On

I've found a solution using the @mapbox/tile-decorator package, as follows:

const express = require("express");
const path = require("path");
const MBTiles = require('@mapbox/mbtiles');
const { updateLayerProperties, read, write } = require('@mapbox/tile-decorator')

function toBuffer(arrayBuffer) {
  const buffer = Buffer.alloc(arrayBuffer.byteLength);
  const view = new Uint8Array(arrayBuffer);
  for (let i = 0; i < buffer.length; ++i) {
    buffer[i] = view[i];
  }
  return buffer;
}

const app = new express();

app.get('/tiles/:z/:x/:y.vector.pbf', async (req, res) => {
    let { z, x, y } = req.params;

    let tileSource = "shapes_uf";
    if (z > 7) {
        tileSource = "municipios_br";
    }

    new MBTiles(path.join(__dirname, `${tileSource}.mbtiles`) + "?mode=ro", function(err, mbtiles) {
        if (err) {
            console.log("Error loading tiles: ", err.message)
        }

        mbtiles.getTile(z, x, y, function (err, data, headers) {
            console.log(data)
            if (err) {
                // console.log("err: ", err)
                return res.status(404).send(err.message)
            } else {

                const tile = read(data);

                for (let x = 0; x < tile.layers.length; x += 1) {
                    const newData = []

                    for (let x = 0; x < tile.layers[x].values.length; x += 1) {
                        newData.push({ age: "33"})
                    }

                    updateLayerProperties(tile.layers[x], newData)
                }

                const resp = write(tile)

              res
                .setHeader(
                  'Content-Type',
                  'application/x-protobuf'
                )
                .status(200).send(toBuffer(resp))
                }
        });
        });

})

const port = process.env.PORT || 3000;

app.listen(port, () => {
    console.log("Server listening on ", port);
});