nakarte

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

commit d115da4588ea508e428fde7e131be86038efc352
parent efc0fd78b3890549929699cc6eaf0f0b83ef3778
Author: Sergej Orlov <wladimirych@gmail.com>
Date:   Mon, 21 Jul 2025 14:55:22 +0200

Bing layers: get URL template from WEB API without using MS JS API

Diffstat:
Meslint_rules/legacy_files_list.js | 2--
Msrc/layers.js | 10+++++-----
Msrc/lib/leaflet.layer.bing/index.js | 159++++++++++++++++++++++++++-----------------------------------------------------
Msrc/lib/leaflet.layer.rasterize/Bing.js | 6+++---
Msrc/secrets.js.template | 1-
5 files changed, 60 insertions(+), 118 deletions(-)

diff --git a/eslint_rules/legacy_files_list.js b/eslint_rules/legacy_files_list.js @@ -129,8 +129,6 @@ module.exports = [ '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', 'src/lib/iconFromBackgroundImage/index.js', 'src/lib/leaflet.controls.raise-on-focus/index.js', diff --git a/src/layers.js b/src/layers.js @@ -1,7 +1,7 @@ import L from "leaflet"; import '~/lib/leaflet.layer.yandex'; import '~/lib/leaflet.layer.google'; -import {BingLayer} from '~/lib/leaflet.layer.bing'; +import {BingSatLayer, BingOrdnanceSurveyLayer} from '~/lib/leaflet.layer.bing'; import config from './config'; import '~/lib/leaflet.layer.soviet-topomaps-grid'; import '~/lib/leaflet.layer.westraPasses'; @@ -171,14 +171,15 @@ class LayerGroupWithOptions extends L.LayerGroup { { title: 'Bing Satellite', isDefault: true, - layer: new BingLayer(config.bingKey, + layer: new BingSatLayer( { code: 'I', isOverlay: false, scaleDependent: false, print: true, jnx: true, - shortName: 'bing_sat' + shortName: 'bing_sat', + attribution: '<a href="https://www.bing.com/maps?style=h">Microsoft</a>', } ) }, @@ -922,8 +923,7 @@ class LayerGroupWithOptions extends L.LayerGroup { isDefault: false, layer: new LayerGroupWithOptions( [ - new BingLayer(config.bingKey, { - type: 'OrdnanceSurvey', + new BingOrdnanceSurveyLayer({ minZoom: 12, maxNativeZoom: 16, bounds: [ diff --git a/src/lib/leaflet.layer.bing/index.js b/src/lib/leaflet.layer.bing/index.js @@ -1,10 +1,12 @@ import L from 'leaflet'; +import {fetch} from '~/lib/xhr-promise'; + function tile2quad(x, y, z) { - var quad = ''; - for (var i = z; i > 0; i--) { - var digit = 0; - var mask = 1 << (i - 1); + let quad = ''; + for (let i = z; i > 0; i--) { + let digit = 0; + const mask = 1 << (i - 1); if ((x & mask) !== 0) { digit += 1; } @@ -16,128 +18,71 @@ function tile2quad(x, y, z) { return quad; } -const BingLayer = L.TileLayer.extend({ - options: { - subdomains: [0, 1, 2, 3], - type: 'Aerial', - attribution: 'Bing', - culture: '' +const BingBaseLayer = L.TileLayer.extend({ + getTileUrl: function (tilePoint) { + const data = { + quadkey: tile2quad(tilePoint.x, tilePoint.y, this._getZoomForUrl()), + }; + return L.Util.template(this._url, L.extend(data, this.options)); }, +}); - initialize: function(key, options) { - L.Util.setOptions(this, options); - - this._key = key; - this._url = null; - this._providers = []; - this.metaRequested = false; +const BingBaseLayerWithDynamicUrl = BingBaseLayer.extend({ + initialize: function (options) { + BingBaseLayer.prototype.initialize.call(this, null, options); + this.layerInfoRequested = false; }, - getTileUrl: function(tilePoint) { - var zoom = this._getZoomForUrl(); - var subdomains = this.options.subdomains, - s = this.options.subdomains[Math.abs((tilePoint.x + tilePoint.y) % subdomains.length)]; - return this._url.replace('{subdomain}', s) - .replace('{quadkey}', tile2quad(tilePoint.x, tilePoint.y, zoom)) - .replace('{culture}', this.options.culture); + onAdd: function (map) { + this.loadLayerInfo(); + L.TileLayer.prototype.onAdd.apply(this, [map]); }, - loadMetadata: function() { - if (this.metaRequested) { + _update: function () { + if (this._url === null || !this._map) { return; } - this.metaRequested = true; - var that = this; - var cbid = '_bing_metadata_' + L.Util.stamp(this); - window[cbid] = function(meta) { - window[cbid] = undefined; - var e = document.getElementById(cbid); - e.parentNode.removeChild(e); - if (meta.errorDetails) { - throw new Error(meta.errorDetails); - } - that.initMetadata(meta); - }; - var urlScheme = 'https'; - var url = urlScheme + '://dev.virtualearth.net/REST/v1/Imagery/Metadata/' + - this.options.type + '?include=ImageryProviders&jsonp=' + cbid + - '&key=' + this._key + '&UriScheme=' + urlScheme; - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = url; - script.id = cbid; - document.getElementsByTagName('head')[0].appendChild(script); + L.TileLayer.prototype._update.apply(this); }, - initMetadata: function(meta) { - var r = meta.resourceSets[0].resources[0]; - this.options.subdomains = r.imageUrlSubdomains; - this._url = r.imageUrl; - if (r.imageryProviders) { - for (var i = 0; i < r.imageryProviders.length; i++) { - var p = r.imageryProviders[i]; - for (var j = 0; j < p.coverageAreas.length; j++) { - var c = p.coverageAreas[j]; - var coverage = {zoomMin: c.zoomMin, zoomMax: c.zoomMax, active: false}; - var bounds = new L.LatLngBounds( - new L.LatLng(c.bbox[0] + 0.01, c.bbox[1] + 0.01), - new L.LatLng(c.bbox[2] - 0.01, c.bbox[3] - 0.01) - ); - coverage.bounds = bounds; - coverage.attrib = p.attribution; - this._providers.push(coverage); - } - } - } - this._update(); + getLayerUrl: async function () { + throw new Error('Not implemented'); }, - _update: function() { - if (this._url === null || !this._map) { + loadLayerInfo: async function () { + if (this.layerInfoRequested) { return; } - this._update_attribution(); - L.TileLayer.prototype._update.apply(this, []); + this.layerInfoRequested = true; + this._url = await this.getLayerUrl(); + this._update(); }, +}); - _update_attribution: function() { - var bounds = L.latLngBounds( - this._map.getBounds().getSouthWest().wrap(), - this._map.getBounds().getNorthEast().wrap() - ); - var zoom = this._map.getZoom(); - for (var i = 0; i < this._providers.length; i++) { - var p = this._providers[i]; - if ((zoom <= p.zoomMax && zoom >= p.zoomMin) && - bounds.intersects(p.bounds)) { - if (!p.active && this._map.attributionControl) { - this._map.attributionControl.addAttribution(p.attrib); - } - p.active = true; - } else { - if (p.active && this._map.attributionControl) { - this._map.attributionControl.removeAttribution(p.attrib); - } - p.active = false; - } - } +const BingSatLayer = BingBaseLayerWithDynamicUrl.extend({ + getLayerUrl: async function () { + const xhr = await fetch('https://www.bing.com/maps/style?styleid=aerial', { + responseType: 'json', + timeout: 5000, + }); + return xhr.response['sources']['bing-aerial']['tiles'][0].replace(/^raster/u, 'https'); }, +}); - onAdd: function(map) { - this.loadMetadata(); - L.TileLayer.prototype.onAdd.apply(this, [map]); +const BingOrdnanceSurveyLayer = BingBaseLayerWithDynamicUrl.extend({ + options: { + credentials: 'Auy875gcaw3RCFzVQSxi8Ytzw_K67r4Dw8DpGHavRZW_ciCBHLhQJAhCiXSdnzwH', }, - onRemove: function(map) { - for (var i = 0; i < this._providers.length; i++) { - var p = this._providers[i]; - if (p.active && this._map.attributionControl) { - this._map.attributionControl.removeAttribution(p.attrib); - p.active = false; - } - } - L.TileLayer.prototype.onRemove.apply(this, [map]); - } + getLayerUrl: async function () { + const xhr = await fetch('https://www.bing.com/maps/style?styleid=ordnancesurvey', { + responseType: 'json', + headers: [['accept-language', 'en-GB']], + timeout: 5000, + }); + return xhr.response['sources']['osMaps1']['tiles'][0].replace(/^raster/u, 'https'); + }, }); -export {BingLayer}; +// eslint-disable-next-line import/no-unused-modules +export {BingSatLayer, BingOrdnanceSurveyLayer, BingBaseLayerWithDynamicUrl}; diff --git a/src/lib/leaflet.layer.rasterize/Bing.js b/src/lib/leaflet.layer.rasterize/Bing.js @@ -1,7 +1,7 @@ import L from 'leaflet'; -import {BingLayer} from '~/lib/leaflet.layer.bing'; +import {BingBaseLayerWithDynamicUrl} from '~/lib/leaflet.layer.bing'; -BingLayer.include({ +BingBaseLayerWithDynamicUrl.include({ waitTilesReadyToGrab: function() { if (this._url) { return Promise.resolve(); @@ -19,7 +19,7 @@ BingLayer.include({ }, cloneForPrint: function(options) { - return new BingLayer(this._key, L.Util.extend({}, this.options, options)); + return new this.constructor(L.Util.extend({}, this.options, options)); }, } ); diff --git a/src/secrets.js.template b/src/secrets.js.template @@ -1,5 +1,4 @@ const secrets = { - bingKey: '0000000000000000000000000000000000000000000000000000000000000000', sentryDSN: 'https://00000000000000000000000000000000@sentry.io/111111', mapillary4: 'MLY|1111111111111111|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', google: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX',