Bing.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the Clear BSD license.
  3. * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Layer/XYZ.js
  7. * @requires OpenLayers/Layer/SphericalMercator.js
  8. */
  9. /**
  10. * Class: OpenLayers.Layer.Bing
  11. * Bing layer using direct tile access as provided by Bing Maps REST Services.
  12. * See http://msdn.microsoft.com/en-us/library/ff701713.aspx for more
  13. * information. Note: Terms of Service compliant use requires the map to be
  14. * configured with an <OpenLayers.Control.Attribution> control and the
  15. * attribution placed on or near the map.
  16. *
  17. * Inherits from:
  18. * - <OpenLayers.Layer.XYZ>
  19. */
  20. OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
  21. /**
  22. * Property: serverResolutions
  23. * {Array} the resolutions provided by the Bing servers.
  24. */
  25. serverResolutions: [
  26. 156543.03390625, 78271.516953125, 39135.7584765625,
  27. 19567.87923828125, 9783.939619140625, 4891.9698095703125,
  28. 2445.9849047851562, 1222.9924523925781, 611.4962261962891,
  29. 305.74811309814453, 152.87405654907226, 76.43702827453613,
  30. 38.218514137268066, 19.109257068634033, 9.554628534317017,
  31. 4.777314267158508, 2.388657133579254, 1.194328566789627,
  32. 0.5971642833948135, 0.29858214169740677, 0.14929107084870338,
  33. 0.07464553542435169
  34. ],
  35. /**
  36. * Property: attributionTemplate
  37. * {String}
  38. */
  39. attributionTemplate: '<span class="olBingAttribution ${type}">' +
  40. '<div><a target="_blank" href="http://www.bing.com/maps/">' +
  41. '<img src="${logo}" /></a></div>${copyrights}' +
  42. '<a style="white-space: nowrap" target="_blank" '+
  43. 'href="http://www.microsoft.com/maps/product/terms.html">' +
  44. 'Terms of Use</a></span>',
  45. /**
  46. * Property: metadata
  47. * {Object} Metadata for this layer, as returned by the callback script
  48. */
  49. metadata: null,
  50. /**
  51. * APIProperty: type
  52. * {String} The layer identifier. Any non-birdseye imageryType
  53. * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be
  54. * used. Default is "Road".
  55. */
  56. type: "Road",
  57. /**
  58. * APIProperty: metadataParams
  59. * {Object} Optional url parameters for the Get Imagery Metadata request
  60. * as described here: http://msdn.microsoft.com/en-us/library/ff701716.aspx
  61. */
  62. metadataParams: null,
  63. /**
  64. * Constructor: OpenLayers.Layer.Bing
  65. * Create a new Bing layer.
  66. *
  67. * Example:
  68. * (code)
  69. * var road = new OpenLayers.Layer.Bing({
  70. * name: "My Bing Aerial Layer",
  71. * type: "Aerial",
  72. * key: "my-api-key-here",
  73. * });
  74. * (end)
  75. *
  76. * Parameters:
  77. * config - {Object} Configuration properties for the layer.
  78. *
  79. * Required configuration properties:
  80. * key - {String} Bing Maps API key for your application. Get one at
  81. * http://bingmapsportal.com/.
  82. * type - {String} The layer identifier. Any non-birdseye imageryType
  83. * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be
  84. * used.
  85. *
  86. * Any other documented layer properties can be provided in the config object.
  87. */
  88. initialize: function(options) {
  89. options = OpenLayers.Util.applyDefaults({
  90. sphericalMercator: true
  91. }, options);
  92. var name = options.name || "Bing " + (options.type || this.type);
  93. var newArgs = [name, null, options];
  94. OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs);
  95. this.loadMetadata();
  96. },
  97. /**
  98. * Method: loadMetadata
  99. */
  100. loadMetadata: function() {
  101. this._callbackId = "_callback_" + this.id.replace(/\./g, "_");
  102. // link the processMetadata method to the global scope and bind it
  103. // to this instance
  104. window[this._callbackId] = OpenLayers.Function.bind(
  105. OpenLayers.Layer.Bing.processMetadata, this
  106. );
  107. var params = OpenLayers.Util.applyDefaults({
  108. key: this.key,
  109. jsonp: this._callbackId,
  110. include: "ImageryProviders"
  111. }, this.metadataParams);
  112. var url = "http://dev.virtualearth.net/REST/v1/Imagery/Metadata/" +
  113. this.type + "?" + OpenLayers.Util.getParameterString(params);
  114. var script = document.createElement("script");
  115. script.type = "text/javascript";
  116. script.src = url;
  117. script.id = this._callbackId;
  118. document.getElementsByTagName("head")[0].appendChild(script);
  119. },
  120. /**
  121. * Method: initLayer
  122. *
  123. * Sets layer properties according to the metadata provided by the API
  124. */
  125. initLayer: function() {
  126. var res = this.metadata.resourceSets[0].resources[0];
  127. var url = res.imageUrl.replace("{quadkey}", "${quadkey}");
  128. this.url = [];
  129. for (var i=0; i<res.imageUrlSubdomains.length; ++i) {
  130. this.url.push(url.replace("{subdomain}", res.imageUrlSubdomains[i]));
  131. };
  132. this.addOptions({
  133. maxResolution: Math.min(
  134. this.serverResolutions[res.zoomMin], this.maxResolution
  135. ),
  136. zoomOffset: res.zoomMin,
  137. numZoomLevels: Math.min(
  138. res.zoomMax + 1 - res.zoomMin, this.numZoomLevels
  139. )
  140. }, true);
  141. },
  142. /**
  143. * Method: getURL
  144. *
  145. * Paramters:
  146. * bounds - {<OpenLayers.Bounds>}
  147. */
  148. getURL: function(bounds) {
  149. if (!this.url) {
  150. return OpenLayers.Util.getImagesLocation() + "blank.gif";
  151. }
  152. var xyz = this.getXYZ(bounds), x = xyz.x, y = xyz.y, z = xyz.z;
  153. var quadDigits = [];
  154. for (var i = z; i > 0; --i) {
  155. var digit = '0';
  156. var mask = 1 << (i - 1);
  157. if ((x & mask) != 0) {
  158. digit++;
  159. }
  160. if ((y & mask) != 0) {
  161. digit++;
  162. digit++;
  163. }
  164. quadDigits.push(digit);
  165. }
  166. var quadKey = quadDigits.join("");
  167. var url = this.selectUrl('' + x + y + z, this.url);
  168. return OpenLayers.String.format(url, {'quadkey': quadKey});
  169. },
  170. /**
  171. * Method: updateAttribution
  172. * Updates the attribution according to the requirements outlined in
  173. * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html
  174. */
  175. updateAttribution: function() {
  176. var metadata = this.metadata;
  177. if (!metadata || !this.map || !this.map.center) {
  178. return;
  179. }
  180. var res = metadata.resourceSets[0].resources[0];
  181. var extent = this.map.getExtent().transform(
  182. this.map.getProjectionObject(),
  183. new OpenLayers.Projection("EPSG:4326")
  184. );
  185. var providers = res.imageryProviders, zoom = this.map.getZoom() + 1,
  186. copyrights = "", provider, i, ii, j, jj, bbox, coverage;
  187. for (i=0,ii=providers.length; i<ii; ++i) {
  188. provider = providers[i];
  189. for (j=0,jj=provider.coverageAreas.length; j<jj; ++j) {
  190. coverage = provider.coverageAreas[j];
  191. bbox = OpenLayers.Bounds.fromArray(coverage.bbox);
  192. if (extent.intersectsBounds(bbox) &&
  193. zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) {
  194. copyrights += provider.attribution + " ";
  195. }
  196. }
  197. }
  198. this.attribution = OpenLayers.String.format(this.attributionTemplate, {
  199. type: this.type.toLowerCase(),
  200. logo: metadata.brandLogoUri,
  201. copyrights: copyrights
  202. });
  203. this.map && this.map.events.triggerEvent("changelayer", {
  204. layer: this,
  205. property: "attribution"
  206. });
  207. },
  208. /**
  209. * Method: setMap
  210. */
  211. setMap: function() {
  212. OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments);
  213. this.updateAttribution();
  214. this.map.events.register("moveend", this, this.updateAttribution);
  215. },
  216. /**
  217. * APIMethod: clone
  218. *
  219. * Parameters:
  220. * obj - {Object}
  221. *
  222. * Returns:
  223. * {<OpenLayers.Layer.Bing>} An exact clone of this <OpenLayers.Layer.Bing>
  224. */
  225. clone: function(obj) {
  226. if (obj == null) {
  227. obj = new OpenLayers.Layer.Bing(this.options);
  228. }
  229. //get all additions from superclasses
  230. obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
  231. // copy/set any non-init, non-simple values here
  232. return obj;
  233. },
  234. /**
  235. * Method: destroy
  236. */
  237. destroy: function() {
  238. this.map &&
  239. this.map.events.unregister("moveend", this, this.updateAttribution);
  240. OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments);
  241. },
  242. CLASS_NAME: "OpenLayers.Layer.Bing"
  243. });
  244. /**
  245. * Function: OpenLayers.Layer.Bing.processMetadata
  246. * This function will be bound to an instance, linked to the global scope with
  247. * an id, and called by the JSONP script returned by the API.
  248. *
  249. * Parameters:
  250. * metadata - {Object} metadata as returned by the API
  251. */
  252. OpenLayers.Layer.Bing.processMetadata = function(metadata) {
  253. this.metadata = metadata;
  254. this.initLayer();
  255. var script = document.getElementById(this._callbackId);
  256. script.parentNode.removeChild(script);
  257. window[this._callbackId] = undefined; // cannot delete from window in IE
  258. delete this._callbackId;
  259. };