279 lines
9.2 KiB
JavaScript
279 lines
9.2 KiB
JavaScript
import queue from "./queue";
|
|
|
|
var cacheBusterDate = +new Date();
|
|
|
|
// leaflet-image
|
|
export default function leafletImage(map, callback) {
|
|
|
|
var dimensions = map.getSize(),
|
|
layerQueue = new queue(1);
|
|
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = dimensions.x;
|
|
canvas.height = dimensions.y;
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
// dummy canvas image when loadTile get 404 error
|
|
// and layer don't have errorTileUrl
|
|
var dummycanvas = document.createElement('canvas');
|
|
dummycanvas.width = 1;
|
|
dummycanvas.height = 1;
|
|
var dummyctx = dummycanvas.getContext('2d');
|
|
dummyctx.fillStyle = 'rgba(0,0,0,0)';
|
|
dummyctx.fillRect(0, 0, 1, 1);
|
|
|
|
// layers are drawn in the same order as they are composed in the DOM:
|
|
// tiles, paths, and then markers
|
|
map.eachLayer(drawTileLayer);
|
|
map.eachLayer(drawEsriDynamicLayer);
|
|
|
|
if (map._pathRoot) {
|
|
layerQueue.defer(handlePathRoot, map._pathRoot);
|
|
} else if (map._panes) {
|
|
var firstCanvas = map._panes.overlayPane.getElementsByTagName('canvas').item(0);
|
|
if (firstCanvas) {
|
|
layerQueue.defer(handlePathRoot, firstCanvas);
|
|
}
|
|
}
|
|
map.eachLayer(drawMarkerLayer);
|
|
layerQueue.awaitAll(layersDone);
|
|
|
|
function drawTileLayer(l) {
|
|
if (l instanceof L.TileLayer) layerQueue.defer(handleTileLayer, l);
|
|
else if (l._heat) layerQueue.defer(handlePathRoot, l._canvas);
|
|
}
|
|
|
|
function drawMarkerLayer(l) {
|
|
if (l instanceof L.Marker && l.options.icon instanceof L.Icon) {
|
|
layerQueue.defer(handleMarkerLayer, l);
|
|
}
|
|
}
|
|
|
|
function drawEsriDynamicLayer(l) {
|
|
if (!L.esri) return;
|
|
|
|
if (l instanceof L.esri.DynamicMapLayer) {
|
|
layerQueue.defer(handleEsriDymamicLayer, l);
|
|
}
|
|
}
|
|
|
|
function done() {
|
|
callback(null, canvas);
|
|
}
|
|
|
|
function layersDone(err, layers) {
|
|
if (err) throw err;
|
|
layers.forEach(function (layer) {
|
|
if (layer && layer.canvas) {
|
|
ctx.drawImage(layer.canvas, 0, 0);
|
|
}
|
|
});
|
|
done();
|
|
}
|
|
|
|
function handleTileLayer(layer, callback) {
|
|
// `L.TileLayer.Canvas` was removed in leaflet 1.0
|
|
var isCanvasLayer = (L.TileLayer.Canvas && layer instanceof L.TileLayer.Canvas),
|
|
canvas = document.createElement('canvas');
|
|
|
|
canvas.width = dimensions.x;
|
|
canvas.height = dimensions.y;
|
|
|
|
var ctx = canvas.getContext('2d'),
|
|
bounds = map.getPixelBounds(),
|
|
zoom = map.getZoom(),
|
|
tileSize = layer.options.tileSize;
|
|
|
|
if (zoom > layer.options.maxZoom ||
|
|
zoom < layer.options.minZoom
|
|
) {
|
|
return callback();
|
|
}
|
|
|
|
var tileBounds = L.bounds(
|
|
bounds.min.divideBy(tileSize)._floor(),
|
|
bounds.max.divideBy(tileSize)._floor()),
|
|
tiles = [],
|
|
j, i,
|
|
tileQueue = new queue(1);
|
|
|
|
for (j = tileBounds.min.y; j <= tileBounds.max.y; j++) {
|
|
for (i = tileBounds.min.x; i <= tileBounds.max.x; i++) {
|
|
tiles.push(new L.Point(i, j));
|
|
}
|
|
}
|
|
|
|
tiles.forEach(function (tilePoint) {
|
|
var originalTilePoint = tilePoint.clone();
|
|
|
|
if (layer._adjustTilePoint) {
|
|
layer._adjustTilePoint(tilePoint);
|
|
}
|
|
|
|
var tilePos = originalTilePoint
|
|
.scaleBy(new L.Point(tileSize, tileSize))
|
|
.subtract(bounds.min);
|
|
|
|
if (tilePoint.y >= 0) {
|
|
if (isCanvasLayer) {
|
|
var tile = layer._tiles[tilePoint.x + ':' + tilePoint.y];
|
|
tileQueue.defer(canvasTile, tile, tilePos, tileSize);
|
|
} else {
|
|
var url = addCacheString(layer.getTileUrl(tilePoint));
|
|
tileQueue.defer(loadTile, url, tilePos, tileSize);
|
|
}
|
|
}
|
|
});
|
|
|
|
tileQueue.awaitAll(tileQueueFinish);
|
|
|
|
function canvasTile(tile, tilePos, tileSize, callback) {
|
|
callback(null, {
|
|
img: tile,
|
|
pos: tilePos,
|
|
size: tileSize
|
|
});
|
|
}
|
|
|
|
function loadTile(url, tilePos, tileSize, callback) {
|
|
var im = new Image();
|
|
im.crossOrigin = '';
|
|
im.onload = function () {
|
|
callback(null, {
|
|
img: this,
|
|
pos: tilePos,
|
|
size: tileSize
|
|
});
|
|
};
|
|
im.onerror = function (e) {
|
|
// use canvas instead of errorTileUrl if errorTileUrl get 404
|
|
if (layer.options.errorTileUrl != '' && e.target.errorCheck === undefined) {
|
|
e.target.errorCheck = true;
|
|
e.target.src = layer.options.errorTileUrl;
|
|
} else {
|
|
callback(null, {
|
|
img: dummycanvas,
|
|
pos: tilePos,
|
|
size: tileSize
|
|
});
|
|
}
|
|
};
|
|
im.src = url;
|
|
}
|
|
|
|
function tileQueueFinish(err, data) {
|
|
data.forEach(drawTile);
|
|
callback(null, { canvas: canvas });
|
|
}
|
|
|
|
function drawTile(d) {
|
|
ctx.drawImage(d.img, Math.floor(d.pos.x), Math.floor(d.pos.y),
|
|
d.size, d.size);
|
|
}
|
|
}
|
|
|
|
function handlePathRoot(root, callback) {
|
|
var bounds = map.getPixelBounds(),
|
|
origin = map.getPixelOrigin(),
|
|
canvas = document.createElement('canvas');
|
|
canvas.width = dimensions.x;
|
|
canvas.height = dimensions.y;
|
|
var ctx = canvas.getContext('2d');
|
|
var pos = L.DomUtil.getPosition(root).subtract(bounds.min).add(origin);
|
|
try {
|
|
ctx.drawImage(root, pos.x, pos.y, canvas.width - (pos.x * 2), canvas.height - (pos.y * 2));
|
|
callback(null, {
|
|
canvas: canvas
|
|
});
|
|
} catch (e) {
|
|
console.error('Element could not be drawn on canvas', root); // eslint-disable-line no-console
|
|
}
|
|
}
|
|
|
|
function handleMarkerLayer(marker, callback) {
|
|
var canvas = document.createElement('canvas'),
|
|
ctx = canvas.getContext('2d'),
|
|
pixelBounds = map.getPixelBounds(),
|
|
minPoint = new L.Point(pixelBounds.min.x, pixelBounds.min.y),
|
|
pixelPoint = map.project(marker.getLatLng()),
|
|
url = "/vendor/leaflet-image/marker.png",
|
|
im = new Image(),
|
|
options = marker.options.icon.options,
|
|
size = options.iconSize,
|
|
pos = pixelPoint.subtract(minPoint),
|
|
anchor = L.point(options.iconAnchor || size && { x: size[0], y: size[1] });
|
|
|
|
if (size instanceof L.Point) size = [size.x, size.y];
|
|
|
|
var x = Math.round(pos.x - size[0] + anchor.x),
|
|
y = Math.round(pos.y - anchor.y);
|
|
|
|
canvas.width = dimensions.x;
|
|
canvas.height = dimensions.y;
|
|
im.crossOrigin = '';
|
|
|
|
im.onload = function () {
|
|
if (marker._icon.classList.contains("leaflet-grid-label")) {
|
|
const label = marker._icon.children[0].textContent;
|
|
ctx.font = '600 8px "Font Awesome 6 Free"';
|
|
ctx.fillStyle = "#000";
|
|
ctx.fillText(label, x + 4, y + 12);
|
|
} else {
|
|
const waypointName = marker.options.meta?.waypointName;
|
|
const icon = getComputedStyle(marker._icon.children[0], ':before').getPropertyValue('content').substring(1, 2) ?? "\uf111";
|
|
ctx.drawImage(this, x, y, size[0], size[1]);
|
|
ctx.font = '600 14px "Font Awesome 6 Free"';
|
|
ctx.fillStyle = "#ffffff";
|
|
ctx.fillText(icon, x + 10.2, y + 24);
|
|
if (waypointName) {
|
|
ctx.fillStyle = "#313131"
|
|
ctx.roundRect(x - 8, y - 18, waypointName.length * 7, 20, 5)
|
|
ctx.fill();
|
|
ctx.font = '600 12px "IBMPlexSans"';
|
|
ctx.fillStyle = "#ffffff";
|
|
ctx.fillText(waypointName, x, y - 4);
|
|
}
|
|
}
|
|
|
|
callback(null, {
|
|
canvas: canvas
|
|
});
|
|
};
|
|
|
|
im.src = url;
|
|
}
|
|
|
|
function handleEsriDymamicLayer(dynamicLayer, callback) {
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = dimensions.x;
|
|
canvas.height = dimensions.y;
|
|
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
var im = new Image();
|
|
im.crossOrigin = '';
|
|
im.src = addCacheString(dynamicLayer._currentImage._image.src);
|
|
|
|
im.onload = function () {
|
|
ctx.drawImage(im, 0, 0);
|
|
callback(null, {
|
|
canvas: canvas
|
|
});
|
|
};
|
|
}
|
|
|
|
function addCacheString(url) {
|
|
// If it's a data URL we don't want to touch this.
|
|
if (isDataURL(url)) {
|
|
return url;
|
|
}
|
|
return url + ((url.match(/\?/)) ? '&' : '?') + 'cache=' + cacheBusterDate;
|
|
}
|
|
|
|
function isDataURL(url) {
|
|
var dataURLRegex = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
|
|
return !!url.match(dataURLRegex);
|
|
}
|
|
|
|
};
|