nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

commit 20eee8b4cf39b08c2089701ff0f7686e3dd00a79
parent ec7b6cfe2a32a1ee8639337c0ba7c6418508a171
Author: Sergej Orlov <wladimirych@gmail.com>
Date:   Wed, 15 Feb 2017 21:46:00 +0300

[print] support for google, westra passes, waypoints

Diffstat:
Msrc/layers.js | 2--
Msrc/lib/leaflet.control.printPages/map-render.js | 33++++++++++++++++++++++-----------
Msrc/lib/leaflet.control.track-list/track-list.js | 29++---------------------------
Msrc/lib/leaflet.layer.google/index.js | 3+--
Msrc/lib/leaflet.layer.rasterize/Bing.js | 6+-----
Asrc/lib/leaflet.layer.rasterize/CanvasMarkers.js | 28++++++++++++++++++++++++++++
Asrc/lib/leaflet.layer.rasterize/Google.js | 44++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/leaflet.layer.rasterize/TileLayer.js | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Asrc/lib/leaflet.layer.rasterize/WestraPasses.js | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/lib/leaflet.layer.rasterize/index.js | 3+++
Msrc/lib/leaflet.layer.westraPasses/index.js | 2+-
Msrc/lib/leaflet.layer.westraPasses/westraPassesMarkers.js | 2++
12 files changed, 235 insertions(+), 88 deletions(-)

diff --git a/src/layers.js b/src/layers.js @@ -237,8 +237,6 @@ export default function getLayers() { }, ] }, - - { group: 'OpenStreetMap alternatives', layers: [ diff --git a/src/lib/leaflet.control.printPages/map-render.js b/src/lib/leaflet.control.printPages/map-render.js @@ -114,19 +114,33 @@ class PageComposer { } } -function getTempMap(zoom) { +function getTempMap(zoom, fullSize, pixelBounds) { const container = L.DomUtil.create('div', '', document.body); + let width, height, center; + if (fullSize) { + const size = pixelBounds.getSize(); + width = size.x; + height = size.y; + center = pixelBounds.min.add(size.divideBy(2)); + center = L.CRS.EPSG3857.pointToLatLng(center, zoom); + } else { + width = 100; + height = 100; + center = L.latLng(0, 0); + } + Object.assign(container.style, { - width: '100px', - height: '100px', + width: `${width}px`, + height: `${height}px`, position: 'absolute', left: '0', top: '0', - // visibility: 'hidden' + visibility: 'hidden' } ); + const map = L.map(container, {fadeAnimation: false, zoomAnimation: false, inertia: false}); - map.setView(L.latLng(0, 0), zoom); + map.setView(center, zoom); return map; } @@ -150,11 +164,11 @@ async function* iterateLayersTiles(layers, latLngBounds, zooms) { } else { zoom = zooms.satZoom; } - let map = getTempMap(zoom); let pixelBounds = L.bounds( - map.project(latLngBounds.getNorthWest()).round(), - map.project(latLngBounds.getSouthEast()).round() + L.CRS.EPSG3857.latLngToPoint(latLngBounds.getNorthWest(), zoom).round(), + L.CRS.EPSG3857.latLngToPoint(latLngBounds.getSouthEast(), zoom).round() ); + let map = getTempMap(zoom, layer._rasterizeNeedsFullSizeMap, pixelBounds); map.addLayer(layer); let {iterateTilePromises, count} = await layer.getTilesInfo({xhrOptions: defaultXHROptions, pixelBounds}); for (let tilePromise of iterateTilePromises()) { @@ -163,7 +177,6 @@ async function* iterateLayersTiles(layers, latLngBounds, zooms) { doStop = yield tilePromise; if (doStop) { tilePromise.abortLoading(); - console.log('DO STOP3'); break; } } @@ -187,7 +200,6 @@ async function* promiseQueueBuffer(source, maxActive) { while (queue.length) { let doStop = yield queue.shift(); if (doStop) { - console.log('DO STOP2'); let {value, done} = await source.next(true); if (!done) { queue.push(value); @@ -231,7 +243,6 @@ async function renderPages({map, pages, zooms, resolution, progressCallback}) { try { tileInfo = await tilePromise.tilePromise; } catch (e) { - console.log('DO STOP1'); queuedTilesIterator.next(true); throw e; } diff --git a/src/lib/leaflet.control.track-list/track-list.js b/src/lib/leaflet.control.track-list/track-list.js @@ -21,32 +21,6 @@ import 'lib/leaflet.control.elevation-profile'; var MeasuredEditableLine = L.MeasuredLine.extend({}); MeasuredEditableLine.include(L.Polyline.EditMixin); -var Waypoints = L.Layer.CanvasMarkers.extend({ - options: { - scaleDependent: true - }, - - clone: function() { - var markers = this.rtree.all(), - markersCopy; - - function cloneMarker(marker) { - return { - latlng: {lat: marker.latlng.lat, lng: marker.latlng.lng}, - label: marker.label, - icon: marker.icon - }; - } - - markersCopy = markers.map(cloneMarker); - var options = {}; - L.extend(options, this.options, {iconScale: 1.5, labelFontSize: 14}); - return new Waypoints(markersCopy, options); - } - } -); - - L.Control.TrackList = L.Control.extend({ options: {position: 'bottomright'}, @@ -126,7 +100,7 @@ L.Control.TrackList = L.Control.extend({ {text: 'Delete hidden tracks', callback: this.deleteHiddenTracks.bind(this)} ] ); - this._markerLayer = new Waypoints(null, {print: true}).addTo(map); + this._markerLayer = new L.Layer.CanvasMarkers(null, {print: true, scaleDependent: true}).addTo(map); this._markerLayer.on('markerclick markercontextmenu', this.onMarkerClick, this); map.on('resize', this._setAdaptiveHeight, this); setTimeout(() => this._setAdaptiveHeight(), 0); @@ -491,6 +465,7 @@ L.Control.TrackList = L.Control.extend({ var fileText = exporter(lines, name, points); var filename = name + extension; + // FIXME: make function stringToBlob: convert string to byteArray first saveAs(new Blob([fileText], {type: 'application/download'}), filename); }, diff --git a/src/lib/leaflet.layer.google/index.js b/src/lib/leaflet.layer.google/index.js @@ -7,7 +7,6 @@ L.Layer.Google = L.GridLayer.extend({ // Possible types: SATELLITE, ROADMAP, HYBRID, TERRAIN initialize: function(mapType, options) { L.GridLayer.prototype.initialize.call(this, options); - L.Layer.prototype.constructor(options); this.mapType = mapType; }, @@ -55,7 +54,7 @@ L.Layer.Google = L.GridLayer.extend({ } this._googleMap = null; this._clearTiles(); - map.getContainer().removeChild(this._googleMapContainer); + L.DomUtil.remove(this._googleMapContainer); map.off({ viewreset: this._clearTiles, resize: this._onResize, diff --git a/src/lib/leaflet.layer.rasterize/Bing.js b/src/lib/leaflet.layer.rasterize/Bing.js @@ -2,7 +2,7 @@ import L from 'leaflet'; import 'lib/leaflet.layer.bing'; L.BingLayer.include({ - whenReady: function() { + waitTilesReadyToGrab: function() { if (this._url) { return Promise.resolve(); } else { @@ -22,9 +22,5 @@ L.BingLayer.include({ cloneForPrint: function(options) { return new L.BingLayer(this._key, L.Util.extend({}, this.options, options)); }, - - getTilesInfo: function(printOptions) { - return this.whenReady().then(() => L.TileLayer.prototype.getTilesInfo.call(this, printOptions)); - } } ); diff --git a/src/lib/leaflet.layer.rasterize/CanvasMarkers.js b/src/lib/leaflet.layer.rasterize/CanvasMarkers.js @@ -0,0 +1,28 @@ +import L from "leaflet"; +import 'lib/leaflet.layer.canvasMarkers' +import {CanvasLayerGrabMixin} from './TileLayer'; + +L.Layer.CanvasMarkers.include(CanvasLayerGrabMixin); +L.Layer.CanvasMarkers.include({ + cloneMarkers: function() { + const markers = this.rtree.all(); + + function cloneMarker(marker) { + return { + latlng: {lat: marker.latlng.lat, lng: marker.latlng.lng}, + label: marker.label, + icon: marker.icon + }; + } + + const markersCopy = markers.map(cloneMarker); + return markersCopy; + }, + + cloneForPrint: function(options) { + options = L.Util.extend({}, this.options, {iconScale: 1.5, labelFontSize: 14}); + return new L.Layer.CanvasMarkers(this.cloneMarkers(), options); + + } + } +); diff --git a/src/lib/leaflet.layer.rasterize/Google.js b/src/lib/leaflet.layer.rasterize/Google.js @@ -0,0 +1,44 @@ +import L from 'leaflet'; +import 'lib/leaflet.layer.google'; +import {TileLayerGrabMixin} from './TileLayer'; + + + +const GooglePrint = L.Layer.Google.extend({ + includes: TileLayerGrabMixin, + + _rasterizeNeedsFullSizeMap: true, + + _dummyTile: L.DomUtil.create('div'), + + onAdd: function(map) { + this._waitTilesReadyToGrab = new Promise((resolve) => { + this._tilesReadyToGrab = resolve; + }); + L.Layer.Google.prototype.onAdd.call(this, map); + }, + + waitTilesReadyToGrab: function() { + return this._waitTilesReadyToGrab; + }, + + createTile: function() { + return this._dummyTile; + }, + + _fullfillPendingTiles: function() { + this._tilesReadyToGrab(); + }, + + getTileUrl: function(coords) { + return this._readyTiles[this._tileCoordsToKey(coords)]; + } +}); + + +L.Layer.Google.include({ + cloneForPrint: function(options) { + return new GooglePrint(this.mapType, L.Util.extend({}, this.options, options)); + }, +}); + diff --git a/src/lib/leaflet.layer.rasterize/TileLayer.js b/src/lib/leaflet.layer.rasterize/TileLayer.js @@ -2,51 +2,100 @@ import L from 'leaflet'; import urlViaCorsProxy from 'lib/CORSProxy'; import {imgFromDataString} from './imgFromDataString'; -L.TileLayer.include({ +const GridLayerGrabMixin = { + tileImagePromiseFromCoords: function(coords) { + throw new Error('Method not implemented'); + }, + + waitTilesReadyToGrab: function() { + return Promise.resolve(null); + }, + + getTilesInfo: async function(printOptions) { + await this.waitTilesReadyToGrab(); + const {pixelBounds} = printOptions; + const tileRange = this._pxBoundsToTileRange(pixelBounds); + const topLeft = pixelBounds.min; + const tilePromiseIterator = (function*() { + for (let j = tileRange.min.y; j <= tileRange.max.y; j++) { + for (let i = tileRange.min.x; i <= tileRange.max.x; i++) { + let coords = new L.Point(i, j); + coords.z = this._tileZoom; + coords = this._wrapCoords(coords); + + if (!this._isValidTile(coords)) { + continue; + } + let tilePos = this._getTilePos(coords); + const coordsPlusOne = coords.add(L.point(1, 1)); + coordsPlusOne.z = coords.z; + const tileSize = this._getTilePos(coordsPlusOne).subtract(tilePos); + tilePos = tilePos.add(this._level.origin).subtract(topLeft); + let {tilePromise, abortLoading} = this.tileImagePromiseFromCoords(coords, printOptions); + yield { + tilePromise: tilePromise.then((image) => { + return {image, tilePos, tileSize}; + } + ), + abortLoading + }; + } + } + }).bind(this); + return { + iterateTilePromises: tilePromiseIterator, + count: (tileRange.max.x - tileRange.min.x + 1) * (tileRange.max.y - tileRange.min.y + 1) + }; + } +}; + +const TileLayerGrabMixin = L.Util.extend({}, GridLayerGrabMixin, { cloneForPrint: function(options) { return L.tileLayer(this._url, L.Util.extend({}, this.options, options)); }, - getTilesInfo: function(printOptions) { - const {pixelBounds, xhrOptions} = printOptions; - const tileRange = this._pxBoundsToTileRange(pixelBounds); - const topLeft = pixelBounds.min; - const tilePromiseIterator = (function*() { - for (let j = tileRange.min.y; j <= tileRange.max.y; j++) { - for (let i = tileRange.min.x; i <= tileRange.max.x; i++) { - let coords = new L.Point(i, j); - coords.z = this._tileZoom; - - if (!this._isValidTile(coords)) { - continue; - } - - let url = this.getTileUrl(coords); - if (this.options.noCors) { - url = urlViaCorsProxy(url); - } - let tilePos = this._getTilePos(coords); - const coordsPlusOne = coords.add(L.point(1, 1)); - coordsPlusOne.z = coords.z; - const tileSize = this._getTilePos(coordsPlusOne).subtract(tilePos); - tilePos = tilePos.add(this._level.origin).subtract(topLeft); - let promise = this.options.xhrQueue.put(url, xhrOptions); - yield { - tilePromise: promise.then(imgFromDataString).then((image) => { - return {image, tilePos, tileSize}; - } - ), - abortLoading: () => promise.abort() - }; - } - } - }).bind(this); - return Promise.resolve({ - iterateTilePromises: tilePromiseIterator, - count: (tileRange.max.x - tileRange.min.x + 1) * (tileRange.max.y - tileRange.min.y + 1) - } - ); + tileImagePromiseFromCoords: function(coords, printOptions) { + let {xhrOptions} = printOptions; + let url = this.getTileUrl(coords); + if (this.options.noCors) { + url = urlViaCorsProxy(url); + } + let promise = this.options.xhrQueue.put(url, xhrOptions); + return { + tilePromise: promise.then(imgFromDataString), + abortLoading: () => promise.abort() + } } } ); +function noop() { + +} + +const CanvasLayerGrabMixin = L.Util.extend({}, GridLayerGrabMixin, { + getCanvasFromTile: function(tile) { + return tile; + }, + + tileImagePromiseFromCoords: function(coords) { + let tilePromise; + if (this.createTile.length < 2) { + let tile = this.createTile(coords); + tilePromise = Promise.resolve(tile); + } else { + tilePromise = new Promise((resolve) => { + return this.createTile(coords, resolve); + }); + } + + return { + tilePromise: tilePromise.then(this.getCanvasFromTile), + abortLoading: noop + } + } +}); + +L.TileLayer.include(TileLayerGrabMixin); + +export {TileLayerGrabMixin, GridLayerGrabMixin, CanvasLayerGrabMixin}; +\ No newline at end of file diff --git a/src/lib/leaflet.layer.rasterize/WestraPasses.js b/src/lib/leaflet.layer.rasterize/WestraPasses.js @@ -0,0 +1,41 @@ +import L from "leaflet"; +import 'lib/leaflet.layer.westraPasses'; +import {WestraPassesMarkers} from 'lib/leaflet.layer.westraPasses/westraPassesMarkers'; +import {CanvasLayerGrabMixin} from './TileLayer'; +import 'lib/leaflet.layer.canvasMarkers' + +const WestraPrint = L.Layer.CanvasMarkers.extend({ + includes: CanvasLayerGrabMixin, + + initialize: function(srcLayer, options) { + this.srcLayer = srcLayer; + L.Layer.CanvasMarkers.prototype.initialize.call(this, null, options); + }, + + waitTilesReadyToGrab: function() { + let promise; + if (this.srcLayer._dataLoaded) { + promise = Promise.resolve(null); + } else { + // FIXME: handle data load errors + promise = new Promise((resolve) => { + this.srcLayer.once('data-loaded', resolve); + }) + } + return promise.then(() => { + this.addMarkers(this.srcLayer.rtree.all()); + }) + }, +}); + +L.Layer.WestraPasses.addInitHook(function() { + this.markers.options.print = this.options.print; + this.options.print = false; +}); + +WestraPassesMarkers.include({ + cloneForPrint: function (options) { + return new WestraPrint(this, L.Util.extend( + {}, this.options, {iconScale: 1.5, labelFontSize: 14}, options)); + } +}); diff --git a/src/lib/leaflet.layer.rasterize/index.js b/src/lib/leaflet.layer.rasterize/index.js @@ -1,3 +1,6 @@ import './TileLayer' import './Bing' import './Yandex' +import './Google' +import './WestraPasses' +import './CanvasMarkers' diff --git a/src/lib/leaflet.layer.westraPasses/index.js b/src/lib/leaflet.layer.westraPasses/index.js @@ -24,6 +24,7 @@ L.Layer.WestraPasses = L.Layer.extend({ } ); }, + _setRegionLabel: function(layerName, feature, layer) { var latlon = layer.getBounds().getCenter(); var icon = L.divIcon({ @@ -96,4 +97,3 @@ L.Layer.WestraPasses = L.Layer.extend({ ); - diff --git a/src/lib/leaflet.layer.westraPasses/westraPassesMarkers.js b/src/lib/leaflet.layer.westraPasses/westraPassesMarkers.js @@ -124,6 +124,8 @@ const WestraPassesMarkers = L.Layer.CanvasMarkers.extend({ markers.push(marker); } this.addMarkers(markers); + this._dataLoaded = true; + this.fire('data-loaded'); },