首页 > 解决方案 > 使用 Express.JS 为矢量图块发送多个响应

问题描述

我正在使用 PostgreSQL、Node.JS 和 OpenLayers 创建矢量图块。目前,我能够使用存储在 PostgreSQL 中的数据创建多层矢量图块,但我认为我遵循的过程是重复的,并且不确定这是正确的方法做。目前,当我运行服务器时,它会在地图上一一加载所有图层。有什么办法可以同时加载所有图层吗?

代码:

// mercator
var SphericalMercator = require('@mapbox/sphericalmercator');
var mercator = new SphericalMercator({size: 256})

// database library
var {Client} = require('pg')
var db = new Client('postgres://postgres:password@localhost:5432/vtiles');
db.connect();

// http server
var express = require('express');
var app = express();

app.use(express.static(__dirname + '/public'));

// roads
var layerName1 = 'roads';
app.get(`/tiles/${layerName1}/:z/:x/:y.mvt`, async (req, res) => {
  var bbox = mercator.bbox(req.params.x, req.params.y, req.params.z, false);
  var query = `
      SELECT ST_AsMVT(q, '${layerName1}', 4096, 'geom') FROM (
        SELECT 
          osm_id, name, type,
          ST_AsMVTGeom(
            geom,
            ST_MakeEnvelope(${bbox[0]}, ${bbox[1]}, ${bbox[2]}, ${bbox[3]}, 4326),
            4096,
            256,
            true
          ) geom FROM ${layerName1} WHERE type IS NOT NULL
        ) q
    `;
  try {
    
    var tiles = await db.query(query);
    var tile = tiles.rows[0];
    res.setHeader('Content-Type', 'application/x-protobuf');
    if (tile.st_asmvt.length === 0) {
      res.status(204);
    }
    res.send(tile.st_asmvt);
  } catch (err) {
    res.status(404).send({ error: err.toString() });
  }
});

// buildings
var layerName2 = 'buildings';
app.get(`/tiles/${layerName2}/:z/:x/:y.mvt`, async (req, res) => {
  var bbox = mercator.bbox(req.params.x, req.params.y, req.params.z, false);
  var query = `
      SELECT ST_AsMVT(q, '${layerName2}', 4096, 'geom') FROM (
        SELECT 
          osm_id, name, type,
          ST_AsMVTGeom(
            geom,
            ST_MakeEnvelope(${bbox[0]}, ${bbox[1]}, ${bbox[2]}, ${bbox[3]}, 4326),
            4096,
            256,
            true
          ) geom FROM ${layerName2} WHERE type IS NOT NULL
        ) q
    `;
  try {
    
    var tiles = await db.query(query);
    var tile = tiles.rows[0];
    res.setHeader('Content-Type', 'application/x-protobuf');
    if (tile.st_asmvt.length === 0) {
      res.status(204);
    }
    res.send(tile.st_asmvt);
  } catch (err) {
    res.status(404).send({ error: err.toString() });
  }
});

app.listen(8080);

HTML 代码

<!DOCTYPE html>
<html>
  <head>
    <title>Vector Tile Example</title>
    <link
      rel="stylesheet"
      href="https://openlayers.org/en/v5.3.0/css/ol.css"
      type="text/css"
    />
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    
    <style>
      .map {
        width: 100%;
        height: 100vh;
      }
      body {
        margin: 0;
      }
    </style>
  </head>
  <body>
    <div id="status"></div>
    <div id="map" class="map"></div>
        </div>
    <script>
      var tileLayer = new ol.layer.Tile({
        //source: new ol.source.Stamen({ layer: 'terrain-background' })
        source: new ol.source.OSM()
      })

      var vectorLayer1 = new ol.layer.VectorTile({
        source: new ol.source.VectorTile({
          format: new ol.format.MVT(),
          url: 'http://localhost:8080/tiles/roads/{z}/{x}/{y}.mvt'
        }),
        style: function(feature) {
          return new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: 'rgba(30, 30, 30, 0.5)',
              width: ['step', ['zoom'], 0.4, 14, 1, 16, 2, 18, 4, 20, 8]
            })
          })
        }
      })

      var vectorLayer2 = new ol.layer.VectorTile({
        source: new ol.source.VectorTile({
          format: new ol.format.MVT(),
          url: 'http://localhost:8080/tiles/buildings/{z}/{x}/{y}.mvt'
        }),
        style: function(feature) {
          return new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: 'rgba(30, 30, 30, 0.5)',
              width: ['step', ['zoom'], 0.4, 14, 1, 16, 2, 18, 4, 20, 8]
            })
          })
        }
      })
      var map = new ol.Map({
        target: 'map',
        layers: [tileLayer, vectorLayer1,vectorLayer2],
        view: new ol.View({
          center: ol.proj.fromLonLat([103.8198,1.3521]),
          zoom: 13
        })
      })
    
      </script>
  </body>
</html>

标签: node.jspostgresqlexpressopenlayersvector-tiles

解决方案


推荐阅读