public
Last active

  • Download Gist
TileLayer.Bing.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
/*
* Portions of this code and logic copied from OpenLayers and
* redistributed under the original Clear BSD license terms:
*
* http://trac.osgeo.org/openlayers/browser/license.txt
*
* Copyright 2005-2010 OpenLayers Contributors, released under
* the Clear BSD license. See authors.txt for a list of contributors.
* All rights reserved.
*
* --
*
* Leaflet-specific modifications are released under the following
* terms:
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
 
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++);
var 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._map.attributionControl._attributions = {};
this._map.attributionControl._update();
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();
}

Hello! I'm trying to get this to work but Bing is giving me '400 Bad Request' responses. Is there someplace with a working example of this I could look at? Thanks!

Hi, sorry I don't have a working example any more, I deleted it somewhere along the way. I will be coming back to this experiment in a few weeks as I will have need of it again, until then I don't have time to debug problems. I expect the issue is that Bing has changed something in their API and this code would need to be updated to accommodate the changes. This code was adapted from OpenLayers Bing support, I notice the OpenLayers Bing example is still working so perhaps you could start there if you need to get it working sooner .. http://openlayers.org/dev/examples/bing-tiles.html

Cheers

Paul

I had some trouble with the processMetadata function. It looks to me like Leaflet commit e5f934e changed L.Utils.bind in such a way as to break your callback. A clumsy adjustment to your _loadMetadata routine fixed it for me:

//window[this._callbackId] = L.Util.bind(L.TileLayer.Bing.processMetadata, this);
that = this;
window[this._callbackId] = function() { L.TileLayer.Bing.processMetadata.apply(that, arguments); };

I forked your Gist with my changes

Thanks,
Ryan

Cool, thanks. I'm hoping to pick this up on Monday and make sure it wires with the latest versions of everything.

Sent from my iPhone

On 2012-03-11, at 12:57 PM, Ryan Clark reply@reply.github.com wrote:

I had some trouble with the processMetadata function. It looks to me like Leaflet commit e5f934e changed L.Utils.bind in such a way as to break your callback. A clumsy adjustment to your _loadMetadata routine fixed it for me:

   //window[this._callbackId] = L.Util.bind(L.TileLayer.Bing.processMetadata, this);
   that = this;
   window[this._callbackId] = function() { L.TileLayer.Bing.processMetadata.apply(that, arguments); };

I forked your Gist with my changes

Thanks,
Ryan


Reply to this email directly or view it on GitHub:
https://gist.github.com/1221998

:) sorry, its been a busy week. Does Ryan's fork linked above work for you? I haven't tried it yet.

Let me go try that out.

Thanks a lot for writing it and putting it out for us to use in the
first place! :D

On Wed, Mar 14, 2012 at 7:40 AM, Paul Spencer
reply@reply.github.com
wrote:

:) sorry, its been a busy week.  Does Ryan's fork linked above work for you?  I haven't tried it yet.


Reply to this email directly or view it on GitHub:
https://gist.github.com/1221998

Yuvi Panda T
http://yuvi.in/blog

Yes, Ryan's changes worked. Thanks! :D

It'll also be nice if you could explicitly state what license this code is under...

Great point. I've updated this Gist with Ryan's changes (untested) and appropriate license and copyright details.

Cheers

Paul

There are still problems, I think, if you want to have more than one Bing layer in your app.

Issue with multiple Bing Layers and attributions being added multiple times:

Replace


with
```this._map.attributionControl.removeAttribution(this.attribution);
    this._map.attributionControl._attributions = {};
    this._map.attributionControl._update();```

Forked here:
https://gist.github.com/2342958

updated gist with ccgdesigns contribution.

When I try to overlay a custom tilelayer over the bing layer, the bing one always supersedes. As in, I want the custom layer to be on top. The custom layer falls under the aerial imagery, so i don't see it at all!

This code has been incorporated into https://github.com/shramov/leaflet-plugins, I suggest following up there.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.