This commit is contained in:
79
routes/tiles.js
Normal file
79
routes/tiles.js
Normal file
@@ -0,0 +1,79 @@
|
||||
const express = require("express");
|
||||
const Database = require("better-sqlite3");
|
||||
const path = require("path");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// =======================
|
||||
// MBTiles DB (READONLY)
|
||||
// =======================
|
||||
const mbtilesPath = path.join(__dirname, "..", "data", "map.mbtiles");
|
||||
const tileDb = new Database(mbtilesPath, { readonly: true });
|
||||
|
||||
// =======================
|
||||
// 📊 METADATA
|
||||
// =======================
|
||||
const metadataRows = tileDb.prepare("SELECT name, value FROM metadata").all();
|
||||
const metadata = {};
|
||||
|
||||
for (const row of metadataRows) {
|
||||
metadata[row.name] = row.value;
|
||||
}
|
||||
|
||||
// decide content-type
|
||||
let contentType = "application/octet-stream";
|
||||
|
||||
if (metadata.format === "pbf") {
|
||||
contentType = "application/x-protobuf";
|
||||
} else if (metadata.format === "png") {
|
||||
contentType = "image/png";
|
||||
} else if (metadata.format === "jpg" || metadata.format === "jpeg") {
|
||||
contentType = "image/jpeg";
|
||||
}
|
||||
|
||||
// =======================
|
||||
// METADATA API
|
||||
// =======================
|
||||
router.get("/metadata/info", (req, res) => {
|
||||
res.json(metadata);
|
||||
});
|
||||
|
||||
// =======================
|
||||
// TILE API (XYZ → TMS)
|
||||
// =======================
|
||||
router.get("/:z/:x/:y", (req, res) => {
|
||||
const z = Number(req.params.z);
|
||||
const x = Number(req.params.x);
|
||||
const y = Number(req.params.y);
|
||||
|
||||
if (!Number.isInteger(z) || !Number.isInteger(x) || !Number.isInteger(y)) {
|
||||
return res.status(400).json({ error: "Invalid tile coordinates" });
|
||||
}
|
||||
|
||||
// convert XYZ → TMS
|
||||
const tmsY = (1 << z) - 1 - y;
|
||||
|
||||
const stmt = tileDb.prepare(`
|
||||
SELECT tile_data
|
||||
FROM tiles
|
||||
WHERE zoom_level = ?
|
||||
AND tile_column = ?
|
||||
AND tile_row = ?
|
||||
`);
|
||||
|
||||
const tile = stmt.get(z, x, tmsY);
|
||||
|
||||
if (!tile) {
|
||||
return res.status(404).json({ error: "Tile not found" });
|
||||
}
|
||||
|
||||
res.setHeader("Content-Type", contentType);
|
||||
|
||||
if (metadata.format === "pbf") {
|
||||
res.setHeader("Content-Encoding", "gzip");
|
||||
}
|
||||
|
||||
res.send(tile.tile_data);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user