我正在尝试在Node.js中设置一个Web服务器,该服务器提供使用MapboxGL JS在浏览器中显示的矢量图块。矢量图块的数据存储在PostGIS数据库中。
这是我的数据库方案:CREATE TABLE IF NOT EXISTS earthquakes( table_id SERIAL, properties jsonb not null, geom geometry(GeometryZ,4326), primary key (table_id));
地震在geojson内部具有属性,我将每个要素存储在数据库中。
例如,地震具有以下属性:"properties": { "id": "ak16994521", "mag": 2.3, "time": 1507425650893, "felt": null, "tsunami": 0 }
。您可以看到所有geojson here。
我当前的设置似乎朝着正确的方向发展,因为我可以看到矢量图块正在加载并显示在浏览器中,并且渲染结果是正确的。
但是,当我单击某个功能时,仅返回table_id而不返回每个功能的属性。
如何发送属性?
var zlib = require('zlib');
var express = require('express');
var mapnik = require('mapnik');
var Promise = require('promise');
var SphericalMercator = require('sphericalmercator');
var mercator = new SphericalMercator({
size: 256 //tile size
});
mapnik.register_default_input_plugins();
var app = express();
app.get('/:namelayer/:z/:x/:y.pbf', (req, res, next) => {
var options = {
x: parseInt(req.params.x),
y: parseInt(req.params.y),
z: parseInt(req.params.z),
layerName: req.params.namelayer
};
makeVectorTile(options).then( (vectorTile) => {
zlib.deflate(vectorTile, (err, data) => {
if (err) return res.status(500).send(err.message);
res.setHeader('Content-Encoding', 'deflate');
res.setHeader('Content-Type', 'application/x-protobuf');
return res.send(data);
});
});
});
function makeVectorTile(options) {
var extent = mercator.bbox(options.x, options.y, options.z, false, '3857');
var map = new mapnik.Map(256, 256, '+init=epsg:3857');
map.extent = extent;
var layer = new mapnik.Layer(options.layerName);
layer.datasource = new mapnik.Datasource({
type: process.env.DB_TYPE,
dbname: process.env.DB_DATABASE,
table: options.layerName,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
layer.styles = ['default'];
map.add_layer(layer);
return new Promise( (resolve, reject) => {
var vtile = new mapnik.VectorTile(parseInt(options.z), parseInt(options.x), parseInt(options.y));
map.render(vtile, function (err, vtile) {
if (err) return reject(err);
console.log(`${vtile.getData().length} KB`);
resolve(vtile.getData());
});
});
};
module.exports = app;
答案 0 :(得分:0)
感谢所有帮助我的人。
这是带有查询的代码,可用于切片服务器。
我使用此查询来获取键数组:
const sql = SELECT ARRAY_AGG(f)作为密钥FROM(SELECT jsonb_object_keys(properties)f由$ {options.layerName}分组,按f) 你;
随后,该函数创建一个查询以获取每个属性作为名为generateSQL的列。
我希望代码会有用。
/** CONSTANTS **/
const TILE_SIZE = 256;
const PROJECTION_STRING = '+init=epsg:3857';
/** LIBRARIES **/
var zlib = require('zlib');
var express = require('express');
var mapnik = require('mapnik');
var Promise = require('promise');
var SphericalMercator = require('sphericalmercator');
const { pool } = require('../postgressql/config');
var mercator = new SphericalMercator({
size: TILE_SIZE
});
mapnik.register_default_input_plugins();
var app = express();
app.get('/:namelayer/:z/:x/:y.pbf', (req, res, next) => {
var options = {
x: parseInt(req.params.x),
y: parseInt(req.params.y),
z: parseInt(req.params.z),
layerName: req.params.namelayer
};
const sql = `SELECT ARRAY_AGG(f) as keys FROM (SELECT jsonb_object_keys(properties) f FROM ${options.layerName} group by f) u`;
try {
pool.query(sql, (error, results) => {
if (error) {
return res.status(500).json({
ok: false,
message: error
});
}
const keys = (results && results.rows && results.rows.length > 0 && results.rows[0].keys && results.rows[0].keys.length >0) ? results.rows[0].keys.slice() : [];
const sql = generateSQL(options, keys);
makeVectorTile(options, sql).then( (vectorTile) => {
zlib.deflate(vectorTile, (err, data) => {
if (err) {
return res.status(500).send(err.message);
}
res.setHeader('Content-Encoding', 'deflate');
res.setHeader('Content-Type', 'application/x-protobuf');
res.setHeader('Access-Control-Allow-Origin', '*');
return res.send(data);
});
});
});
} catch (e) {
res.status(404).send({
error: e.toString(),
});
}
});
function generateSQL(options, keys) {
if (keys.length === 0) {
return `select table_id, geom from ${options.layerName}`;
} else {
let sql = "";
keys.forEach( key => {
sql = sql + `(properties->>'${key}') as ${key},`;
});
sql = `select table_id, ${sql} geom from ${options.layerName}`
return sql;
}
};
function makeVectorTile(options, sql) {
var extent = mercator.bbox(options.x, options.y, options.z, false, '3857');
var map = new mapnik.Map(TILE_SIZE, TILE_SIZE, PROJECTION_STRING);
map.extent = extent;
var layer = new mapnik.Layer(options.layerName);
layer.datasource = new mapnik.Datasource({
type: process.env.DB_TYPE,
dbname: process.env.DB_DATABASE,
// table: options.layerName,
table: `(${sql}) as tile`,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
layer.styles = ['default'];
map.add_layer(layer);
return new Promise( (resolve, reject) => {
var vtile = new mapnik.VectorTile(parseInt(options.z), parseInt(options.x), parseInt(options.y));
map.render(vtile, function (err, vtile) {
if (err) {
return reject(err);
}
console.log(`${vtile.getData().length} KB`);
resolve(vtile.getData());
});
});
};
module.exports = app;