Skip to content

Instantly share code, notes, and snippets.

@rclark
Forked from pagameba/TileLayer.Bing.js
Created March 11, 2012 16:50
Show Gist options
  • Save rclark/2017109 to your computer and use it in GitHub Desktop.
Save rclark/2017109 to your computer and use it in GitHub Desktop.
Leaflet Bing layer
L.TileLayer.Bing = L.TileLayer.extend({
supportedTypes: ['Road', 'Aerial', 'AerialWithLabels'],
attributionTemplate: '<span style="display:inline-block">' +
'<a target="_blank" href="http://www.bing.com/maps/">' +
'<img src="{logo}" /></a><br><span>{copyrights}' +
'<a style="white-space: nowrap" target="_blank" '+
'href="http://www.microsoft.com/maps/product/terms.html">' +
'Terms of Use</a></span></span>',
initialize: function(/*String*/ apiKey, /*String*/ mapType, /*Object*/ options) {
this._apiKey = apiKey;
this._mapType = mapType;
this._loadMetadata();
L.Util.setOptions(this, options);
},
_loadMetadata: function() {
this._callbackId = "_l_tilelayer_bing_" + (L.TileLayer.Bing._callbackId++);
//window[this._callbackId] = L.Util.bind(L.TileLayer.Bing.processMetadata, this);
that = this;
window[this._callbackId] = function() { L.TileLayer.Bing.processMetadata.apply(that, arguments); }
var params = {
key: this._apiKey,
jsonp: this._callbackId,
include: 'ImageryProviders'
},
url = "http://dev.virtualearth.net/REST/v1/Imagery/Metadata/" +
this._mapType + L.Util.getParamString(params),
script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
script.id = this._callbackId;
document.getElementsByTagName("head")[0].appendChild(script);
},
_onMetadataLoaded: function() {},
onAdd: function(map, insertAtTheBottom) {
if (!this.metadata) {
this._onMetadataLoaded = L.Util.bind(function() {
L.TileLayer.prototype.onAdd.call(this, map, insertAtTheBottom);
map.on('moveend', this._updateAttribution, this);
this._updateAttribution();
}, this);
} else {
L.TileLayer.prototype.onAdd.call(this, map, insertAtTheBottom);
map.on('moveend', this._updateAttribution, this);
this._updateAttribution();
}
},
onRemove: function(map) {
if (this._map.attributionControl) {
this._map.attributionControl.removeAttribution(this.attribution);
}
this._map.off('moveend', this._updateAttribution, this);
L.TileLayer.prototype.onRemove.call(this, map);
},
getTileUrl: function(xy, z) {
var subdomains = this.options.subdomains,
quadDigits = [],
i = z,
digit,
mask,
quadKey;
// borrowed directly from OpenLayers
for (; i > 0; --i) {
digit = '0';
mask = 1 << (i - 1);
if ((xy.x & mask) != 0) {
digit++;
}
if ((xy.y & mask) != 0) {
digit++;
digit++;
}
quadDigits.push(digit);
}
return this._url
.replace('{subdomain}', subdomains[(xy.x + xy.y) % subdomains.length])
.replace('{quadkey}', quadDigits.join(""));
},
_updateAttribution: function() {
if (this._map.attributionControl) {
var metadata = this.metadata;
var res = metadata.resourceSets[0].resources[0];
var bounds = this._map.getBounds();
var providers = res.imageryProviders, zoom = this._map.getZoom() + 1,
copyrights = "", provider, i, ii, j, jj, bbox, coverage;
for (i=0,ii=providers.length; i<ii; ++i) {
provider = providers[i];
for (j=0,jj=provider.coverageAreas.length; j<jj; ++j) {
coverage = provider.coverageAreas[j];
if (zoom <= coverage.zoomMax && zoom >= coverage.zoomMin && coverage.bbox.intersects(bounds)) {
copyrights += provider.attribution + " ";
j = jj;
}
}
}
this._map.attributionControl.removeAttribution(this.attribution);
this.attribution = this.attributionTemplate
.replace('{logo}', metadata.brandLogoUri)
.replace('{copyrights}', copyrights);
this._map.attributionControl.addAttribution(this.attribution);
}
}
});
L.TileLayer.Bing._callbackId = 0;
L.TileLayer.Bing.processMetadata = function(metadata) {
if (metadata.authenticationResultCode != 'ValidCredentials') {
throw "Invalid Bing Maps API Key"
}
if (!metadata.resourceSets.length || !metadata.resourceSets[0].resources.length) {
throw "No resources returned, perhaps " + this._mapType + " is an invalid map type?";
}
if (metadata.statusCode != 200) {
throw "Bing Maps API request failed with status code " + metadata.statusCode;
}
this.metadata = metadata;
var res = metadata.resourceSets[0].resources[0],
providers = res.imageryProviders,
i = 0,
j,
provider,
bbox,
script = document.getElementById(this._callbackId);
for (; i<providers.length; i++) {
provider = providers[i];
for (j=0; j<provider.coverageAreas.length; j++) {
bbox = provider.coverageAreas[j].bbox;
provider.coverageAreas[j].bbox = new L.LatLngBounds(new L.LatLng(bbox[0],bbox[1],true),new L.LatLng(bbox[2],bbox[3], true));
}
}
this._url = res.imageUrl.replace('{culture}','en-US');
this.options.subdomains = [].concat(res.imageUrlSubdomains);
script.parentNode.removeChild(script);
window[this._callbackId] = undefined; // cannot delete from window in IE
delete this._callbackId;
this._onMetadataLoaded();
}
@mattit
Copy link

mattit commented Jul 3, 2014

I know this thread has been closed for awhile, but I wanted to let you guys know that I've modified the Bing.js file to allow for multiple options for the map types. This also allows the API code to be put into the .js file and out of the main display file, while simplifying the front-end coding.

/* add your API code to the top _/
var key= 'your_API_code';
L.BingLayer = L.TileLayer.extend({
options: {
subdomains: [0, 1, 2, 3],
/_type: 'Road', / /<================== Comment out or remove the type option */
attribution: 'Bing',
culture: ''
},

initialize: function(/key,/ mtype, options) { /_<=== Comment out or remove the key option
and add the type as an option */
L.Util.setOptions(this, options);
this._key = key;
this.type = mtype; /<================== Add the type option to the function call */
this._url = null;
this.meta = {};
this.loadMetadata();
},

.
.
.

/* Change the this.options.type to _this.type in the url definition */
var url = document.location.protocol + '//dev.virtualearth.net/REST/v1/Imagery/Metadata/' + this._type + ...


In your display page you can now simply your code and add display options without having to triple the number of JS files.

var map = new L.Map('map', {center: new L.LatLng(67.6755, 33.936), zoom: 10 });
var bingr = new L.BingLayer("Road");
var binga = new L.BingLayer("Aerial");
var bingl = new L.BingLayer("AerialWithLabels");
map.addLayer(bingl);
map.addLayer(binga);
map.addLayer(bingr);
map.addControl(new L.Control.Layers({'Road':bingr, "Aerial":binga, "Hybrid":bingl}, {}));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment