我正在使用 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>