nakarte

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

commit 7ba6f41ef4e8fe0f84dc54dae97e1fde2bf8159a
parent 4a3b9d6dd80123df34fa9d38b84097f431c2aad0
Author: Sergej Orlov <wladimirych@gmail.com>
Date:   Thu,  5 May 2022 10:00:48 +0200

mapillary: Replace vector coverage layer with raster

Diffstat:
Msrc/config.js | 1+
Msrc/lib/leaflet.control.panoramas/lib/mapillary/index.js | 7+++++--
Dsrc/lib/leaflet.control.panoramas/lib/mapillary/mapillary-coverage-layer.js | 160-------------------------------------------------------------------------------
Dsrc/lib/leaflet.control.panoramas/lib/mapillary/mapillary-loader.js | 87-------------------------------------------------------------------------------
Dsrc/lib/leaflet.control.panoramas/lib/mapillary/mvt.js | 123-------------------------------------------------------------------------------
Dsrc/lib/leaflet.control.panoramas/lib/mapillary/vector_tile_pb.js | 46----------------------------------------------
6 files changed, 6 insertions(+), 418 deletions(-)

diff --git a/src/config.js b/src/config.js @@ -16,6 +16,7 @@ const config = { geocachingSuUrl: 'https://nakarte.me/geocachingSu/geocaching_su2.json', tracksStorageServer: 'https://tracks.nakarte.me', wikimapiaTilesBaseUrl: 'https://proxy.nakarte.me/wikimapia/', + mapillaryRasterTilesUrl: 'https://mapillary.nakarte.me/{z}/{x}/{y}', ...secrets }; diff --git a/src/lib/leaflet.control.panoramas/lib/mapillary/index.js b/src/lib/leaflet.control.panoramas/lib/mapillary/index.js @@ -1,12 +1,15 @@ import L from 'leaflet'; -import {MapillaryCoverage} from './mapillary-coverage-layer'; import {fetch} from '~/lib/xhr-promise'; import config from '~/config'; import './style.css'; import {CloseButtonMixin, DateLabelMixin} from '../common'; function getCoverageLayer(options) { - return new MapillaryCoverage(options); + return L.tileLayer(config.mapillaryRasterTilesUrl, L.extend({ + tileSize: 1024, + zoomOffset: -2, + minNativeZoom: 0, + }, options)); } async function getMapillary() { diff --git a/src/lib/leaflet.control.panoramas/lib/mapillary/mapillary-coverage-layer.js b/src/lib/leaflet.control.panoramas/lib/mapillary/mapillary-coverage-layer.js @@ -1,160 +0,0 @@ -import L from 'leaflet'; -import {MapillaryLoader} from './mapillary-loader'; - -const MapillaryCoverage = L.GridLayer.extend({ - options: { - tileSize: 1024, - updateWhenIdle: true, - color: '#00cfb1' - }, - - initialize: function(options) { - L.GridLayer.prototype.initialize.call(this, options); - this.loader = new MapillaryLoader(this.options.url, 12); - }, - - onAdd: function(map) { - L.GridLayer.prototype.onAdd.call(this, map); - this.on('tileunload', this.onTileUnload, this); - }, - - onRemove: function(map) { - L.GridLayer.prototype.onRemove.call(this, map); - this.off('tileunload', this.onTileUnload, this); - }, - - onTileUnload: function(e) { - const tile = e.tile; - tile._abortLoading(); - delete tile._tileData; - delete tile._adjustment; - }, - - drawOverview: function(canvas) { - const - tileData = canvas._tileData; - if (!tileData['mapillary-sequence-overview']) { - return; - } - let {multiplier, offsetX, offsetY} = canvas._adjustment; - const canvasCtx = canvas.getContext('2d'); - canvasCtx.fillStyle = this.options.color; - for (let feature of tileData['mapillary-sequence-overview']) { - if (feature.geometry.type !== 'Point') { - throw new Error(`Invalid sequence overview geometry type "${feature.geometry.type}"`); - } - canvasCtx.beginPath(); - let x = feature.geometry.coordinates[0] * multiplier - offsetX; - let y = feature.geometry.coordinates[1] * multiplier - offsetY; - canvasCtx.arc(x, y, 5, 0, 2 * Math.PI); - canvasCtx.fill(); - } - }, - - drawSequences: function(canvas, lineWidth) { - let - tileData = canvas._tileData, - adjustment = canvas._adjustment; - - if (!tileData['mapillary-sequences']) { - return; - } - const canvasCtx = canvas.getContext('2d'); - canvasCtx.beginPath(); - canvasCtx.strokeStyle = this.options.color; - canvasCtx.lineWidth = lineWidth; - // canvasCtx.lineWidth = thinLines ? 1 : 1; - canvasCtx.lineCap = "round"; - canvasCtx.lineJoin = "bevel"; - for (let feature of tileData['mapillary-sequences']) { - if (feature.geometry.type !== 'MultiLineString') { - throw new Error(`Invalid sequence geometry type "${feature.geometry.type}"`); - } - let {multiplier, offsetX, offsetY} = adjustment; - - let lines = feature.geometry.coordinates; - for (let lineI = 0; lineI < lines.length; lineI++) { - let line = lines[lineI]; - if (!line.length) { - continue; - } - let x = line[0][0] * multiplier - offsetX; - let y = line[0][1] * multiplier - offsetY; - canvasCtx.moveTo(x, y); - if (line.length === 1) { - canvasCtx.lineTo(x, y); - } - for (let pointI = 0; pointI < line.length; pointI++) { - let x = line[pointI][0] * multiplier - offsetX; - let y = line[pointI][1] * multiplier - offsetY; - canvasCtx.lineTo(x, y); - } - } - } - canvasCtx.stroke(); - }, - - drawImages: function(canvas) { - let - tileData = canvas._tileData, - adjustment = canvas._adjustment; - if (!tileData['mapillary-images']) { - return; - } - let {multiplier, offsetX, offsetY} = adjustment; - const canvasCtx = canvas.getContext('2d'); - canvasCtx.beginPath(); - canvasCtx.fillStyle = this.options.color; - for (let feature of tileData['mapillary-images']) { - if (feature.geometry.type !== 'Point') { - throw new Error(`Invalid image geometry type "${feature.geometry.type}"`); - } - canvasCtx.beginPath(); - let x = feature.geometry.coordinates[0] * multiplier - offsetX; - let y = feature.geometry.coordinates[1] * multiplier - offsetY; - canvasCtx.arc(x, y, 4, 0, 2 * Math.PI); - canvasCtx.fill(); - } - }, - - drawTile: function(canvas, coords) { - if (!this._map) { - return; - } - if (!canvas._tileData) { - return; - } - if (coords.z < 6 + 2) { - this.drawOverview(canvas); - } else if (coords.z < 14 + 2) { - let width = coords.z < 14 ? 10 : 5; - this.drawSequences(canvas, width); - } else { - this.drawSequences(canvas, 2); - this.drawImages(canvas); - } - }, - - createTile: function(coords, done) { - const canvas = L.DomUtil.create('canvas', 'leaflet-tile'); - canvas.width = this.options.tileSize; - canvas.height = this.options.tileSize; - let {dataPromise, abortLoading} = this.loader.requestTileData(coords); - dataPromise.then((data) => { - if (!data.error) { - canvas._tileData = data.tileData; - canvas._adjustment = data.adjustment || {multiplier: 1, offsetX: 0, offsetY: 0}; - setTimeout(() => { - this.drawTile(canvas, coords); - done(null, canvas); - }, 1); - } - }); - canvas._abortLoading = abortLoading; - return canvas; - }, - - } -); - -export {MapillaryCoverage}; diff --git a/src/lib/leaflet.control.panoramas/lib/mapillary/mapillary-loader.js b/src/lib/leaflet.control.panoramas/lib/mapillary/mapillary-loader.js @@ -1,87 +0,0 @@ -import L from 'leaflet'; -import {TiledDataLoader} from '~/lib/tiled-data-loader'; -import {decodeMvt} from './mvt'; - -class MapillaryLoader extends TiledDataLoader { - url = 'https://d25uarhxywzl1j.cloudfront.net/v0.1/{z}/{x}/{y}.mvt'; - maxZoom = 14; - - getTileUrl(coords) { - const data = { - x: coords.x, - z: coords.z, - y: coords.y - }; - return L.Util.template(this.url, data); - } - - layerTileToDataTileCoords(layerTileCoords) { - let z = layerTileCoords.z - 2; - let z2 = null; - if (z > 6 && z <= 10) { - z2 = 6; - } else if (z >= 11 && z < 14) { - z2 = z - 4; - } else if (z < 0) { - z2 = 0; - } else if (z > this.maxZoom) { - z2 = this.maxZoom; - } else { - return {z, x: layerTileCoords.x, y: layerTileCoords.y}; - } - - let multiplier = 1 << (z - z2); - return { - x: Math.floor(layerTileCoords.x / multiplier), - y: Math.floor(layerTileCoords.y / multiplier), - z: z2 - }; - } - - makeRequestData(dataTileCoords) { - return { - url: this.getTileUrl(dataTileCoords), - options: { - responseType: 'arraybuffer', - timeout: 10000, - isResponseSuccess: (xhr) => xhr.status === 200 || xhr.status === 403 - } - }; - } - - calcAdjustment(layerTileCoords, dataTileCoords) { - let adjustment = super.calcAdjustment( - {x: layerTileCoords.x, y: layerTileCoords.y, z: layerTileCoords.z - 2}, - dataTileCoords - ); - if (adjustment) { - adjustment.offsetX *= 1024; - adjustment.offsetY *= 1024; - } - return adjustment; - } - - async processResponse(xhr, originalDataTileCoords) { - return this._processResponse(xhr, originalDataTileCoords); - } - - async _processResponse(xhr, originalDataTileCoords) { - let tileData; - if (xhr.status === 200 && xhr.response) { - const layers = decodeMvt(xhr.response, 1024); - tileData = {}; - for (let layer of layers) { - tileData[layer.name] = layer.features; - } - } else { - tileData = null; - } - - return { - tileData, - coords: originalDataTileCoords - }; - } -} - -export {MapillaryLoader}; diff --git a/src/lib/leaflet.control.panoramas/lib/mapillary/mvt.js b/src/lib/leaflet.control.panoramas/lib/mapillary/mvt.js @@ -1,123 +0,0 @@ -import Pbf from 'pbf'; -import {Tile as TileProto} from './vector_tile_pb'; - -function decodeCoordinate(x) { - return ((x >> 1) ^ (-(x & 1))); -} - -function parseGeometry(geometryType, ints, coordinatesScale) { // eslint-disable-line complexity - if (geometryType !== TileProto.GeomType.POINT && geometryType !== TileProto.GeomType.LINESTRING && - geometryType !== TileProto.GeomType.POLYGON) { - throw new Error(`Unknown feature geometry type ${geometryType}`); - } - const len = ints.length; - let pos = 0; - const lineStrings = []; - let line; - let x = 0, - y = 0; - while (pos < len) { - let i = ints[pos]; - let cmd = i & 0x7; - let cmdRepeat = i >> 3; - switch (cmd) { - case 1: // MoveTo - if (cmdRepeat !== 1) { - throw new Error(`repeat=${cmdRepeat} for command MoveTo`); - } - if (pos + 2 > len) { - throw new Error('Not enough elements for MoveTo arguments'); - } - if (line) { - lineStrings.push(line); - } - x += decodeCoordinate(ints[pos + 1]); - y += decodeCoordinate(ints[pos + 2]); - line = [[x * coordinatesScale, y * coordinatesScale]]; - pos += 3; - break; - case 2: // LineTo - if (cmdRepeat < 1) { - throw new Error(`repeat=${cmdRepeat} for command LineTo`); - } - if (!line) { - throw new Error('LineTo with empty linestring'); - } - pos += 1; - for (let cmdN = 0; cmdN < cmdRepeat; cmdN++) { - if (pos + 2 > len) { - throw new Error('Not enough elements for LineTo arguments'); - } - x += decodeCoordinate(ints[pos]); - y += decodeCoordinate(ints[pos + 1]); - line.push([x * coordinatesScale, y * coordinatesScale]); - pos += 2; - } - break; - case 7: // ClosePath - if (geometryType !== TileProto.GeomType.POLYGON) { - throw new Error(`ClosePath command for non-polygon type ${geometryType}`); - } - if (!line) { - throw new Error('ClosePath with empty linestring'); - } - if (cmdRepeat !== 1) { - throw new Error(`ClosePath repeats ${cmdRepeat} times`); - } - line.push(line[0]); - pos += 1; - break; - default: - throw new Error(`Unknown command ${i} & 0x7 = ${cmd}`); - } - } - if (line) { - lineStrings.push(line); - } - const geometry = {}; - switch (geometryType) { - case TileProto.GeomType.POINT: - if (lineStrings.length !== 1 || lineStrings[0].length !== 1) { - throw new Error('Invalid coordinates number for point'); - } - geometry.type = 'Point'; - geometry.coordinates = lineStrings[0][0]; - break; - case TileProto.GeomType.LINESTRING: - geometry.type = 'MultiLineString'; - geometry.coordinates = lineStrings; - break; - case TileProto.GeomType.POLYGON: - geometry.type = 'Polygon'; - geometry.coordinates = lineStrings; - break; - default: - } - return geometry; -} - -function parseFeatures(layer, coordinatesScale) { - const features = []; - for (let feature of layer.features) { - const geometry = parseGeometry(feature.type, feature.geometry, coordinatesScale); - features.push({geometry}); - } - return features; -} - -function decodeMvt(ar, tileExtent = 256) { - const - pbf = new Pbf(new Uint8Array(ar)), - tileData = TileProto.read(pbf); - const parsedLayers = []; - for (let layer of tileData.layers) { - let scale = tileExtent / layer.extent; - parsedLayers.push({ - name: layer.name, - features: parseFeatures(layer, scale) - }); - } - return parsedLayers; -} - -export {decodeMvt}; diff --git a/src/lib/leaflet.control.panoramas/lib/mapillary/vector_tile_pb.js b/src/lib/leaflet.control.panoramas/lib/mapillary/vector_tile_pb.js @@ -1,46 +0,0 @@ -// code generated by pbf v3.0.5 - -// Tile ======================================== - -var Tile = exports.Tile = {}; - -Tile.read = function (pbf, end) { - return pbf.readFields(Tile._readField, {layers: []}, end); -}; -Tile._readField = function (tag, obj, pbf) { - if (tag === 3) obj.layers.push(Tile.Layer.read(pbf, pbf.readVarint() + pbf.pos)); -}; - -Tile.GeomType = { - "UNKNOWN": 0, - "POINT": 1, - "LINESTRING": 2, - "POLYGON": 3 -}; - - -// Tile.Feature ======================================== - -Tile.Feature = {}; - -Tile.Feature.read = function (pbf, end) { - return pbf.readFields(Tile.Feature._readField, {id: 0, tags: [], type: 0, geometry: []}, end); -}; -Tile.Feature._readField = function (tag, obj, pbf) { - if (tag === 3) obj.type = pbf.readVarint(); - else if (tag === 4) pbf.readPackedVarint(obj.geometry); -}; - -// Tile.Layer ======================================== - -Tile.Layer = {}; - -Tile.Layer.read = function (pbf, end) { - return pbf.readFields(Tile.Layer._readField, {version: 0, name: "", features: [], keys: [], values: [], extent: 0}, end); -}; -Tile.Layer._readField = function (tag, obj, pbf) { - if (tag === 15) obj.version = pbf.readVarint(); - else if (tag === 1) obj.name = pbf.readString(); - else if (tag === 2) obj.features.push(Tile.Feature.read(pbf, pbf.readVarint() + pbf.pos)); - else if (tag === 5) obj.extent = pbf.readVarint(); -};