Skip to content

Instantly share code, notes, and snippets.

@yourcelf
Forked from pagameba/TileLayer.Bing.js
Created October 31, 2011 22:17

Revisions

  1. yourcelf revised this gist Oct 31, 2011. 1 changed file with 19 additions and 11 deletions.
    30 changes: 19 additions & 11 deletions TileLayer.Bing.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,11 @@
    var bounds_intersects = function(a, b) {
    return (
    a.contains(b._northEast) ||
    a.contains(b._southWest) ||
    b.contains(a._northEast) ||
    b.contains(a._southWest)
    );
    };
    L.TileLayer.Bing = L.TileLayer.extend({

    supportedTypes: ['Road', 'Aerial', 'AerialWithLabels'],
    @@ -65,12 +73,12 @@ L.TileLayer.Bing = L.TileLayer.extend({

    getTileUrl: function(xy, z) {
    var subdomains = this.options.subdomains,
    quadDigits = [],
    i = z,
    digit,
    mask,
    quadKey;
    // borrowed directly from OpenLayers
    quadDigits = [],
    i = z,
    digit,
    mask,
    quadKey;
    // borrowed directly from OpenLayers
    for (; i > 0; --i) {
    digit = '0';
    mask = 1 << (i - 1);
    @@ -84,9 +92,9 @@ L.TileLayer.Bing = L.TileLayer.extend({
    quadDigits.push(digit);
    }

    return this._url
    .replace('{subdomain}', subdomains[(xy.x + xy.y) % subdomains.length])
    .replace('{quadkey}', quadDigits.join(""));
    return this._url
    .replace('{subdomain}', subdomains[(xy.x + xy.y) % subdomains.length])
    .replace('{quadkey}', quadDigits.join(""));
    },

    _updateAttribution: function() {
    @@ -100,7 +108,7 @@ L.TileLayer.Bing = L.TileLayer.extend({
    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)) {
    if (zoom <= coverage.zoomMax && zoom >= coverage.zoomMin && bounds_intersects(coverage.bbox, bounds)) {
    copyrights += provider.attribution + " ";
    j = jj;
    }
    @@ -112,7 +120,7 @@ L.TileLayer.Bing = L.TileLayer.extend({
    .replace('{copyrights}', copyrights);
    this._map.attributionControl.addAttribution(this.attribution);
    }
    }
    }
    });

    L.TileLayer.Bing._callbackId = 0;
  2. @pagameba pagameba revised this gist Sep 16, 2011. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions TileLayer.Bing.js
    Original file line number Diff line number Diff line change
    @@ -100,9 +100,7 @@ L.TileLayer.Bing = L.TileLayer.extend({
    provider = providers[i];
    for (j=0,jj=provider.coverageAreas.length; j<jj; ++j) {
    coverage = provider.coverageAreas[j];
    console.log('coverage: ' + coverage.bbox.toBBoxString() + ', bounds: ' + bounds.toBBoxString());
    if (zoom <= coverage.zoomMax && zoom >= coverage.zoomMin && coverage.bbox.intersects(bounds)) {
    console.log('intersects! ' + provider.attribution);
    copyrights += provider.attribution + " ";
    j = jj;
    }
  3. @pagameba pagameba revised this gist Sep 16, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion TileLayer.Bing.js
    Original file line number Diff line number Diff line change
    @@ -101,7 +101,7 @@ L.TileLayer.Bing = L.TileLayer.extend({
    for (j=0,jj=provider.coverageAreas.length; j<jj; ++j) {
    coverage = provider.coverageAreas[j];
    console.log('coverage: ' + coverage.bbox.toBBoxString() + ', bounds: ' + bounds.toBBoxString());
    if (zoom <= coverage.zoomMax && zoom >= coverage.zoomMin && coverage.bbox.contains(bounds, true)) {
    if (zoom <= coverage.zoomMax && zoom >= coverage.zoomMin && coverage.bbox.intersects(bounds)) {
    console.log('intersects! ' + provider.attribution);
    copyrights += provider.attribution + " ";
    j = jj;
  4. @pagameba pagameba created this gist Sep 16, 2011.
    158 changes: 158 additions & 0 deletions TileLayer.Bing.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,158 @@
    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);

    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];
    console.log('coverage: ' + coverage.bbox.toBBoxString() + ', bounds: ' + bounds.toBBoxString());
    if (zoom <= coverage.zoomMax && zoom >= coverage.zoomMin && coverage.bbox.contains(bounds, true)) {
    console.log('intersects! ' + provider.attribution);
    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();
    }