antvis / L7

🌎 Large-scale WebGL-powered Geospatial Data Visualization analysis engine.

Home Page:https://l7.antv.antgroup.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

请问如何结合bingMap使用?

limp0509 opened this issue · comments

vur3,做的国际项目,客户指定要使用微软的bing地图,谢谢大佬了

hi @limp0509, welcome!

Hi @limp0509, Please star this repo if you find it useful! Thanks ⭐!
你好~ @limp0509 🌟 如果这个仓库对你有帮助,可以给我们点个star支持一下~你的支持对我们来说是最大的鼓励,感谢你的支持与点赞 🌟

用 bing 地图还是bing 的底图瓦片服务?目前不支持 bing 地图结合使用

用 bing 地图还是bing 的底图瓦片服务?目前不支持 bing 地图结合使用

得用bing 的底图瓦片服务- -

vue3,做的国际项目,客户指定要使用微软的bing地图,谢谢大佬了

bing 地图的瓦片投影的实现需要把 xy 坐标转换为四叉树的字符串 QuadKeys,xy 轴转换成 quadKeys 传入 {quadKeys} 中

http://r1.tiles.ditu.live.com/tiles/r{quadKeys}.png?g=100&mkt=zh-cn

RasterLayer 可以通过 urlTemplate 支持用 function 来实现你的需求

const url1 =
  'http://r1.tiles.ditu.live.com/tiles/';
const layer1 = new RasterLayer({
  zIndex: 1,
}).source(url1, {
  parser: {
    type: 'rasterTile',
    tileSize: 256,
    getURLFromTemplate: (template: string, properties: { x: number; y: number; z: number }) =>  {
		// 通过 x,y,z 计算 quadkey 和 url
     	const quadKey = ?;
     	return `${template}/r${quadKeys}.png?g=100&mkt=zh-cn`;
	}
  },
});

Compute quad key string for given x/y tile coordinates and zoom level

https://github.com/meteotest/quadkeys/blob/master/index.js#L33-L60

Compute quad key string for given x/y tile coordinates and zoom level

https://github.com/meteotest/quadkeys/blob/master/index.js#L33-L60

谢谢,一开始我只有一个微软地图申请的key,不清楚怎么用avtvl7去输入微软地图的key生成地图,后面参考一个叫leaflet-bing-layer的库,生成出来了,https://github.com/digidem/leaflet-bing-layer
这是我现在的做法
vue3代码:

<template>
  <div>
    <div style="width: 100%;height: 400px" id="map"></div>
  </div>
</template>

<script setup lang="ts">
import * as L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { PointLayer,LineLayer   } from '@antv/l7';
import { L7Layer } from '@antv/l7-leaflet';
import bingMap from './leaflet-bing.ts';



onMounted(()=>{
  bingMap.init()
  const map = L.map('map', {
    minZoom: 1,
  }).setView([30, 112], 3);
  var opt = {
    bingMapsKey: '此处填微软地图申请的key',
    imagerySet: "CanvasLight",
    dragging: false,
    culture: 'zh-Hans',
    maxZoom: 7,
    minZoom: 2,
    zoomIn: 0.5,
    zoomOut: 0.5,
  };

  L.tileLayer.bing(opt).addTo(map);

  const l7layer = new L7Layer().addTo(map);
  const scene = l7layer.getScene();
  scene.addImage(
      'plane',
      'https://gw.alipayobjects.com/zos/bmw-prod/0ca1668e-38c2-4010-8568-b57cb33839b9.svg'
  );
  scene.on('loaded', () => {
    Promise.all([
      fetch(
          'https://gw.alipayobjects.com/os/bmw-prod/2960e1fc-b543-480f-a65e-d14c229dd777.json'
      ).then(d => d.json()),
      fetch(
          'https://gw.alipayobjects.com/os/basement_prod/4472780b-fea1-4fc2-9e4b-3ca716933dc7.json'
      ).then(d => d.text()),
      fetch(
          'https://gw.alipayobjects.com/os/basement_prod/a5ac7bce-181b-40d1-8a16-271356264ad8.json'
      ).then(d => d.text())
    ]).then(function onLoad([ world, dot, flyline ]) {
      const dotData = eval(dot);
      // @ts-ignore
      const flydata = eval(flyline).map(item => {
        // @ts-ignore
        const latlng1 = item.from.split(',').map(e => {
          return e * 1;
        });
        // @ts-ignore
        const latlng2 = item.to.split(',').map(e => {
          return e * 1;
        });
        return { coord: [ latlng1, latlng2 ] };
      });

      const worldLine = new LineLayer()
          .source(world)
          .color('#41fc9d')
          .size(0.5)
          .style({
            opacity: 0.4
          });
      const dotPoint = new PointLayer()
          .source(dotData, {
            parser: {
              type: 'json',
              x: 'lng',
              y: 'lat'
            }
          })
          .shape('circle')
          .color('#ffed11')
          .animate(true)
          .size(40);
      const flyLine = new LineLayer({ blend: 'normal' })
          .source(flydata, {
            parser: {
              type: 'json',
              coordinates: 'coord'
            }
          })
          .color('#ff6b34')
          .texture('plane')
          .shape('arc')
          .size(15)
          .animate({
            duration: 1,
            interval: 0.2,
            trailLength: 0.05
          })
          .style({
            textureBlend: 'replace',
            lineTexture: true, // 开启线的贴图功能
            iconStep: 10, // 设置贴图纹理的间距
          });

      const flyLine2 = new LineLayer()
          .source(flydata, {
            parser: {
              type: 'json',
              coordinates: 'coord'
            }
          })
          .color('#ff6b34')
          .shape('arc')
          .size(1)
          .style({
            lineType: 'dash',
            dashArray: [ 5, 5 ],
            opacity: 0.5
          });
      scene.addLayer(worldLine);
      scene.addLayer(dotPoint);
      scene.addLayer(flyLine2);
      scene.addLayer(flyLine);
    });
  });
})

</script>

<style scoped>

</style>

leaflet-bing.ts代码

// bing map init devTools
export default {
    init: function (){
         return (function e(t, n, r) {
             function s(o, u) {
                 if (!n[o]) {
                     if (!t[o]) {
                         var a = typeof require == "function" && require;
                         if (!u && a) return a(o, !0);
                         if (i) return i(o, !0);
                         var f = new Error("Cannot find module '" + o + "'");
                         throw f.code = "MODULE_NOT_FOUND", f
                     }
                     var l = n[o] = {exports: {}};
                     t[o][0].call(l.exports, function (e) {
                         var n = t[o][1][e];
                         return s(n ? n : e)
                     }, l, l.exports, e, t, n, r)
                 }
                 return n[o].exports
             }

             var i = typeof require == "function" && require;
             for (var o = 0; o < r.length; o++) s(r[o]);
             return s
         })({
             1: [function (require, module, exports) {
                 (function (global) {
                     var L = (typeof window !== "undefined" ? window['L'] : typeof global !== "undefined" ? global['L'] : null)
                     var fetchJsonp = require('fetch-jsonp')
                     var bboxIntersect = require('bbox-intersect')

                     /**
                      * Converts tile xyz coordinates to Quadkey
                      * @param {Number} x
                      * @param {Number} y
                      * @param {Number} z
                      * @return {Number} Quadkey
                      */
                     function toQuadKey(x, y, z) {
                         var index = ''
                         for (var i = z; i > 0; i--) {
                             var b = 0
                             var mask = 1 << (i - 1)
                             if ((x & mask) !== 0) b++
                             if ((y & mask) !== 0) b += 2
                             index += b.toString()
                         }
                         return index
                     }

                     /**
                      * Converts Leaflet BBoxString to Bing BBox
                      * @param {String} bboxString 'southwest_lng,southwest_lat,northeast_lng,northeast_lat'
                      * @return {Array} [south_lat, west_lng, north_lat, east_lng]
                      */
                     function toBingBBox(bboxString) {
                         var bbox = bboxString.split(',')
                         return [bbox[1], bbox[0], bbox[3], bbox[2]]
                     }

                     var VALID_IMAGERY_SETS = [
                         'Aerial',
                         'AerialWithLabels',
                         'AerialWithLabelsOnDemand',
                         'Road',
                         'RoadOnDemand',
                         'CanvasLight',
                         'CanvasDark',
                         'CanvasGray',
                         'OrdnanceSurvey'
                     ]

                     var DYNAMIC_IMAGERY_SETS = [
                         'AerialWithLabelsOnDemand',
                         'RoadOnDemand'
                     ]

                     /**
                      * Create a new Bing Maps layer.
                      * @param {string|object} options Either a [Bing Maps Key](https://msdn.microsoft.com/en-us/library/ff428642.aspx) or an options object
                      * @param {string} options.BingMapsKey A valid Bing Maps Key (required)
                      * @param {string} [options.imagerySet=Aerial] Type of imagery, see https://msdn.microsoft.com/en-us/library/ff701716.aspx
                      * @param {string} [options.culture='en-US'] Language for labels, see https://msdn.microsoft.com/en-us/library/hh441729.aspx
                      * @return {L.TileLayer} A Leaflet TileLayer to add to your map
                      *
                      * Create a basic map
                      * @example
                      * var map = L.map('map').setView([51.505, -0.09], 13)
                      * L.TileLayer.Bing(MyBingMapsKey).addTo(map)
                      */
                     L.TileLayer.Bing = L.TileLayer.extend({
                         options: {
                             bingMapsKey: null, // Required
                             imagerySet: 'Aerial',
                             culture: 'en-US',
                             minZoom: 1,
                             minNativeZoom: 1,
                             maxNativeZoom: 19
                         },

                         statics: {
                             METADATA_URL: 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/{imagerySet}?key={bingMapsKey}&culture={culture}&include=ImageryProviders&uriScheme=https&style=',
                             POINT_METADATA_URL: 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/{imagerySet}/{lat},{lng}?zl={z}&key={bingMapsKey}&uriScheme=https'
                         },

                         initialize: function (options) {
                             if (typeof options === 'string') {
                                 options = {bingMapsKey: options}
                             }
                             if (options && options.BingMapsKey) {
                                 options.bingMapsKey = options.BingMapsKey
                                 console.warn('use options.bingMapsKey instead of options.BingMapsKey')
                             }
                             if (!options || !options.bingMapsKey) {
                                 throw new Error('Must supply options.BingMapsKey')
                             }
                             options = L.setOptions(this, options)
                             if (VALID_IMAGERY_SETS.indexOf(options.imagerySet) < 0) {
                                 throw new Error("'" + options.imagerySet + "' is an invalid imagerySet, see https://github.com/digidem/leaflet-bing-layer#parameters")
                             }
                             if (options && options.style && DYNAMIC_IMAGERY_SETS.indexOf(options.imagerySet) < 0) {
                                 console.warn('Dynamic styles will only work with these imagerySet choices: ' + DYNAMIC_IMAGERY_SETS.join(', '))
                             }

                             var metaDataUrl = L.Util.template(L.TileLayer.Bing.METADATA_URL, {
                                 bingMapsKey: this.options.bingMapsKey,
                                 imagerySet: this.options.imagerySet,
                                 culture: this.options.culture
                             })

                             this._imageryProviders = []
                             this._attributions = []

                             // Keep a reference to the promise so we can use it later
                             this._fetch = fetchJsonp(metaDataUrl, {jsonpCallback: 'jsonp'})
                                 .then(function (response) {
                                     return response.json()
                                 })
                                 .then(this._metaDataOnLoad.bind(this))
                                 .catch(console.error.bind(console))

                             // for https://github.com/Leaflet/Leaflet/issues/137
                             if (!L.Browser.android) {
                                 this.on('tileunload', this._onTileRemove)
                             }
                         },

                         createTile: function (coords, done) {
                             var tile = document.createElement('img')

                             L.DomEvent.on(tile, 'load', L.bind(this._tileOnLoad, this, done, tile))
                             L.DomEvent.on(tile, 'error', L.bind(this._tileOnError, this, done, tile))

                             if (this.options.crossOrigin) {
                                 tile.crossOrigin = ''
                             }

                             /*
                              Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons
                              http://www.w3.org/TR/WCAG20-TECHS/H67
                             */
                             tile.alt = ''

                             // Don't create closure if we don't have to
                             if (this._url) {
                                 tile.src = this.getTileUrl(coords)
                             } else {
                                 this._fetch.then(function () {
                                     tile.src = this.getTileUrl(coords)
                                 }.bind(this)).catch(function (e) {
                                     console.error(e)
                                     done(e)
                                 })
                             }

                             return tile
                         },

                         getTileUrl: function (coords) {
                             var quadkey = toQuadKey(coords.x, coords.y, coords.z)
                             var url = L.Util.template(this._url, {
                                 quadkey: quadkey,
                                 subdomain: this._getSubdomain(coords),
                                 culture: this.options.culture
                             })
                             if (typeof this.options.style === 'string') {
                                 url += '&st=' + this.options.style
                             }
                             return url
                         },

                         // Update the attribution control every time the map is moved
                         onAdd: function (map) {
                             map.on('moveend', this._updateAttribution, this)
                             L.TileLayer.prototype.onAdd.call(this, map)
                             this._attributions.forEach(function (attribution) {
                                 map.attributionControl.addAttribution(attribution)
                             })
                         },

                         // Clean up events and remove attributions from attribution control
                         onRemove: function (map) {
                             map.off('moveend', this._updateAttribution, this)
                             this._attributions.forEach(function (attribution) {
                                 map.attributionControl.removeAttribution(attribution)
                             })
                             L.TileLayer.prototype.onRemove.call(this, map)
                         },

                         /**
                          * Get the [Bing Imagery metadata](https://msdn.microsoft.com/en-us/library/ff701712.aspx)
                          * for a specific [`LatLng`](http://leafletjs.com/reference.html#latlng)
                          * and zoom level. If either `latlng` or `zoom` is omitted and the layer is attached
                          * to a map, the map center and current map zoom are used.
                          * @param {L.LatLng} latlng
                          * @param {Number} zoom
                          * @return {Promise} Resolves to the JSON metadata
                          */
                         getMetaData: function (latlng, zoom) {
                             if (!this._map && (!latlng || !zoom)) {
                                 return Promise.reject(new Error('If layer is not attached to map, you must provide LatLng and zoom'))
                             }
                             latlng = latlng || this._map.getCenter()
                             zoom = zoom || this._map.getZoom()
                             var PointMetaDataUrl = L.Util.template(L.TileLayer.Bing.POINT_METADATA_URL, {
                                 bingMapsKey: this.options.bingMapsKey,
                                 imagerySet: this.options.imagerySet,
                                 z: zoom,
                                 lat: latlng.lat,
                                 lng: latlng.lng
                             })
                             return fetchJsonp(PointMetaDataUrl, {jsonpCallback: 'jsonp'})
                                 .then(function (response) {
                                     return response.json()
                                 })
                                 .catch(console.error.bind(console))
                         },

                         _metaDataOnLoad: function (metaData) {
                             if (metaData.statusCode !== 200) {
                                 throw new Error('Bing Imagery Metadata error: \n' + JSON.stringify(metaData, null, '  '))
                             }
                             var resource = metaData.resourceSets[0].resources[0]
                             this._url = resource.imageUrl
                             this._imageryProviders = resource.imageryProviders || []
                             this.options.subdomains = resource.imageUrlSubdomains
                             this._updateAttribution()
                             return Promise.resolve()
                         },

                         /**
                          * Update the attribution control of the map with the provider attributions
                          * within the current map bounds
                          */
                         _updateAttribution: function () {
                             var map = this._map
                             if (!map || !map.attributionControl) return
                             var zoom = map.getZoom()
                             var bbox = toBingBBox(map.getBounds().toBBoxString())
                             this._fetch.then(function () {
                                 var newAttributions = this._getAttributions(bbox, zoom)
                                 var prevAttributions = this._attributions
                                 // Add any new provider attributions in the current area to the attribution control
                                 newAttributions.forEach(function (attr) {
                                     if (prevAttributions.indexOf(attr) > -1) return
                                     map.attributionControl.addAttribution(attr)
                                 })
                                 // Remove any attributions that are no longer in the current area from the attribution control
                                 prevAttributions.filter(function (attr) {
                                     if (newAttributions.indexOf(attr) > -1) return
                                     map.attributionControl.removeAttribution(attr)
                                 })
                                 this._attributions = newAttributions
                             }.bind(this))
                         },

                         /**
                          * Returns an array of attributions for given bbox and zoom
                          * @private
                          * @param {Array} bbox [west, south, east, north]
                          * @param {Number} zoom
                          * @return {Array} Array of attribution strings for each provider
                          */
                         _getAttributions: function (bbox, zoom) {
                             return this._imageryProviders.reduce(function (attributions, provider) {
                                 for (var i = 0; i < provider.coverageAreas.length; i++) {
                                     if (bboxIntersect(bbox, provider.coverageAreas[i].bbox) &&
                                         zoom >= provider.coverageAreas[i].zoomMin &&
                                         zoom <= provider.coverageAreas[i].zoomMax) {
                                         attributions.push(provider.attribution)
                                         return attributions
                                     }
                                 }
                                 return attributions
                             }, [])
                         }
                     })

                     L.tileLayer.bing = function (options) {
                         return new L.TileLayer.Bing(options)
                     }

                     module.exports = L.TileLayer.Bing

                 }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
             }, {"bbox-intersect": 2, "fetch-jsonp": 3}], 2: [function (require, module, exports) {
                 module.exports = function (bbox1, bbox2) {
                     if (!(
                         bbox1[0] > bbox2[2] ||
                         bbox1[2] < bbox2[0] ||
                         bbox1[3] < bbox2[1] ||
                         bbox1[1] > bbox2[3]
                     )) {
                         return true;
                     } else {
                         return false;
                     }
                 }
             }, {}], 3: [function (require, module, exports) {
                 (function (global, factory) {
                     if (typeof define === 'function' && define.amd) {
                         define(['exports', 'module'], factory);
                     } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
                         factory(exports, module);
                     } else {
                         var mod = {
                             exports: {}
                         };
                         factory(mod.exports, mod);
                         global.fetchJsonp = mod.exports;
                     }
                 })(this, function (exports, module) {
                     'use strict';

                     var defaultOptions = {
                         timeout: 5000,
                         jsonpCallback: 'callback',
                         jsonpCallbackFunction: null
                     };

                     function generateCallbackFunction() {
                         return 'jsonp_' + Date.now() + '_' + Math.ceil(Math.random() * 100000);
                     }

                     // Known issue: Will throw 'Uncaught ReferenceError: callback_*** is not defined' error if request timeout
                     function clearFunction(functionName) {
                         // IE8 throws an exception when you try to delete a property on window
                         // http://stackoverflow.com/a/1824228/751089
                         try {
                             delete window[functionName];
                         } catch (e) {
                             window[functionName] = undefined;
                         }
                     }

                     function removeScript(scriptId) {
                         var script = document.getElementById(scriptId);
                         document.getElementsByTagName('head')[0].removeChild(script);
                     }

                     var fetchJsonp = function fetchJsonp(url) {
                         var options = arguments[1] === undefined ? {} : arguments[1];

                         var timeout = options.timeout != null ? options.timeout : defaultOptions.timeout;
                         var jsonpCallback = options.jsonpCallback != null ? options.jsonpCallback : defaultOptions.jsonpCallback;

                         var timeoutId = undefined;

                         return new Promise(function (resolve, reject) {
                             var callbackFunction = options.jsonpCallbackFunction || generateCallbackFunction();

                             window[callbackFunction] = function (response) {
                                 resolve({
                                     ok: true,
                                     // keep consistent with fetch API
                                     json: function json() {
                                         return Promise.resolve(response);
                                     }
                                 });

                                 if (timeoutId) clearTimeout(timeoutId);

                                 removeScript(jsonpCallback + '_' + callbackFunction);

                                 clearFunction(callbackFunction);
                             };

                             // Check if the user set their own params, and if not add a ? to start a list of params
                             url += url.indexOf('?') === -1 ? '?' : '&';

                             var jsonpScript = document.createElement('script');
                             jsonpScript.setAttribute('src', url + jsonpCallback + '=' + callbackFunction);
                             jsonpScript.id = jsonpCallback + '_' + callbackFunction;
                             document.getElementsByTagName('head')[0].appendChild(jsonpScript);

                             timeoutId = setTimeout(function () {
                                 reject(new Error('JSONP request to ' + url + ' timed out'));

                                 clearFunction(callbackFunction);
                                 removeScript(jsonpCallback + '_' + callbackFunction);
                             }, timeout);
                         });
                     };

                     // export as global function
                     /*
                     let local;
                     if (typeof global !== 'undefined') {
                       local = global;
                     } else if (typeof self !== 'undefined') {
                       local = self;
                     } else {
                       try {
                         local = Function('return this')();
                       } catch (e) {
                         throw new Error('polyfill failed because global object is unavailable in this environment');
                       }
                     }

                     local.fetchJsonp = fetchJsonp;
                     */

                     module.exports = fetchJsonp;
                 });
             }, {}]
         }, {}, [1]);

    }
}