Convert to esm module syntax (#606)
* switch to esm module * Update package.json * change to maplibre package * fix tests * eslint * remove extra package updates * Delete package-lock.json * change 'fs' to 'node:fs' * put back node 10. without the package updates this still works * remove trailing commas * remove unassociated fix / formatting * remove unassociated fix * remove eslint from this PR * remove unassociated fix * lint * Merge remote-tracking branch 'upstream/master' into esm_update * fix mlgl * update maplibre-native to new version with arm64 * update minor version
This commit is contained in:
@@ -1,37 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const advancedPool = require('advanced-pool');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
const util = require('util');
|
||||
const zlib = require('zlib');
|
||||
|
||||
// sharp has to be required before node-canvas
|
||||
// see https://github.com/lovell/sharp/issues/371
|
||||
const sharp = require('sharp');
|
||||
|
||||
const { createCanvas } = require('canvas');
|
||||
|
||||
const clone = require('clone');
|
||||
const Color = require('color');
|
||||
const express = require('express');
|
||||
const mercator = new (require('@mapbox/sphericalmercator'))();
|
||||
const mbgl = require('@maplibre/maplibre-gl-native');
|
||||
const MBTiles = require('@mapbox/mbtiles');
|
||||
const proj4 = require('proj4');
|
||||
const request = require('request');
|
||||
|
||||
const utils = require('./utils');
|
||||
import advancedPool from 'advanced-pool';
|
||||
import fs from 'node:fs';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
import util from 'util';
|
||||
import zlib from 'zlib';
|
||||
import sharp from 'sharp'; // sharp has to be required before node-canvas. see https://github.com/lovell/sharp/issues/371
|
||||
import pkg from 'canvas';
|
||||
import clone from 'clone';
|
||||
import Color from 'color';
|
||||
import express from 'express';
|
||||
import SphericalMercator from '@mapbox/sphericalmercator';
|
||||
import mlgl from '@maplibre/maplibre-gl-native';
|
||||
import MBTiles from '@mapbox/mbtiles';
|
||||
import proj4 from 'proj4';
|
||||
import request from 'request';
|
||||
import {getFontsPbf, getTileUrls, fixTileJSONCenter} from './utils.js';
|
||||
|
||||
const FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+\.?\\d+)';
|
||||
const httpTester = /^(http(s)?:)?\/\//;
|
||||
|
||||
const getScale = scale => (scale || '@1x').slice(1, 2) | 0;
|
||||
const {createCanvas} = pkg;
|
||||
const mercator = new SphericalMercator();
|
||||
const getScale = (scale) => (scale || '@1x').slice(1, 2) | 0;
|
||||
|
||||
mbgl.on('message', e => {
|
||||
mlgl.on('message', (e) => {
|
||||
if (e.severity === 'WARNING' || e.severity === 'ERROR') {
|
||||
console.log('mbgl:', e);
|
||||
console.log('mlgl:', e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -54,14 +50,14 @@ const cachedEmptyResponses = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an appropriate mbgl response for http errors.
|
||||
* Create an appropriate mlgl response for http errors.
|
||||
* @param {string} format The format (a sharp format or 'pbf').
|
||||
* @param {string} color The background color (or empty string for transparent).
|
||||
* @param {Function} callback The mbgl callback.
|
||||
* @param {Function} callback The mlgl callback.
|
||||
*/
|
||||
function createEmptyResponse(format, color, callback) {
|
||||
if (!format || format === 'pbf') {
|
||||
callback(null, { data: cachedEmptyResponses[''] });
|
||||
callback(null, {data: cachedEmptyResponses['']});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,7 +71,7 @@ function createEmptyResponse(format, color, callback) {
|
||||
const cacheKey = `${format},${color}`;
|
||||
const data = cachedEmptyResponses[cacheKey];
|
||||
if (data) {
|
||||
callback(null, { data: data });
|
||||
callback(null, {data: data});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -93,7 +89,7 @@ function createEmptyResponse(format, color, callback) {
|
||||
if (!err) {
|
||||
cachedEmptyResponses[cacheKey] = buffer;
|
||||
}
|
||||
callback(null, { data: buffer });
|
||||
callback(null, {data: buffer});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -119,7 +115,7 @@ const extractPathFromQuery = (query, transformer) => {
|
||||
};
|
||||
|
||||
const renderOverlay = (z, x, y, bearing, pitch, w, h, scale,
|
||||
path, query) => {
|
||||
path, query) => {
|
||||
if (!path || path.length < 2) {
|
||||
return null;
|
||||
}
|
||||
@@ -179,14 +175,14 @@ const calcZForBBox = (bbox, w, h, query) => {
|
||||
const padding = query.padding !== undefined ?
|
||||
parseFloat(query.padding) : 0.1;
|
||||
|
||||
const minCorner = mercator.px([bbox[0], bbox[3]], z),
|
||||
maxCorner = mercator.px([bbox[2], bbox[1]], z);
|
||||
const minCorner = mercator.px([bbox[0], bbox[3]], z);
|
||||
const maxCorner = mercator.px([bbox[2], bbox[1]], z);
|
||||
const w_ = w / (1 + 2 * padding);
|
||||
const h_ = h / (1 + 2 * padding);
|
||||
|
||||
z -= Math.max(
|
||||
Math.log((maxCorner[0] - minCorner[0]) / w_),
|
||||
Math.log((maxCorner[1] - minCorner[1]) / h_)
|
||||
Math.log((maxCorner[0] - minCorner[0]) / w_),
|
||||
Math.log((maxCorner[1] - minCorner[1]) / h_)
|
||||
) / Math.LN2;
|
||||
|
||||
z = Math.max(Math.log(Math.max(w, h) / 256) / Math.LN2, Math.min(25, z));
|
||||
@@ -197,7 +193,7 @@ const calcZForBBox = (bbox, w, h, query) => {
|
||||
const existingFonts = {};
|
||||
let maxScaleFactor = 2;
|
||||
|
||||
module.exports = {
|
||||
export const serve_rendered = {
|
||||
init: (options, repo) => {
|
||||
const fontListingPromise = new Promise((resolve, reject) => {
|
||||
fs.readdir(options.paths.fonts, (err, files) => {
|
||||
@@ -253,9 +249,9 @@ module.exports = {
|
||||
pool = item.map.renderers_static[scale];
|
||||
}
|
||||
pool.acquire((err, renderer) => {
|
||||
const mbglZ = Math.max(0, z - 1);
|
||||
const mlglZ = Math.max(0, z - 1);
|
||||
const params = {
|
||||
zoom: mbglZ,
|
||||
zoom: mlglZ,
|
||||
center: [lon, lat],
|
||||
bearing: bearing,
|
||||
pitch: pitch,
|
||||
@@ -282,9 +278,9 @@ module.exports = {
|
||||
|
||||
// Fix semi-transparent outlines on raw, premultiplied input
|
||||
// https://github.com/maptiler/tileserver-gl/issues/350#issuecomment-477857040
|
||||
for (var i = 0; i < data.length; i += 4) {
|
||||
var alpha = data[i + 3];
|
||||
var norm = alpha / 255;
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
const alpha = data[i + 3];
|
||||
const norm = alpha / 255;
|
||||
if (alpha === 0) {
|
||||
data[i] = 0;
|
||||
data[i + 1] = 0;
|
||||
@@ -321,7 +317,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
if (opt_overlay) {
|
||||
image.composite([{ input: opt_overlay }]);
|
||||
image.composite([{input: opt_overlay}]);
|
||||
}
|
||||
if (item.watermark) {
|
||||
const canvas = createCanvas(scale * width, scale * height);
|
||||
@@ -334,17 +330,17 @@ module.exports = {
|
||||
ctx.fillStyle = 'rgba(0,0,0,.4)';
|
||||
ctx.fillText(item.watermark, 5, height - 5);
|
||||
|
||||
image.composite([{ input: canvas.toBuffer() }]);
|
||||
image.composite([{input: canvas.toBuffer()}]);
|
||||
}
|
||||
|
||||
const formatQuality = (options.formatQuality || {})[format];
|
||||
|
||||
if (format === 'png') {
|
||||
image.png({ adaptiveFiltering: false });
|
||||
image.png({adaptiveFiltering: false});
|
||||
} else if (format === 'jpeg') {
|
||||
image.jpeg({ quality: formatQuality || 80 });
|
||||
image.jpeg({quality: formatQuality || 80});
|
||||
} else if (format === 'webp') {
|
||||
image.webp({ quality: formatQuality || 90 });
|
||||
image.webp({quality: formatQuality || 90});
|
||||
}
|
||||
image.toBuffer((err, buffer, info) => {
|
||||
if (!buffer) {
|
||||
@@ -367,18 +363,18 @@ module.exports = {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
|
||||
const modifiedSince = req.get('if-modified-since'), cc = req.get('cache-control');
|
||||
const modifiedSince = req.get('if-modified-since'); const cc = req.get('cache-control');
|
||||
if (modifiedSince && (!cc || cc.indexOf('no-cache') === -1)) {
|
||||
if (new Date(item.lastModified) <= new Date(modifiedSince)) {
|
||||
return res.sendStatus(304);
|
||||
}
|
||||
}
|
||||
|
||||
const z = req.params.z | 0,
|
||||
x = req.params.x | 0,
|
||||
y = req.params.y | 0,
|
||||
scale = getScale(req.params.scale),
|
||||
format = req.params.format;
|
||||
const z = req.params.z | 0;
|
||||
const x = req.params.x | 0;
|
||||
const y = req.params.y | 0;
|
||||
const scale = getScale(req.params.scale);
|
||||
const format = req.params.format;
|
||||
if (z < 0 || x < 0 || y < 0 ||
|
||||
z > 22 || x >= Math.pow(2, z) || y >= Math.pow(2, z)) {
|
||||
return res.status(404).send('Out of bounds');
|
||||
@@ -397,8 +393,8 @@ module.exports = {
|
||||
|
||||
const centerPattern =
|
||||
util.format(':x(%s),:y(%s),:z(%s)(@:bearing(%s)(,:pitch(%s))?)?',
|
||||
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN,
|
||||
FLOAT_PATTERN, FLOAT_PATTERN);
|
||||
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN,
|
||||
FLOAT_PATTERN, FLOAT_PATTERN);
|
||||
|
||||
app.get(util.format(staticPattern, centerPattern), (req, res, next) => {
|
||||
const item = repo[req.params.id];
|
||||
@@ -406,15 +402,15 @@ module.exports = {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
const raw = req.params.raw;
|
||||
let z = +req.params.z,
|
||||
x = +req.params.x,
|
||||
y = +req.params.y,
|
||||
bearing = +(req.params.bearing || '0'),
|
||||
pitch = +(req.params.pitch || '0'),
|
||||
w = req.params.width | 0,
|
||||
h = req.params.height | 0,
|
||||
scale = getScale(req.params.scale),
|
||||
format = req.params.format;
|
||||
const z = +req.params.z;
|
||||
let x = +req.params.x;
|
||||
let y = +req.params.y;
|
||||
const bearing = +(req.params.bearing || '0');
|
||||
const pitch = +(req.params.pitch || '0');
|
||||
const w = req.params.width | 0;
|
||||
const h = req.params.height | 0;
|
||||
const scale = getScale(req.params.scale);
|
||||
const format = req.params.format;
|
||||
|
||||
if (z < 0) {
|
||||
return res.status(404).send('Invalid zoom');
|
||||
@@ -441,8 +437,7 @@ module.exports = {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
const raw = req.params.raw;
|
||||
const bbox = [+req.params.minx, +req.params.miny,
|
||||
+req.params.maxx, +req.params.maxy];
|
||||
const bbox = [+req.params.minx, +req.params.miny, +req.params.maxx, +req.params.maxy];
|
||||
let center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
|
||||
|
||||
const transformer = raw ?
|
||||
@@ -458,30 +453,31 @@ module.exports = {
|
||||
center = transformer(center);
|
||||
}
|
||||
|
||||
const w = req.params.width | 0,
|
||||
h = req.params.height | 0,
|
||||
scale = getScale(req.params.scale),
|
||||
format = req.params.format;
|
||||
const w = req.params.width | 0;
|
||||
const h = req.params.height | 0;
|
||||
const scale = getScale(req.params.scale);
|
||||
const format = req.params.format;
|
||||
|
||||
const z = calcZForBBox(bbox, w, h, req.query),
|
||||
x = center[0],
|
||||
y = center[1],
|
||||
bearing = 0,
|
||||
pitch = 0;
|
||||
const z = calcZForBBox(bbox, w, h, req.query);
|
||||
const x = center[0];
|
||||
const y = center[1];
|
||||
const bearing = 0;
|
||||
const pitch = 0;
|
||||
|
||||
const path = extractPathFromQuery(req.query, transformer);
|
||||
const overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, path, req.query);
|
||||
|
||||
return respondImage(item, z, x, y, bearing, pitch, w, h, scale, format, res, next, overlay, 'static');
|
||||
};
|
||||
|
||||
const boundsPattern =
|
||||
util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)',
|
||||
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
|
||||
FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);
|
||||
|
||||
app.get(util.format(staticPattern, boundsPattern), serveBounds);
|
||||
|
||||
app.get('/:id/static/', (req, res, next) => {
|
||||
for (let key in req.query) {
|
||||
for (const key in req.query) {
|
||||
req.query[key.toLowerCase()] = req.query[key];
|
||||
}
|
||||
req.params.raw = true;
|
||||
@@ -510,12 +506,12 @@ module.exports = {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
const raw = req.params.raw;
|
||||
const w = req.params.width | 0,
|
||||
h = req.params.height | 0,
|
||||
bearing = 0,
|
||||
pitch = 0,
|
||||
scale = getScale(req.params.scale),
|
||||
format = req.params.format;
|
||||
const w = req.params.width | 0;
|
||||
const h = req.params.height | 0;
|
||||
const bearing = 0;
|
||||
const pitch = 0;
|
||||
const scale = getScale(req.params.scale);
|
||||
const format = req.params.format;
|
||||
|
||||
const transformer = raw ?
|
||||
mercator.inverse.bind(mercator) : item.dataProjWGStoInternalWGS;
|
||||
@@ -535,12 +531,12 @@ module.exports = {
|
||||
|
||||
const bbox_ = mercator.convert(bbox, '900913');
|
||||
const center = mercator.inverse(
|
||||
[(bbox_[0] + bbox_[2]) / 2, (bbox_[1] + bbox_[3]) / 2]
|
||||
[(bbox_[0] + bbox_[2]) / 2, (bbox_[1] + bbox_[3]) / 2]
|
||||
);
|
||||
|
||||
const z = calcZForBBox(bbox, w, h, req.query),
|
||||
x = center[0],
|
||||
y = center[1];
|
||||
const z = calcZForBBox(bbox, w, h, req.query);
|
||||
const x = center[0];
|
||||
const y = center[1];
|
||||
|
||||
const overlay = renderOverlay(z, x, y, bearing, pitch, w, h, scale, path, req.query);
|
||||
|
||||
@@ -554,8 +550,8 @@ module.exports = {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
const info = clone(item.tileJSON);
|
||||
info.tiles = utils.getTileUrls(req, info.tiles,
|
||||
`styles/${req.params.id}`, info.format, item.publicUrl);
|
||||
info.tiles = getTileUrls(req, info.tiles,
|
||||
`styles/${req.params.id}`, info.format, item.publicUrl);
|
||||
return res.send(info);
|
||||
});
|
||||
|
||||
@@ -571,38 +567,38 @@ module.exports = {
|
||||
let styleJSON;
|
||||
const createPool = (ratio, mode, min, max) => {
|
||||
const createRenderer = (ratio, createCallback) => {
|
||||
const renderer = new mbgl.Map({
|
||||
const renderer = new mlgl.Map({
|
||||
mode: mode,
|
||||
ratio: ratio,
|
||||
request: (req, callback) => {
|
||||
const protocol = req.url.split(':')[0];
|
||||
//console.log('Handling request:', req);
|
||||
// console.log('Handling request:', req);
|
||||
if (protocol === 'sprites') {
|
||||
const dir = options.paths[protocol];
|
||||
const file = unescape(req.url).substring(protocol.length + 3);
|
||||
fs.readFile(path.join(dir, file), (err, data) => {
|
||||
callback(err, { data: data });
|
||||
callback(err, {data: data});
|
||||
});
|
||||
} else if (protocol === 'fonts') {
|
||||
const parts = req.url.split('/');
|
||||
const fontstack = unescape(parts[2]);
|
||||
const range = parts[3].split('.')[0];
|
||||
utils.getFontsPbf(
|
||||
null, options.paths[protocol], fontstack, range, existingFonts
|
||||
).then(concated => {
|
||||
callback(null, { data: concated });
|
||||
}, err => {
|
||||
callback(err, { data: null });
|
||||
getFontsPbf(
|
||||
null, options.paths[protocol], fontstack, range, existingFonts
|
||||
).then((concated) => {
|
||||
callback(null, {data: concated});
|
||||
}, (err) => {
|
||||
callback(err, {data: null});
|
||||
});
|
||||
} else if (protocol === 'mbtiles') {
|
||||
const parts = req.url.split('/');
|
||||
const sourceId = parts[2];
|
||||
const source = map.sources[sourceId];
|
||||
const sourceInfo = styleJSON.sources[sourceId];
|
||||
const z = parts[3] | 0,
|
||||
x = parts[4] | 0,
|
||||
y = parts[5].split('.')[0] | 0,
|
||||
format = parts[5].split('.')[1];
|
||||
const z = parts[3] | 0;
|
||||
const x = parts[4] | 0;
|
||||
const y = parts[5].split('.')[0] | 0;
|
||||
const format = parts[5].split('.')[1];
|
||||
source.getTile(z, x, y, (err, data, headers) => {
|
||||
if (err) {
|
||||
if (options.verbose) console.log('MBTiles error, serving empty', err);
|
||||
@@ -619,11 +615,11 @@ module.exports = {
|
||||
try {
|
||||
response.data = zlib.unzipSync(data);
|
||||
} catch (err) {
|
||||
console.log("Skipping incorrect header for tile mbtiles://%s/%s/%s/%s.pbf", id, z, x, y);
|
||||
console.log('Skipping incorrect header for tile mbtiles://%s/%s/%s/%s.pbf', id, z, x, y);
|
||||
}
|
||||
if (options.dataDecoratorFunc) {
|
||||
response.data = options.dataDecoratorFunc(
|
||||
sourceId, 'data', response.data, z, x, y);
|
||||
sourceId, 'data', response.data, z, x, y);
|
||||
}
|
||||
} else {
|
||||
response.data = data;
|
||||
@@ -670,7 +666,7 @@ module.exports = {
|
||||
min: min,
|
||||
max: max,
|
||||
create: createRenderer.bind(null, ratio),
|
||||
destroy: renderer => {
|
||||
destroy: (renderer) => {
|
||||
renderer.release();
|
||||
}
|
||||
});
|
||||
@@ -688,8 +684,8 @@ module.exports = {
|
||||
if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) {
|
||||
styleJSON.sprite = 'sprites://' +
|
||||
styleJSON.sprite
|
||||
.replace('{style}', path.basename(styleFile, '.json'))
|
||||
.replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleJSONPath)));
|
||||
.replace('{style}', path.basename(styleFile, '.json'))
|
||||
.replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleJSONPath)));
|
||||
}
|
||||
if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) {
|
||||
styleJSON.glyphs = `fonts://${styleJSON.glyphs}`;
|
||||
@@ -720,9 +716,9 @@ module.exports = {
|
||||
const attributionOverride = params.tilejson && params.tilejson.attribution;
|
||||
Object.assign(tileJSON, params.tilejson || {});
|
||||
tileJSON.tiles = params.domains || options.domains;
|
||||
utils.fixTileJSONCenter(tileJSON);
|
||||
fixTileJSONCenter(tileJSON);
|
||||
|
||||
repo[id] = {
|
||||
const repoobj = {
|
||||
tileJSON,
|
||||
publicUrl,
|
||||
map,
|
||||
@@ -730,6 +726,7 @@ module.exports = {
|
||||
lastModified: new Date().toUTCString(),
|
||||
watermark: params.watermark || options.watermark
|
||||
};
|
||||
repo[id] = repoobj;
|
||||
|
||||
const queue = [];
|
||||
for (const name of Object.keys(styleJSON.sources)) {
|
||||
@@ -770,11 +767,11 @@ module.exports = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!repo[id].dataProjWGStoInternalWGS && info.proj4) {
|
||||
if (!repoobj.dataProjWGStoInternalWGS && info.proj4) {
|
||||
// how to do this for multiple sources with different proj4 defs?
|
||||
const to3857 = proj4('EPSG:3857');
|
||||
const toDataProj = proj4(info.proj4);
|
||||
repo[id].dataProjWGStoInternalWGS = xy => to3857.inverse(toDataProj.forward(xy));
|
||||
repoobj.dataProjWGStoInternalWGS = (xy) => to3857.inverse(toDataProj.forward(xy));
|
||||
}
|
||||
|
||||
const type = source.type;
|
||||
@@ -823,15 +820,15 @@ module.exports = {
|
||||
return Promise.all([renderersReadyPromise]);
|
||||
},
|
||||
remove: (repo, id) => {
|
||||
let item = repo[id];
|
||||
const item = repo[id];
|
||||
if (item) {
|
||||
item.map.renderers.forEach(pool => {
|
||||
item.map.renderers.forEach((pool) => {
|
||||
pool.close();
|
||||
});
|
||||
item.map.renderers_static.forEach(pool => {
|
||||
item.map.renderers_static.forEach((pool) => {
|
||||
pool.close();
|
||||
});
|
||||
}
|
||||
delete repo[id];
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user