[OpenLayers-Commits] r10975 - in trunk/openlayers: examples lib
lib/OpenLayers/Layer tests tests/Layer theme/default
commits-20090109 at openlayers.org
commits-20090109 at openlayers.org
Fri Dec 17 18:46:22 EST 2010
Author: ahocevar
Date: 2010-12-17 15:46:22 -0800 (Fri, 17 Dec 2010)
New Revision: 10975
Added:
trunk/openlayers/examples/bing-tiles.html
trunk/openlayers/examples/bing-tiles.js
trunk/openlayers/lib/OpenLayers/Layer/Bing.js
trunk/openlayers/tests/Layer/Bing.html
Modified:
trunk/openlayers/lib/OpenLayers.js
trunk/openlayers/lib/OpenLayers/Layer/XYZ.js
trunk/openlayers/tests/list-tests.html
trunk/openlayers/theme/default/style.css
Log:
Added Bing layer with direct tile access. p=me,tschaub r=tschaub,me (closes #2975)
Added: trunk/openlayers/examples/bing-tiles.html
===================================================================
--- trunk/openlayers/examples/bing-tiles.html (rev 0)
+++ trunk/openlayers/examples/bing-tiles.html 2010-12-17 23:46:22 UTC (rev 10975)
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>OpenLayers Bing Tiles Example</title>
+ <link rel="stylesheet" href="../theme/default/style.css" type="text/css">
+ <link rel="stylesheet" href="style.css" type="text/css">
+ <style type="text/css">
+ .olControlAttribution {
+ left: 5px;
+ right: inherit;
+ bottom: 5px;
+ }
+ </style>
+ </head>
+ <body>
+ <h1 id="title">Basic Bing Tiles Example</h1>
+
+ <div id="tags">
+ bing tiles
+ </div>
+
+ <div id="shortdesc">Use Bing with direct tile access</div>
+
+ <div id="map" class="smallmap"></div>
+
+ <div id="docs">
+ <p>This example shows a very simple map with Bing layers that use
+ direct tile access through Bing Maps REST Services.</p><p>See
+ <a target="_blank" href="bing-tiles.js">bing-tiles.js</a> for the
+ source code.</p>
+ </div>
+ <script src="../lib/OpenLayers.js"></script>
+ <script src="bing-tiles.js"></script>
+ </body>
+</html>
Added: trunk/openlayers/examples/bing-tiles.js
===================================================================
--- trunk/openlayers/examples/bing-tiles.js (rev 0)
+++ trunk/openlayers/examples/bing-tiles.js 2010-12-17 23:46:22 UTC (rev 10975)
@@ -0,0 +1,26 @@
+// API key for http://openlayers.org. Please get your own at
+// http://bingmapsportal.com/ and use that instead.
+var apiKey = "AqTGBsziZHIJYYxgivLBf0hVdrAk9mWO5cQcb8Yux8sW5M8c8opEC2lZqKR1ZZXf";
+
+var map = new OpenLayers.Map( 'map');
+
+var road = new OpenLayers.Layer.Bing({
+ key: apiKey,
+ type: "Road"
+});
+var aerial = new OpenLayers.Layer.Bing({
+ key: apiKey,
+ type: "Aerial"
+});
+var hybrid = new OpenLayers.Layer.Bing({
+ key: apiKey,
+ type: "AerialWithLabels",
+ name: "Bing Aerial With Labels"
+});
+
+map.addLayers([road, aerial, hybrid]);
+map.addControl(new OpenLayers.Control.LayerSwitcher());
+map.setCenter(new OpenLayers.LonLat(-71.147, 42.472).transform(
+ new OpenLayers.Projection("EPSG:4326"),
+ map.getProjectionObject()
+), 12);
Added: trunk/openlayers/lib/OpenLayers/Layer/Bing.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/Bing.js (rev 0)
+++ trunk/openlayers/lib/OpenLayers/Layer/Bing.js 2010-12-17 23:46:22 UTC (rev 10975)
@@ -0,0 +1,312 @@
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt 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.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.XYZ>
+ */
+OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
+
+ /**
+ * Constant: RESOLUTIONS
+ */
+ RESOLUTIONS: [
+ 78271.517,
+ 39135.7585,
+ 19567.87925,
+ 9783.939625,
+ 4891.9698125,
+ 2445.98490625,
+ 1222.992453125,
+ 611.4962265625,
+ 305.74811328125,
+ 152.874056640625,
+ 76.4370283203125,
+ 38.21851416015625,
+ 19.109257080078127,
+ 9.554628540039063,
+ 4.777314270019532,
+ 2.388657135009766,
+ 1.194328567504883,
+ 0.5971642837524415,
+ 0.29858214187622073,
+ 0.14929107093811037,
+ 0.07464553546905518,
+ 0.03732276773452759,
+ 0.018661383867263796
+ ],
+
+ /**
+ * Property: attributionTemplate
+ * {String}
+ */
+ attributionTemplate: '<span class="olBingAttribution ${type}">' +
+ '<div><a target="_blank" href="http://www.bing.com/maps/">' +
+ '<img src="${logo}"></img></div></a>${copyrights}' +
+ '<a style="white-space: nowrap" target="_blank" '+
+ 'href="http://www.microsoft.com/maps/product/terms.html">' +
+ 'Terms of Use</a></span>',
+
+ /**
+ * Property: sphericalMercator
+ * {Boolean} always true for this layer type
+ */
+ sphericalMercator: true,
+
+ /**
+ * Property: metadata
+ * {Object} Metadata for this layer, as returned by the callback script
+ */
+ metadata: null,
+
+ /**
+ * 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",
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * layer.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * All event objects have at least the following properties:
+ * object - {Object} A reference to layer.events.object.
+ * element - {DOMElement} A reference to layer.events.element.
+ *
+ * Supported map event types (in addition to those from <OpenLayers.Layer>):
+ * added - Triggered after the layer is added to a map. Listeners
+ * will receive an object with a *map* property referencing the
+ * map and a *layer* property referencing the layer.
+ */
+ EVENT_TYPES: ["added"],
+
+ /**
+ * 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:
+ * config - {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) {
+ // concatenate events specific to vector with those from the base
+ this.EVENT_TYPES =
+ OpenLayers.Layer.Bing.prototype.EVENT_TYPES.concat(
+ OpenLayers.Layer.prototype.EVENT_TYPES
+ );
+ var name = options.name || "Bing " + (options.type || this.type);
+ var newArgs = [name, null, options];
+ OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs);
+ this.loadMetadata(this.type);
+ },
+
+ /**
+ * Method: loadMetadata
+ *
+ * Parameters:
+ * imageryType - {String}
+ */
+ loadMetadata: function(imageryType) {
+ 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 url = "http://dev.virtualearth.net/REST/v1/Imagery/Metadata/" +
+ imageryType + "?key=" + this.key + "&jsonp=" + this._callbackId +
+ "&include=ImageryProviders";
+ 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}");
+ this.url = [];
+ for (var i=0; i<res.imageUrlSubdomains.length; ++i) {
+ this.url.push(url.replace("{subdomain}", res.imageUrlSubdomains[i]));
+ };
+
+ this.addOptions({
+ resolutions: this.RESOLUTIONS.slice(res.zoomMin-1, res.zoomMax-1),
+ zoomOffset: res.zoomMin
+ });
+ if (this.map) {
+ this.redraw();
+ this.updateAttribution();
+ }
+ },
+
+ /**
+ * Method: getURL
+ *
+ * Paramters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ getURL: function(bounds) {
+ if (!this.url) {
+ return OpenLayers.Util.getImagesLocation() + "blank.gif";
+ }
+ 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 || !this.map) {
+ 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 = 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];
+ bbox = OpenLayers.Bounds.fromArray(coverage.bbox);
+ if (extent.intersectsBounds(bbox) &&
+ zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) {
+ copyrights += provider.attribution + " ";
+ }
+ }
+ }
+ this.attribution = OpenLayers.String.format(this.attributionTemplate, {
+ type: this.type.toLowerCase(),
+ logo: metadata.brandLogoUri,
+ copyrights: copyrights
+ });
+ this.map && this.map.events.triggerEvent("changelayer", {layer: this});
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function() {
+ OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments);
+ if (this.map.getCenter()) {
+ this.updateAttribution();
+ }
+ this.map.events.register("moveend", this, this.updateAttribution);
+ // TODO: move this event to Layer
+ // http://trac.osgeo.org/openlayers/ticket/2983
+ this.events.triggerEvent("added", {map: this.map, layer: this});
+ },
+
+ /**
+ * 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;
+};
Modified: trunk/openlayers/lib/OpenLayers/Layer/XYZ.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/XYZ.js 2010-12-17 16:04:06 UTC (rev 10974)
+++ trunk/openlayers/lib/OpenLayers/Layer/XYZ.js 2010-12-17 23:46:22 UTC (rev 10975)
@@ -107,7 +107,7 @@
},
/**
- * Method: getUrl
+ * Method: getURL
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
@@ -118,6 +118,27 @@
* parameters
*/
getURL: function (bounds) {
+ var xyz = this.getXYZ(bounds);
+ var url = this.url;
+ if (url instanceof Array) {
+ var s = '' + xyz.x + xyz.y + xyz.z;
+ url = this.selectUrl(s, url);
+ }
+
+ return OpenLayers.String.format(url, xyz);
+ },
+
+ /**
+ * Method: getXYZ
+ * Calculates x, y and z for the given bounds.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {Object} - an object with x, y and z properties.
+ */
+ getXYZ: function(bounds) {
var res = this.map.getResolution();
var x = Math.round((bounds.left - this.maxExtent.left)
/ (res * this.tileSize.w));
@@ -127,16 +148,7 @@
OpenLayers.Util.indexOf(this.serverResolutions, res) :
this.map.getZoom() + this.zoomOffset;
- var url = this.url;
- var s = '' + x + y + z;
- if (url instanceof Array)
- {
- url = this.selectUrl(s, url);
- }
-
- var path = OpenLayers.String.format(url, {'x': x, 'y': y, 'z': z});
-
- return path;
+ return {'x': x, 'y': y, 'z': z};
},
/**
Modified: trunk/openlayers/lib/OpenLayers.js
===================================================================
--- trunk/openlayers/lib/OpenLayers.js 2010-12-17 16:04:06 UTC (rev 10974)
+++ trunk/openlayers/lib/OpenLayers.js 2010-12-17 23:46:22 UTC (rev 10975)
@@ -127,6 +127,7 @@
"OpenLayers/Layer/GeoRSS.js",
"OpenLayers/Layer/Boxes.js",
"OpenLayers/Layer/XYZ.js",
+ "OpenLayers/Layer/Bing.js",
"OpenLayers/Layer/TMS.js",
"OpenLayers/Layer/TileCache.js",
"OpenLayers/Layer/Zoomify.js",
Added: trunk/openlayers/tests/Layer/Bing.html
===================================================================
--- trunk/openlayers/tests/Layer/Bing.html (rev 0)
+++ trunk/openlayers/tests/Layer/Bing.html 2010-12-17 23:46:22 UTC (rev 10975)
@@ -0,0 +1,65 @@
+<html>
+<head>
+ <script src="../../lib/OpenLayers.js"></script>
+ <script type="text/javascript">
+ var layer;
+
+ var layerType = 'Aerial';
+ var key = "AqTGBsziZHIJYYxgivLBf0hVdrAk9mWO5cQcb8Yux8sW5M8c8opEC2lZqKR1ZZXf";
+
+ var options = {
+ type: layerType,
+ key: key
+ };
+
+ function test_constructor(t) {
+ t.plan(2);
+
+ var origProcessMetadata = OpenLayers.Layer.Bing.processMetadata;
+ var log = [];
+ OpenLayers.Layer.Bing.processMetadata = function(metadata) {
+ log.push(metadata);
+ origProcessMetadata.apply(this, arguments);
+ };
+ layer = new OpenLayers.Layer.Bing(options);
+ t.ok(layer instanceof OpenLayers.Layer.Bing, "returns OpenLayers.Layer.Bing object" );
+ t.delay_call(2, function() {
+ t.eq(log.length, 1, "processMetadata called");
+ OpenLayers.Layer.Bing.processMetadata = origProcessMetadata;
+ layer.destroy();
+ });
+ }
+
+ function test_attribution(t) {
+ t.plan(3);
+
+ var log = [];
+ var map = new OpenLayers.Map("map");
+ layer = new OpenLayers.Layer.Bing(options);
+ map.addLayer(layer);
+ map.zoomToMaxExtent();
+
+ t.delay_call(2, function() {
+ t.ok(layer.attribution.indexOf('olBingAttribution aerial') !== -1, "Attribution has the correct css class");
+ t.ok(layer.attribution.indexOf('<img src="">') == -1, "Attribution contains a logo");
+ t.ok(layer.attribution.indexOf('</img></div></a><a style=') == -1 , "Attribution contains a copyright");
+ map.destroy();
+ });
+ }
+
+ function test_clone(t) {
+ t.plan(1);
+
+ var clone;
+
+ layer = new OpenLayers.Layer.Bing(options);
+ clone = layer.clone();
+ t.ok(clone instanceof OpenLayers.Layer.Bing, "clone is a Layer.Bing instance");
+ }
+
+ </script>
+</head>
+<body>
+<div id="map" style="width:500px;height:550px"></div>
+</body>
+</html>
Modified: trunk/openlayers/tests/list-tests.html
===================================================================
--- trunk/openlayers/tests/list-tests.html 2010-12-17 16:04:06 UTC (rev 10974)
+++ trunk/openlayers/tests/list-tests.html 2010-12-17 23:46:22 UTC (rev 10975)
@@ -125,6 +125,7 @@
<li>Layer.html</li>
<li>Layer/ArcIMS.html</li>
<li>Layer/ArcGIS93Rest.html</li>
+ <li>Layer/Bing.html</li>
<li>Layer/EventPane.html</li>
<li>Layer/FixedZoomLevels.html</li>
<li>Layer/GeoRSS.html</li>
Modified: trunk/openlayers/theme/default/style.css
===================================================================
--- trunk/openlayers/theme/default/style.css 2010-12-17 16:04:06 UTC (rev 10974)
+++ trunk/openlayers/theme/default/style.css 2010-12-17 23:46:22 UTC (rev 10975)
@@ -397,3 +397,10 @@
top: 5px;
right: 0px;
}
+
+.olBingAttribution {
+ color: #DDD;
+}
+.olBingAttribution.road {
+ color: #333;
+}
More information about the Commits
mailing list