diff options
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Layer/Bing.js')
-rw-r--r-- | misc/openlayers/lib/OpenLayers/Layer/Bing.js | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Layer/Bing.js b/misc/openlayers/lib/OpenLayers/Layer/Bing.js new file mode 100644 index 0000000..0615285 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Layer/Bing.js @@ -0,0 +1,333 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Layer/XYZ.js + */ + +/** + * Class: OpenLayers.Layer.Bing + * Bing layer using direct tile access as provided by Bing Maps REST Services. + * See http://msdn.microsoft.com/en-us/library/ff701713.aspx for more + * information. Note: Terms of Service compliant use requires the map to be + * configured with an <OpenLayers.Control.Attribution> control and the + * attribution placed on or near the map. + * + * Inherits from: + * - <OpenLayers.Layer.XYZ> + */ +OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { + + /** + * Property: key + * {String} API key for Bing maps, get your own key + * at http://bingmapsportal.com/ . + */ + key: null, + + /** + * Property: serverResolutions + * {Array} the resolutions provided by the Bing servers. + */ + serverResolutions: [ + 156543.03390625, 78271.516953125, 39135.7584765625, + 19567.87923828125, 9783.939619140625, 4891.9698095703125, + 2445.9849047851562, 1222.9924523925781, 611.4962261962891, + 305.74811309814453, 152.87405654907226, 76.43702827453613, + 38.218514137268066, 19.109257068634033, 9.554628534317017, + 4.777314267158508, 2.388657133579254, 1.194328566789627, + 0.5971642833948135, 0.29858214169740677, 0.14929107084870338, + 0.07464553542435169 + ], + + /** + * Property: attributionTemplate + * {String} + */ + attributionTemplate: '<span class="olBingAttribution ${type}">' + + '<div><a target="_blank" href="http://www.bing.com/maps/">' + + '<img src="${logo}" /></a></div>${copyrights}' + + '<a style="white-space: nowrap" target="_blank" '+ + 'href="http://www.microsoft.com/maps/product/terms.html">' + + 'Terms of Use</a></span>', + + /** + * Property: metadata + * {Object} Metadata for this layer, as returned by the callback script + */ + metadata: null, + + /** + * Property: protocolRegex + * {RegExp} Regular expression to match and replace http: in bing urls + */ + protocolRegex: /^http:/i, + + /** + * APIProperty: type + * {String} The layer identifier. Any non-birdseye imageryType + * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be + * used. Default is "Road". + */ + type: "Road", + + /** + * APIProperty: culture + * {String} The culture identifier. See http://msdn.microsoft.com/en-us/library/ff701709.aspx + * for the definition and the possible values. Default is "en-US". + */ + culture: "en-US", + + /** + * APIProperty: metadataParams + * {Object} Optional url parameters for the Get Imagery Metadata request + * as described here: http://msdn.microsoft.com/en-us/library/ff701716.aspx + */ + metadataParams: null, + + /** APIProperty: tileOptions + * {Object} optional configuration options for <OpenLayers.Tile> instances + * created by this Layer. Default is + * + * (code) + * {crossOriginKeyword: 'anonymous'} + * (end) + */ + tileOptions: null, + + /** APIProperty: protocol + * {String} Protocol to use to fetch Imagery Metadata, tiles and bing logo + * Can be 'http:' 'https:' or '' + * + * Warning: tiles may not be available under both HTTP and HTTPS protocols. + * Microsoft approved use of both HTTP and HTTPS urls for tiles. However + * this is undocumented and the Imagery Metadata API always returns HTTP + * urls. + * + * Default is '', unless when executed from a file:/// uri, in which case + * it is 'http:'. + */ + protocol: ~window.location.href.indexOf('http') ? '' : 'http:', + + /** + * Constructor: OpenLayers.Layer.Bing + * Create a new Bing layer. + * + * Example: + * (code) + * var road = new OpenLayers.Layer.Bing({ + * name: "My Bing Aerial Layer", + * type: "Aerial", + * key: "my-api-key-here", + * }); + * (end) + * + * Parameters: + * options - {Object} Configuration properties for the layer. + * + * Required configuration properties: + * key - {String} Bing Maps API key for your application. Get one at + * http://bingmapsportal.com/. + * type - {String} The layer identifier. Any non-birdseye imageryType + * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be + * used. + * + * Any other documented layer properties can be provided in the config object. + */ + initialize: function(options) { + options = OpenLayers.Util.applyDefaults({ + sphericalMercator: true + }, options); + var name = options.name || "Bing " + (options.type || this.type); + + var newArgs = [name, null, options]; + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs); + this.tileOptions = OpenLayers.Util.extend({ + crossOriginKeyword: 'anonymous' + }, this.options.tileOptions); + this.loadMetadata(); + }, + + /** + * Method: loadMetadata + */ + loadMetadata: function() { + this._callbackId = "_callback_" + this.id.replace(/\./g, "_"); + // link the processMetadata method to the global scope and bind it + // to this instance + window[this._callbackId] = OpenLayers.Function.bind( + OpenLayers.Layer.Bing.processMetadata, this + ); + var params = OpenLayers.Util.applyDefaults({ + key: this.key, + jsonp: this._callbackId, + include: "ImageryProviders" + }, this.metadataParams); + var url = this.protocol + "//dev.virtualearth.net/REST/v1/Imagery/Metadata/" + + this.type + "?" + OpenLayers.Util.getParameterString(params); + var script = document.createElement("script"); + script.type = "text/javascript"; + script.src = url; + script.id = this._callbackId; + document.getElementsByTagName("head")[0].appendChild(script); + }, + + /** + * Method: initLayer + * + * Sets layer properties according to the metadata provided by the API + */ + initLayer: function() { + var res = this.metadata.resourceSets[0].resources[0]; + var url = res.imageUrl.replace("{quadkey}", "${quadkey}"); + url = url.replace("{culture}", this.culture); + url = url.replace(this.protocolRegex, this.protocol); + this.url = []; + for (var i=0; i<res.imageUrlSubdomains.length; ++i) { + this.url.push(url.replace("{subdomain}", res.imageUrlSubdomains[i])); + } + this.addOptions({ + maxResolution: Math.min( + this.serverResolutions[res.zoomMin], + this.maxResolution || Number.POSITIVE_INFINITY + ), + numZoomLevels: Math.min( + res.zoomMax + 1 - res.zoomMin, this.numZoomLevels + ) + }, true); + if (!this.isBaseLayer) { + this.redraw(); + } + this.updateAttribution(); + }, + + /** + * Method: getURL + * + * Paramters: + * bounds - {<OpenLayers.Bounds>} + */ + getURL: function(bounds) { + if (!this.url) { + return; + } + var xyz = this.getXYZ(bounds), x = xyz.x, y = xyz.y, z = xyz.z; + var quadDigits = []; + for (var i = z; i > 0; --i) { + var digit = '0'; + var mask = 1 << (i - 1); + if ((x & mask) != 0) { + digit++; + } + if ((y & mask) != 0) { + digit++; + digit++; + } + quadDigits.push(digit); + } + var quadKey = quadDigits.join(""); + var url = this.selectUrl('' + x + y + z, this.url); + + return OpenLayers.String.format(url, {'quadkey': quadKey}); + }, + + /** + * Method: updateAttribution + * Updates the attribution according to the requirements outlined in + * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html + */ + updateAttribution: function() { + var metadata = this.metadata; + if (!metadata.resourceSets || !this.map || !this.map.center) { + return; + } + var res = metadata.resourceSets[0].resources[0]; + var extent = this.map.getExtent().transform( + this.map.getProjectionObject(), + new OpenLayers.Projection("EPSG:4326") + ); + var providers = res.imageryProviders || [], + zoom = OpenLayers.Util.indexOf(this.serverResolutions, + this.getServerResolution()), + 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]; + // axis order provided is Y,X + bbox = OpenLayers.Bounds.fromArray(coverage.bbox, true); + if (extent.intersectsBounds(bbox) && + zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) { + copyrights += provider.attribution + " "; + } + } + } + var logo = metadata.brandLogoUri.replace(this.protocolRegex, this.protocol); + this.attribution = OpenLayers.String.format(this.attributionTemplate, { + type: this.type.toLowerCase(), + logo: logo, + copyrights: copyrights + }); + this.map && this.map.events.triggerEvent("changelayer", { + layer: this, + property: "attribution" + }); + }, + + /** + * Method: setMap + */ + setMap: function() { + OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); + this.map.events.register("moveend", this, this.updateAttribution); + }, + + /** + * APIMethod: clone + * + * Parameters: + * obj - {Object} + * + * Returns: + * {<OpenLayers.Layer.Bing>} An exact clone of this <OpenLayers.Layer.Bing> + */ + clone: function(obj) { + if (obj == null) { + obj = new OpenLayers.Layer.Bing(this.options); + } + //get all additions from superclasses + obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); + // copy/set any non-init, non-simple values here + return obj; + }, + + /** + * Method: destroy + */ + destroy: function() { + this.map && + this.map.events.unregister("moveend", this, this.updateAttribution); + OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments); + }, + + CLASS_NAME: "OpenLayers.Layer.Bing" +}); + +/** + * Function: OpenLayers.Layer.Bing.processMetadata + * This function will be bound to an instance, linked to the global scope with + * an id, and called by the JSONP script returned by the API. + * + * Parameters: + * metadata - {Object} metadata as returned by the API + */ +OpenLayers.Layer.Bing.processMetadata = function(metadata) { + this.metadata = metadata; + this.initLayer(); + var script = document.getElementById(this._callbackId); + script.parentNode.removeChild(script); + window[this._callbackId] = undefined; // cannot delete from window in IE + delete this._callbackId; +}; |