UNPKG

@jorgenphi/staticmaps

Version:

A Node.js library for creating map images with markers, polylines, polygons and text.

1,039 lines (862 loc) 37.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _got = _interopRequireDefault(require("got")); var _sharp = _interopRequireDefault(require("sharp")); var _lodash = _interopRequireDefault(require("lodash.find")); var _lodash2 = _interopRequireDefault(require("lodash.uniqby")); var _url = _interopRequireDefault(require("url")); var _lodash3 = _interopRequireDefault(require("lodash.chunk")); var _modernAsync = require("modern-async"); var _crypto = require("crypto"); var _fs = _interopRequireDefault(require("fs")); var _path = _interopRequireDefault(require("path")); var _image = _interopRequireDefault(require("./image")); var _marker = _interopRequireDefault(require("./marker")); var _polyline = _interopRequireDefault(require("./polyline")); var _multipolygon = _interopRequireDefault(require("./multipolygon")); var _circle = _interopRequireDefault(require("./circle")); var _text = _interopRequireDefault(require("./text")); var _bound = _interopRequireDefault(require("./bound")); var _tileserverconfig = _interopRequireDefault(require("./tileserverconfig")); var _asyncQueue = _interopRequireDefault(require("./helper/asyncQueue")); var _geo = _interopRequireDefault(require("./helper/geo")); var RENDER_CHUNK_SIZE = 1000; var StaticMaps = /*#__PURE__*/function () { function StaticMaps() { var _this = this; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; (0, _classCallCheck2["default"])(this, StaticMaps); this.options = options; this.tileLayers = []; if (typeof this.options.tileLayers === 'undefined') { // Pulling from old options for backwards compatibility var baseLayerOptions = {}; if (this.options.tileUrl) { baseLayerOptions.tileUrl = this.options.tileUrl; } baseLayerOptions.tileSubdomains = this.options.tileSubdomains || []; this.tileLayers.push(new _tileserverconfig["default"](baseLayerOptions)); } else { this.options.tileLayers.forEach(function (layerConfig) { _this.tileLayers.push(new _tileserverconfig["default"](layerConfig)); }); } this.width = this.options.width; this.height = this.options.height; this.paddingX = this.options.paddingX || 0; this.paddingY = this.options.paddingY || 0; this.padding = [this.paddingX, this.paddingY]; this.tileSize = this.options.tileSize || 256; this.tileCacheFolder = this.options.tileCacheFolder || null; this.tileCacheAutoPurge = typeof this.options.tileCacheAutoPurge !== 'undefined' ? this.options.tileCacheAutoPurge : true; this.tileCacheLifetime = this.options.tileCacheLifetime || 86400; this.tileCacheHits = 0; this.subdomains = this.options.subdomains || []; this.tileRequestTimeout = this.options.tileRequestTimeout; this.tileRequestHeader = this.options.tileRequestHeader; this.tileRequestLimit = Number.isFinite(this.options.tileRequestLimit) ? Number(this.options.tileRequestLimit) : 2; this.reverseY = this.options.reverseY || false; var zoomRange = this.options.zoomRange || {}; this.zoomRange = { min: zoomRange.min || 1, max: this.options.maxZoom || zoomRange.max || 17 // maxZoom }; // this.maxZoom = this.options.maxZoom; DEPRECATED: use zoomRange.max instead // # features this.markers = []; this.lines = []; this.multipolygons = []; this.circles = []; this.text = []; this.bounds = []; // # fields that get set when map is rendered this.center = []; this.centerX = 0; this.centerY = 0; this.zoom = 0; } (0, _createClass2["default"])(StaticMaps, [{ key: "addLine", value: function addLine(options) { this.lines.push(new _polyline["default"](options)); } }, { key: "addMarker", value: function addMarker(options) { this.markers.push(new _marker["default"](options)); } }, { key: "addPolygon", value: function addPolygon(options) { this.lines.push(new _polyline["default"](options)); } }, { key: "addMultiPolygon", value: function addMultiPolygon(options) { this.multipolygons.push(new _multipolygon["default"](options)); } }, { key: "addCircle", value: function addCircle(options) { this.circles.push(new _circle["default"](options)); } }, { key: "addBound", value: function addBound(options) { this.bounds.push(new _bound["default"](options)); } }, { key: "addText", value: function addText(options) { this.text.push(new _text["default"](options)); } /** * Render static map with all map features that were added to map before */ }, { key: "render", value: function () { var _render = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(center, zoom) { var _this2 = this; var maxZoom, extent, centerLon, centerLat; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!(!this.lines && !this.markers && !this.multipolygons && !(center && zoom))) { _context2.next = 2; break; } throw new Error('Cannot render empty map: Add center || lines || markers || polygons.'); case 2: this.center = center; this.zoom = zoom || this.calculateZoom(); maxZoom = this.zoomRange.max; if (maxZoom && this.zoom > maxZoom) this.zoom = maxZoom; if (center && center.length === 2) { this.centerX = _geo["default"].lonToX(center[0], this.zoom); this.centerY = _geo["default"].latToY(center[1], this.zoom); } else { // # get extent of all lines extent = this.determineExtent(this.zoom); // # calculate center point of map centerLon = (extent[0] + extent[2]) / 2; centerLat = (extent[1] + extent[3]) / 2; this.centerX = _geo["default"].lonToX(centerLon, this.zoom); this.centerY = _geo["default"].latToY(centerLat, this.zoom); } this.image = new _image["default"](this.options); // Await this.drawLayer for each tile layer _context2.next = 10; return (0, _modernAsync.mapSeries)(this.tileLayers, /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(layer) { return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return _this2.drawLayer(layer); case 2: case "end": return _context.stop(); } } }, _callee); })); return function (_x3) { return _ref.apply(this, arguments); }; }()); case 10: _context2.next = 12; return this.loadMarker(); case 12: // when a cache folder is configured and auto purge is enable // clear cache in 10% of all executions if (this.tileCacheFolder !== null && this.tileCacheAutoPurge === true && Math.random() * 10 <= 1) { this.clearCache(); } return _context2.abrupt("return", this.drawFeatures()); case 14: case "end": return _context2.stop(); } } }, _callee2, this); })); function render(_x, _x2) { return _render.apply(this, arguments); } return render; }() }, { key: "getTileCacheHits", value: function getTileCacheHits() { return this.tileCacheHits; } }, { key: "clearCache", value: function () { var _clearCache = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3() { var _this3 = this; var now; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: if (this.tileCacheFolder !== null) { now = new Date().getTime(); _fs["default"].readdir(this.tileCacheFolder, function (err, files) { files.forEach(function (file, index) { _fs["default"].stat(_path["default"].join(_this3.tileCacheFolder, file), function (err, stat) { if (err) { return console.error(err); } var fileMTime = new Date(stat.mtime).getTime() + _this3.tileCacheLifetime * 1000; if (now > fileMTime) { return _fs["default"].unlink(_path["default"].join(_this3.tileCacheFolder, file), function (err) { if (err) { return console.error(err); } }); } }); }); }); } case 1: case "end": return _context3.stop(); } } }, _callee3, this); })); function clearCache() { return _clearCache.apply(this, arguments); } return clearCache; }() /** * calculate common extent of all current map features */ }, { key: "determineExtent", value: function determineExtent(zoom) { var extents = []; // Add bbox to extent if (this.center && this.center.length >= 4) extents.push(this.center); // add bounds to extent if (this.bounds.length) { this.bounds.forEach(function (bound) { return extents.push(bound.extent()); }); } // Add polylines and polygons to extent if (this.lines.length) { this.lines.forEach(function (line) { extents.push(line.extent()); }); } if (this.multipolygons.length) { this.multipolygons.forEach(function (multipolygon) { extents.push(multipolygon.extent()); }); } // Add circles to extent if (this.circles.length) { this.circles.forEach(function (circle) { extents.push(circle.extent()); }); } // Add marker to extent for (var i = 0; i < this.markers.length; i++) { var marker = this.markers[i]; var e = [marker.coord[0], marker.coord[1]]; if (!zoom) { extents.push([marker.coord[0], marker.coord[1], marker.coord[0], marker.coord[1]]); continue; } // # consider dimension of marker var ePx = marker.extentPx(); var x = _geo["default"].lonToX(e[0], zoom); var y = _geo["default"].latToY(e[1], zoom); extents.push([_geo["default"].xToLon(x - parseFloat(ePx[0]) / this.tileSize, zoom), _geo["default"].yToLat(y + parseFloat(ePx[1]) / this.tileSize, zoom), _geo["default"].xToLon(x + parseFloat(ePx[2]) / this.tileSize, zoom), _geo["default"].yToLat(y - parseFloat(ePx[3]) / this.tileSize, zoom)]); } return [Math.min.apply(Math, (0, _toConsumableArray2["default"])(extents.map(function (e) { return e[0]; }))), Math.min.apply(Math, (0, _toConsumableArray2["default"])(extents.map(function (e) { return e[1]; }))), Math.max.apply(Math, (0, _toConsumableArray2["default"])(extents.map(function (e) { return e[2]; }))), Math.max.apply(Math, (0, _toConsumableArray2["default"])(extents.map(function (e) { return e[3]; })))]; } /** * calculate the best zoom level for given extent */ }, { key: "calculateZoom", value: function calculateZoom() { for (var z = this.zoomRange.max; z >= this.zoomRange.min; z--) { var extent = this.determineExtent(z); var width = (_geo["default"].lonToX(extent[2], z) - _geo["default"].lonToX(extent[0], z)) * this.tileSize; if (width > this.width - this.padding[0] * 2) continue; var height = (_geo["default"].latToY(extent[1], z) - _geo["default"].latToY(extent[3], z)) * this.tileSize; if (height > this.height - this.padding[1] * 2) continue; return z; } return this.zoomRange.min; } /** * transform tile number to pixel on image canvas */ }, { key: "xToPx", value: function xToPx(x) { var px = (x - this.centerX) * this.tileSize + this.width / 2; return Number(Math.round(px)); } /** * transform tile number to pixel on image canvas */ }, { key: "yToPx", value: function yToPx(y) { var px = (y - this.centerY) * this.tileSize + this.height / 2; return Number(Math.round(px)); } }, { key: "drawLayer", value: function () { var _drawLayer = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(config) { var xMin, yMin, xMax, yMax, result, x, y, maxTile, tileX, tileY, tileUrl, quadKey, tiles; return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: if (!(!config || !config.tileUrl)) { _context4.next = 3; break; } // Early return if we shouldn't draw a base layer console.log(1); return _context4.abrupt("return", this.image.draw([])); case 3: xMin = Math.floor(this.centerX - 0.5 * this.width / this.tileSize); yMin = Math.floor(this.centerY - 0.5 * this.height / this.tileSize); xMax = Math.ceil(this.centerX + 0.5 * this.width / this.tileSize); yMax = Math.ceil(this.centerY + 0.5 * this.height / this.tileSize); result = []; for (x = xMin; x < xMax; x++) { for (y = yMin; y < yMax; y++) { // # x and y may have crossed the date line maxTile = Math.pow(2, this.zoom); tileX = (x + maxTile) % maxTile; tileY = (y + maxTile) % maxTile; if (this.reverseY) tileY = (1 << this.zoom) - tileY - 1; tileUrl = void 0; if (config.tileUrl.includes('{quadkey}')) { quadKey = _geo["default"].tileXYToQuadKey(tileX, tileY, this.zoom); tileUrl = config.tileUrl.replace('{quadkey}', quadKey); } else { tileUrl = config.tileUrl.replace('{z}', this.zoom).replace('{x}', tileX).replace('{y}', tileY); } if (config.tileSubdomains.length > 0) { // replace subdomain with random domain from tileSubdomains array tileUrl = tileUrl.replace('{s}', config.tileSubdomains[Math.floor(Math.random() * config.tileSubdomains.length)]); } result.push({ url: tileUrl, box: [this.xToPx(x), this.yToPx(y), this.xToPx(x + 1), this.yToPx(y + 1)] }); } } _context4.next = 11; return this.getTiles(result, config); case 11: tiles = _context4.sent; return _context4.abrupt("return", this.image.draw(tiles.filter(function (v) { return v.success; }).map(function (v) { return v.tile; }))); case 13: case "end": return _context4.stop(); } } }, _callee4, this); })); function drawLayer(_x4) { return _drawLayer.apply(this, arguments); } return drawLayer; }() }, { key: "drawSVG", value: function () { var _drawSVG = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(features, svgFunction) { var chunks, baseImage, imageMetadata, processedChunks; return _regenerator["default"].wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: if (features.length) { _context5.next = 2; break; } return _context5.abrupt("return"); case 2: // Chunk for performance chunks = (0, _lodash3["default"])(features, RENDER_CHUNK_SIZE); baseImage = (0, _sharp["default"])(this.image.image); _context5.next = 6; return baseImage.metadata(); case 6: imageMetadata = _context5.sent; processedChunks = chunks.map(function (c) { var svg = "\n <svg\n width=\"".concat(imageMetadata.width, "px\"\n height=\"").concat(imageMetadata.height, "px\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\">\n ").concat(c.map(function (f) { return svgFunction(f); }).join('\n'), "\n </svg>\n "); return { input: Buffer.from(svg), top: 0, left: 0 }; }); _context5.next = 10; return baseImage.composite(processedChunks).toBuffer(); case 10: this.image.image = _context5.sent; case 11: case "end": return _context5.stop(); } } }, _callee5, this); })); function drawSVG(_x5, _x6) { return _drawSVG.apply(this, arguments); } return drawSVG; }() /** * Render a circle to SVG */ }, { key: "circleToSVG", value: function circleToSVG(circle) { var latCenter = circle.coord[1]; var radiusInPixel = _geo["default"].meterToPixel(circle.radius, this.zoom, latCenter); var x = this.xToPx(_geo["default"].lonToX(circle.coord[0], this.zoom)); var y = this.yToPx(_geo["default"].latToY(circle.coord[1], this.zoom)); return "\n <circle\n cx=\"".concat(x, "\"\n cy=\"").concat(y, "\"\n r=\"").concat(radiusInPixel, "\"\n style=\"fill-rule: inherit;\"\n stroke=\"").concat(circle.color, "\"\n fill=\"").concat(circle.fill, "\"\n stroke-width=\"").concat(circle.width, "\"\n />\n "); } /** * Render text to SVG */ }, { key: "textToSVG", value: function textToSVG(text) { var mapcoords = [this.xToPx(_geo["default"].lonToX(text.coord[0], this.zoom)) - text.offset[0], this.yToPx(_geo["default"].latToY(text.coord[1], this.zoom)) - text.offset[1]]; return "\n <text\n x=\"".concat(mapcoords[0], "\"\n y=\"").concat(mapcoords[1], "\"\n style=\"fill-rule: inherit; font-family: ").concat(text.font, ";\"\n font-size=\"").concat(text.size, "pt\"\n stroke=\"").concat(text.color, "\"\n fill=\"").concat(text.fill ? text.fill : 'none', "\"\n stroke-width=\"").concat(text.width, "\"\n text-anchor=\"").concat(text.anchor, "\"\n >\n ").concat(text.text, "\n </text>\n "); } /** * Render MultiPolygon to SVG */ }, { key: "multiPolygonToSVG", value: function multiPolygonToSVG(multipolygon) { var _this4 = this; var shapeArrays = multipolygon.coords.map(function (shape) { return shape.map(function (coord) { return [_this4.xToPx(_geo["default"].lonToX(coord[0], _this4.zoom)), _this4.yToPx(_geo["default"].latToY(coord[1], _this4.zoom))]; }); }); var pathArrays = shapeArrays.map(function (points) { var startPoint = points.shift(); var pathParts = ["M ".concat(startPoint[0], " ").concat(startPoint[1])].concat((0, _toConsumableArray2["default"])(points.map(function (p) { return "L ".concat(p[0], " ").concat(p[1]); })), ['Z']); return pathParts.join(' '); }); return "<path\n d=\"".concat(pathArrays.join(' '), "\"\n style=\"fill-rule: inherit;\"\n stroke=\"").concat(multipolygon.color, "\"\n fill=\"").concat(multipolygon.fill ? multipolygon.fill : 'none', "\"\n stroke-width=\"").concat(multipolygon.width, "\"/>"); } /** * Render Polyline to SVG */ }, { key: "lineToSVG", value: function lineToSVG(line) { var _this5 = this; var points = line.coords.map(function (coord) { return [_this5.xToPx(_geo["default"].lonToX(coord[0], _this5.zoom)), _this5.yToPx(_geo["default"].latToY(coord[1], _this5.zoom))]; }); return "<".concat(line.type === 'polyline' ? 'polyline' : 'polygon', "\n style=\"fill-rule: inherit;\"\n points=\"").concat(points.join(' '), "\"\n stroke=\"").concat(line.color, "\"\n fill=\"").concat(line.fill ? line.fill : 'none', "\"\n stroke-width=\"").concat(line.width, "\"/>"); } /** * Draw markers to the basemap */ }, { key: "drawMarkers", value: function drawMarkers() { var _this6 = this; var queue = []; this.markers.forEach(function (marker) { queue.push( /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6() { var top, left; return _regenerator["default"].wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: top = Math.round(marker.position[1]); left = Math.round(marker.position[0]); if (!(top < 0 || left < 0 || top > _this6.height || left > _this6.width)) { _context6.next = 4; break; } return _context6.abrupt("return"); case 4: _context6.next = 6; return (0, _sharp["default"])(_this6.image.image).composite([{ input: marker.imgData, top: top, left: left }]).toBuffer(); case 6: _this6.image.image = _context6.sent; case 7: case "end": return _context6.stop(); } } }, _callee6); }))); }); return (0, _asyncQueue["default"])(queue); } /** * Draw all features to the basemap */ }, { key: "drawFeatures", value: function () { var _drawFeatures = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7() { var _this7 = this; return _regenerator["default"].wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: _context7.next = 2; return this.drawSVG(this.lines, function (c) { return _this7.lineToSVG(c); }); case 2: _context7.next = 4; return this.drawSVG(this.multipolygons, function (c) { return _this7.multiPolygonToSVG(c); }); case 4: _context7.next = 6; return this.drawMarkers(); case 6: _context7.next = 8; return this.drawSVG(this.text, function (c) { return _this7.textToSVG(c); }); case 8: _context7.next = 10; return this.drawSVG(this.circles, function (c) { return _this7.circleToSVG(c); }); case 10: case "end": return _context7.stop(); } } }, _callee7, this); })); function drawFeatures() { return _drawFeatures.apply(this, arguments); } return drawFeatures; }() /** * Preloading the icon image */ }, { key: "loadMarker", value: function loadMarker() { var _this8 = this; return new Promise(function (resolve, reject) { if (!_this8.markers.length) resolve(true); var icons = (0, _lodash2["default"])(_this8.markers.map(function (m) { return { file: m.img }; }), 'file'); var count = 1; icons.forEach( /*#__PURE__*/function () { var _ref3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(ico) { var icon, isUrl, img; return _regenerator["default"].wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: icon = ico; isUrl = !!_url["default"].parse(icon.file).hostname; _context8.prev = 2; if (!isUrl) { _context8.next = 12; break; } _context8.next = 6; return _got["default"].get({ https: { rejectUnauthorized: false }, url: icon.file, responseType: 'buffer' }); case 6: img = _context8.sent; _context8.next = 9; return (0, _sharp["default"])(img.body).toBuffer(); case 9: icon.data = _context8.sent; _context8.next = 15; break; case 12: _context8.next = 14; return (0, _sharp["default"])(icon.file).toBuffer(); case 14: icon.data = _context8.sent; case 15: _context8.next = 20; break; case 17: _context8.prev = 17; _context8.t0 = _context8["catch"](2); reject(_context8.t0); case 20: if (count++ === icons.length) { // Pre loaded all icons _this8.markers.forEach(function (mark) { var marker = mark; marker.position = [_this8.xToPx(_geo["default"].lonToX(marker.coord[0], _this8.zoom)) - marker.offset[0], _this8.yToPx(_geo["default"].latToY(marker.coord[1], _this8.zoom)) - marker.offset[1]]; var imgData = (0, _lodash["default"])(icons, { file: marker.img }); marker.set(imgData.data); }); resolve(true); } case 21: case "end": return _context8.stop(); } } }, _callee8, null, [[2, 17]]); })); return function (_x7) { return _ref3.apply(this, arguments); }; }()); }); } /** * Fetching tile from endpoint */ }, { key: "getTile", value: function getTile(data, config) { var _this9 = this; return new Promise(function (resolve) { var options = { url: data.url, responseType: 'buffer', resolveWithFullResponse: true, headers: _this9.tileRequestHeader || {}, timeout: _this9.tileRequestTimeout }; var cacheFile = null; if (_this9.tileCacheFolder !== null && !config.disableCache) { var cacheKey = (0, _crypto.createHash)('sha256').update(data.url).digest('hex'); cacheFile = _path["default"].join(_this9.tileCacheFolder, cacheKey); if (_fs["default"].existsSync(cacheFile)) { var stats = _fs["default"].statSync(cacheFile); var seconds = (new Date().getTime() - stats.mtime) / 1000; // If TTL expire, delete file if (seconds < _this9.tileCacheLifetime) { var cacheData; try { cacheData = JSON.parse(_fs["default"].readFileSync(cacheFile)); } catch (e) { try { cacheData = JSON.parse(_fs["default"].readFileSync(cacheFile)); } catch (e) {} } if (cacheData && cacheData.length > 0) { try { cacheData = Buffer.from(cacheData, 'base64'); if (cacheData && cacheData.length > 0) { var responseContent = { success: true, tile: { url: data.url, box: data.box, body: cacheData } }; _this9.tileCacheHits++; resolve(responseContent); return; } } catch (e) {} } } _fs["default"].rmSync(cacheFile); } } // const defaultAgent = `staticmaps@${pjson.version}`; // options.headers['User-Agent'] = options.headers['User-Agent'] || defaultAgent; _got["default"].get(options).then(function (res) { var responseContent = { success: true, tile: { url: data.url, box: data.box, body: res.body } }; if (_this9.tileCacheFolder !== null && !config.disableCache) { _fs["default"].writeFile(cacheFile, JSON.stringify(responseContent.tile.body.toString('base64')), function (err) { if (err) { console.error(err); } // file written successfully }); if (typeof responseContent.tile.body === 'string') { responseContent.tile.body = Buffer.from(responseContent.tile.body, 'base64'); } } resolve(responseContent); })["catch"](function (error) { return resolve({ success: false, error: error }); }); }); } /** * Fetching tiles and limit concurrent connections */ }, { key: "getTiles", value: function () { var _getTiles = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12(baseLayers, config) { var _this10 = this; var limit, _ret, tilePromises; return _regenerator["default"].wrap(function _callee12$(_context12) { while (1) { switch (_context12.prev = _context12.next) { case 0: limit = this.tileRequestLimit; // Limit concurrent connections to tiles server // https://operations.osmfoundation.org/policies/tiles/#technical-usage-requirements if (!Number(limit)) { _context12.next = 6; break; } return _context12.delegateYield( /*#__PURE__*/_regenerator["default"].mark(function _callee11() { var aQueue, tiles, _loop, i, j; return _regenerator["default"].wrap(function _callee11$(_context11) { while (1) { switch (_context11.prev = _context11.next) { case 0: aQueue = []; tiles = []; _loop = function _loop(i, j) { var chunks = baseLayers.slice(i, i + limit); var sQueue = []; aQueue.push( /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10() { return _regenerator["default"].wrap(function _callee10$(_context10) { while (1) { switch (_context10.prev = _context10.next) { case 0: chunks.forEach(function (r) { sQueue.push((0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9() { var tile; return _regenerator["default"].wrap(function _callee9$(_context9) { while (1) { switch (_context9.prev = _context9.next) { case 0: _context9.next = 2; return _this10.getTile(r, config); case 2: tile = _context9.sent; tiles.push(tile); case 4: case "end": return _context9.stop(); } } }, _callee9); }))()); }); _context10.next = 3; return Promise.all(sQueue); case 3: case "end": return _context10.stop(); } } }, _callee10); }))); }; for (i = 0, j = baseLayers.length; i < j; i += limit) { _loop(i, j); } _context11.next = 6; return (0, _asyncQueue["default"])(aQueue); case 6: return _context11.abrupt("return", { v: tiles }); case 7: case "end": return _context11.stop(); } } }, _callee11); })(), "t0", 3); case 3: _ret = _context12.t0; if (!((0, _typeof2["default"])(_ret) === "object")) { _context12.next = 6; break; } return _context12.abrupt("return", _ret.v); case 6: // Do not limit concurrent connections at all tilePromises = []; baseLayers.forEach(function (r) { tilePromises.push(_this10.getTile(r, config)); }); return _context12.abrupt("return", Promise.all(tilePromises)); case 9: case "end": return _context12.stop(); } } }, _callee12, this); })); function getTiles(_x8, _x9) { return _getTiles.apply(this, arguments); } return getTiles; }() }]); return StaticMaps; }(); var _default = StaticMaps; exports["default"] = _default; module.exports = StaticMaps;