commit 5905eab820153b375099e32510948144fa0e37ef
parent 68cbffcbeb3f6065ff5364e33735ad17f8889ab2
Author: Sergey Orlov <wladimirych@gmail.com>
Date: Wed, 21 Oct 2020 09:50:42 +0200
use hi-res tiles for hi-dpi displays, printing and JNX
Diffstat:
8 files changed, 128 insertions(+), 32 deletions(-)
diff --git a/eslint_rules/imports_relax_legacy.js b/eslint_rules/imports_relax_legacy.js
@@ -28,6 +28,7 @@ const filesMissingExport = [
'src/lib/leaflet.layer.rasterize/TileLayer.js',
'src/lib/leaflet.layer.rasterize/WestraPasses.js',
'src/lib/leaflet.layer.rasterize/Yandex.js',
+ 'src/lib/leaflet.layer.rasterize/RetinaTileLayer.js',
'src/lib/leaflet.layer.soviet-topomaps-grid/index.js',
'src/lib/leaflet.layer.westraPasses/index.js',
'src/lib/leaflet.layer.wikimapia/index.js',
diff --git a/eslint_rules/legacy_files_list.js b/eslint_rules/legacy_files_list.js
@@ -127,6 +127,7 @@ module.exports = [
'src/lib/leaflet.layer.rasterize/MeasuredLine.js',
'src/lib/leaflet.layer.rasterize/Bing.js',
'src/lib/leaflet.layer.rasterize/Yandex.js',
+ 'src/lib/leaflet.layer.rasterize/RetinaTileLayer.js',
'src/lib/leaflet.layer.bing/dates.js',
'src/lib/leaflet.layer.bing/index.js',
'src/lib/logging/index.js',
diff --git a/src/layers.js b/src/layers.js
@@ -8,6 +8,7 @@ import '~/lib/leaflet.layer.soviet-topomaps-grid';
import '~/lib/leaflet.layer.westraPasses';
import '~/lib/leaflet.layer.wikimapia';
import {GeocachingSu} from '~/lib/leaflet.layer.geocaching-su';
+import {RetinaTileLayer} from '~/lib/leaflet.layer.RetinaTileLayer';
import urlViaCorsProxy from '~/lib/CORSProxy';
const layersDefs = [
@@ -616,10 +617,15 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
{
title: 'Strava heatmap (all)',
isDefault: false,
- layer: L.tileLayer(
- urlViaCorsProxy(
- 'https://heatmap-external-a.strava.com/tiles-auth/all/hot/{z}/{x}/{y}.png?px=256'
- ),
+ layer: new RetinaTileLayer(
+ [
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/all/hot/{z}/{x}/{y}.png?px=256'
+ ),
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/all/hot/{z}/{x}/{y}.png?px=512'
+ ),
+ ],
{
code: 'Sa',
isOverlay: true,
@@ -628,19 +634,24 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
print: true,
jnx: false,
subdomains: 'abc',
- maxNativeZoom: 16,
noCors: true,
shortName: 'strava_all',
+ retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
}
)
},
{
title: 'Strava heatmap (run)',
isDefault: false,
- layer: L.tileLayer(
- urlViaCorsProxy(
- 'https://heatmap-external-a.strava.com/tiles-auth/run/hot/{z}/{x}/{y}.png?px=256'
- ),
+ layer: new RetinaTileLayer(
+ [
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/run/hot/{z}/{x}/{y}.png?px=256'
+ ),
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/run/hot/{z}/{x}/{y}.png?px=512'
+ ),
+ ],
{
code: 'Sr',
isOverlay: true,
@@ -649,19 +660,24 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
print: true,
jnx: false,
subdomains: 'abc',
- maxNativeZoom: 16,
noCors: true,
shortName: 'strava_run',
+ retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
}
)
},
{
title: 'Strava heatmap (ride)',
isDefault: false,
- layer: L.tileLayer(
- urlViaCorsProxy(
- 'https://heatmap-external-a.strava.com/tiles-auth/ride/hot/{z}/{x}/{y}.png?px=256'
- ),
+ layer: new RetinaTileLayer(
+ [
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/ride/hot/{z}/{x}/{y}.png?px=256'
+ ),
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/ride/hot/{z}/{x}/{y}.png?px=512'
+ ),
+ ],
{
code: 'Sb',
isOverlay: true,
@@ -670,19 +686,24 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
print: true,
jnx: false,
subdomains: 'abc',
- maxNativeZoom: 16,
noCors: true,
shortName: 'strava_ride',
+ retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
}
)
},
{
title: 'Strava heatmap (winter)',
isDefault: false,
- layer: L.tileLayer(
- urlViaCorsProxy(
- 'https://heatmap-external-a.strava.com/tiles-auth/winter/hot/{z}/{x}/{y}.png?px=256'
- ),
+ layer: new RetinaTileLayer(
+ [
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/winter/hot/{z}/{x}/{y}.png?px=256'
+ ),
+ urlViaCorsProxy(
+ 'https://heatmap-external-a.strava.com/tiles-auth/winter/hot/{z}/{x}/{y}.png?px=512'
+ ),
+ ],
{
code: 'Sw',
isOverlay: true,
@@ -691,9 +712,9 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
print: true,
jnx: false,
subdomains: 'abc',
- maxNativeZoom: 16,
noCors: true,
shortName: 'strava_winter',
+ retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
}
)
},
@@ -756,7 +777,11 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
{
title: 'Czech base',
isDefault: false,
- layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/base-m/{z}-{x}-{y}",
+ layer: new RetinaTileLayer(
+ [
+ 'https://m{s}.mapserver.mapy.cz/base-m/{z}-{x}-{y}',
+ 'https://m{s}.mapserver.mapy.cz/base-m/retina/{z}-{x}-{y}'
+ ],
{
code: 'Czb',
isOverlay: false,
@@ -772,7 +797,11 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
{
title: 'mapy.cz tourist',
isDefault: true,
- layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/turist-m/{z}-{x}-{y}",
+ layer: new RetinaTileLayer(
+ [
+ 'https://m{s}.mapserver.mapy.cz/turist-m/{z}-{x}-{y}',
+ 'https://m{s}.mapserver.mapy.cz/turist-m/retina/{z}-{x}-{y}',
+ ],
{
code: 'Czt',
isOverlay: false,
@@ -789,7 +818,11 @@ import urlViaCorsProxy from '~/lib/CORSProxy';
{
title: 'Czech winter',
isDefault: false,
- layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/winter-m/{z}-{x}-{y}",
+ layer: new RetinaTileLayer(
+ [
+ 'https://m{s}.mapserver.mapy.cz/winter-m/{z}-{x}-{y}',
+ 'https://m{s}.mapserver.mapy.cz/winter-m/retina/{z}-{x}-{y}',
+ ],
{
code: 'Czw',
isOverlay: false,
diff --git a/src/lib/leaflet.control.printPages/map-render.js b/src/lib/leaflet.control.printPages/map-render.js
@@ -105,6 +105,7 @@ class PageComposer {
this.projectedBounds = pixelBoundsAtZoom24;
this.currentCanvas = null;
this.currentZoom = null;
+ this.currentTileScale = null;
this.targetCanvas = this.createCanvas(destSize);
}
@@ -125,20 +126,26 @@ class PageComposer {
} else {
zoom = tileInfo.zoom;
}
- if (zoom !== this.currentZoom) {
+ if (zoom !== this.currentZoom || tileInfo.tileScale !== this.currentTileScale) {
this.mergeCurrentCanvas();
- this.setupCurrentCanvas(zoom);
+ this.setupCurrentCanvas(zoom, tileInfo.tileScale);
}
if (tileInfo.isOverlay) {
tileInfo.draw(this.currentCanvas);
} else {
const ctx = this.currentCanvas.getContext('2d');
const {tilePos, tileSize} = tileInfo;
- ctx.drawImage(tileInfo.image, tilePos.x, tilePos.y, tileSize.x, tileSize.y);
+ ctx.drawImage(
+ tileInfo.image,
+ tilePos.x * tileInfo.tileScale,
+ tilePos.y * tileInfo.tileScale,
+ tileSize.x * tileInfo.tileScale,
+ tileSize.y * tileInfo.tileScale
+ );
}
}
- setupCurrentCanvas(zoom) {
+ setupCurrentCanvas(zoom, tileScale) {
let size;
if (zoom === 'overlay' || zoom === 'solidOverlay') {
size = this.destSize;
@@ -147,10 +154,11 @@ class PageComposer {
const
topLeft = this.projectedBounds.min.divideBy(q).round(),
bottomRight = this.projectedBounds.max.divideBy(q).round();
- size = bottomRight.subtract(topLeft);
+ size = bottomRight.subtract(topLeft).multiplyBy(tileScale);
}
this.currentCanvas = this.createCanvas(size);
this.currentZoom = zoom;
+ this.currentTileScale = tileScale;
}
mergeCurrentCanvas() {
@@ -211,7 +219,7 @@ async function* iterateLayersTiles(
map = getTempMap(zoom, layer._rasterizeNeedsFullSizeMap, pixelBounds);
map.addLayer(layer);
}
- let {iterateTilePromises, count} = await layer.getTilesInfo({
+ let {iterateTilePromises, count, tileScale = 1} = await layer.getTilesInfo({
xhrOptions: defaultXHROptions,
pixelBounds,
latLngBounds,
@@ -227,8 +235,13 @@ async function* iterateLayersTiles(
for (let tilePromise of iterateTilePromises()) {
layerPromises.push(tilePromise.tilePromise);
let progressInc = (layer._printProgressWeight || 1) / count;
- tilePromise.tilePromise =
- tilePromise.tilePromise.then((tileInfo) => ({zoom, progressInc, layer, ...tileInfo}));
+ tilePromise.tilePromise = tilePromise.tilePromise.then((tileInfo) => ({
+ zoom,
+ progressInc,
+ layer,
+ tileScale,
+ ...tileInfo,
+ }));
doStop = yield tilePromise;
if (doStop) {
tilePromise.abortLoading();
diff --git a/src/lib/leaflet.layer.RetinaTileLayer/index.js b/src/lib/leaflet.layer.RetinaTileLayer/index.js
@@ -0,0 +1,24 @@
+import L from 'leaflet';
+
+class RetinaTileLayer extends L.TileLayer {
+ constructor(urls, options, hiRes = 'auto') {
+ let url, tileSizeMultiplicator;
+ const useHiResTiles = hiRes === 'auto' ? L.Browser.retina : hiRes;
+ const newOptions = L.extend({}, options);
+ if (useHiResTiles) {
+ url = urls[1];
+ tileSizeMultiplicator = 2;
+ } else {
+ tileSizeMultiplicator = 1;
+ url = urls[0];
+ }
+ if (options.retinaOptionsOverrides) {
+ L.extend(newOptions, options.retinaOptionsOverrides[useHiResTiles ? 1 : 0]);
+ }
+ super(url, newOptions);
+ this.urls = urls;
+ this.tileSizeMultiplicator = tileSizeMultiplicator;
+ }
+}
+
+export {RetinaTileLayer};
diff --git a/src/lib/leaflet.layer.rasterize/RetinaTileLayer.js b/src/lib/leaflet.layer.rasterize/RetinaTileLayer.js
@@ -0,0 +1,17 @@
+import L from 'leaflet';
+
+import {RetinaTileLayer} from '~/lib/leaflet.layer.RetinaTileLayer';
+import './TileLayer';
+
+RetinaTileLayer.include({
+ cloneForPrint: function(options) {
+ const newOptions = L.Util.extend({}, this.options, options);
+ return new RetinaTileLayer(this.urls, newOptions, newOptions.scaleDependent);
+ },
+
+ getTilesInfo: async function(printOptions) {
+ const tilesInfo = await L.TileLayer.prototype.getTilesInfo.call(this, printOptions);
+ tilesInfo.tileScale = this.tileSizeMultiplicator;
+ return tilesInfo;
+ },
+});
diff --git a/src/lib/leaflet.layer.rasterize/Yandex.js b/src/lib/leaflet.layer.rasterize/Yandex.js
@@ -3,7 +3,13 @@ import '~/lib/leaflet.layer.yandex';
L.Layer.Yandex.Map.include({
cloneForPrint: function(options) {
- return new L.Layer.Yandex.Map({...this.options, ...options});
+ return new L.Layer.Yandex.Map({...this.options, ...options, yandexScale: 2});
+ },
+
+ getTilesInfo: async function(printOptions) {
+ const tilesInfo = await L.TileLayer.prototype.getTilesInfo.call(this, printOptions);
+ tilesInfo.tileScale = 2;
+ return tilesInfo;
},
});
diff --git a/src/lib/leaflet.layer.rasterize/index.js b/src/lib/leaflet.layer.rasterize/index.js
@@ -6,6 +6,7 @@ import './Google';
import './WestraPasses';
import './CanvasMarkers';
import './MeasuredLine';
+import './RetinaTileLayer';
function getTempMap(zoom, fullSize, pixelBounds) {
const container = L.DomUtil.create('div', '', document.body);