Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请问如何结合bingMap使用? #2417

Closed
limp0509 opened this issue Apr 19, 2024 · 9 comments
Closed

请问如何结合bingMap使用? #2417

limp0509 opened this issue Apr 19, 2024 · 9 comments
Assignees
Labels
question 疑问/使用问题

Comments

@limp0509
Copy link

limp0509 commented Apr 19, 2024

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

Copy link
Contributor

hi @limp0509, welcome!

Copy link
Contributor

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

@lvisei
Copy link
Member

lvisei commented Apr 19, 2024

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

@limp0509
Copy link
Author

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

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

@limp0509
Copy link
Author

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

@lvisei
Copy link
Member

lvisei commented Apr 19, 2024

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`;
	}
  },
});

@lvisei
Copy link
Member

lvisei commented Apr 19, 2024

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

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

@lvisei lvisei added the question 疑问/使用问题 label Apr 19, 2024
@limp0509
Copy link
Author

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

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

@limp0509
Copy link
Author

limp0509 commented Apr 22, 2024

谢谢,一开始我只有一个微软地图申请的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]);

    }
}



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question 疑问/使用问题
Projects
None yet
Development

No branches or pull requests

4 participants