goog.provide('ol.source.BingMaps'); goog.require('goog.Uri'); goog.require('goog.asserts'); goog.require('goog.net.Jsonp'); goog.require('ol.Attribution'); goog.require('ol.TileRange'); goog.require('ol.TileUrlFunction'); goog.require('ol.extent'); goog.require('ol.proj'); goog.require('ol.source.State'); goog.require('ol.source.TileImage'); goog.require('ol.tilecoord'); /** * @classdesc * Layer source for Bing Maps tile data. * * @constructor * @extends {ol.source.TileImage} * @param {olx.source.BingMapsOptions} options Bing Maps options. * @api stable */ ol.source.BingMaps = function(options) { goog.base(this, { crossOrigin: 'anonymous', opaque: true, projection: ol.proj.get('EPSG:3857'), reprojectionErrorThreshold: options.reprojectionErrorThreshold, state: ol.source.State.LOADING, tileLoadFunction: options.tileLoadFunction, wrapX: options.wrapX !== undefined ? options.wrapX : true }); /** * @private * @type {string} */ this.culture_ = options.culture !== undefined ? options.culture : 'en-us'; /** * @private * @type {number} */ this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1; var uri = new goog.Uri( 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' + options.imagerySet); var jsonp = new goog.net.Jsonp(uri, 'jsonp'); jsonp.send({ 'include': 'ImageryProviders', 'uriScheme': 'https', 'key': options.key }, goog.bind(this.handleImageryMetadataResponse, this)); }; goog.inherits(ol.source.BingMaps, ol.source.TileImage); /** * The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’ * Terms Of Use. * @const * @type {ol.Attribution} * @api */ ol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({ html: '' + 'Terms of Use' }); /** * @param {BingMapsImageryMetadataResponse} response Response. */ ol.source.BingMaps.prototype.handleImageryMetadataResponse = function(response) { if (response.statusCode != 200 || response.statusDescription != 'OK' || response.authenticationResultCode != 'ValidCredentials' || response.resourceSets.length != 1 || response.resourceSets[0].resources.length != 1) { this.setState(ol.source.State.ERROR); return; } var brandLogoUri = response.brandLogoUri; if (brandLogoUri.indexOf('https') == -1) { brandLogoUri = brandLogoUri.replace('http', 'https'); } //var copyright = response.copyright; // FIXME do we need to display this? var resource = response.resourceSets[0].resources[0]; goog.asserts.assert(resource.imageWidth == resource.imageHeight, 'resource has imageWidth equal to imageHeight, i.e. is square'); var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_; var sourceProjection = this.getProjection(); var extent = ol.tilegrid.extentFromProjection(sourceProjection); var tileSize = resource.imageWidth == resource.imageHeight ? resource.imageWidth : [resource.imageWidth, resource.imageHeight]; var tileGrid = ol.tilegrid.createXYZ({ extent: extent, minZoom: resource.zoomMin, maxZoom: maxZoom, tileSize: tileSize }); this.tileGrid = tileGrid; var culture = this.culture_; this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( resource.imageUrlSubdomains.map(function(subdomain) { var quadKeyTileCoord = [0, 0, 0]; var imageUrl = resource.imageUrl .replace('{subdomain}', subdomain) .replace('{culture}', culture); return ( /** * @param {ol.TileCoord} tileCoord Tile coordinate. * @param {number} pixelRatio Pixel ratio. * @param {ol.proj.Projection} projection Projection. * @return {string|undefined} Tile URL. */ function(tileCoord, pixelRatio, projection) { goog.asserts.assert(ol.proj.equivalent( projection, sourceProjection), 'projections are equivalent'); if (!tileCoord) { return undefined; } else { ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1], -tileCoord[2] - 1, quadKeyTileCoord); return imageUrl.replace('{quadkey}', ol.tilecoord.quadKey( quadKeyTileCoord)); } }); })); if (resource.imageryProviders) { var transform = ol.proj.getTransformFromProjections( ol.proj.get('EPSG:4326'), this.getProjection()); var attributions = resource.imageryProviders.map(function(imageryProvider) { var html = imageryProvider.attribution; /** @type {Object.>} */ var tileRanges = {}; imageryProvider.coverageAreas.forEach(function(coverageArea) { var minZ = coverageArea.zoomMin; var maxZ = Math.min(coverageArea.zoomMax, maxZoom); var bbox = coverageArea.bbox; var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]]; var extent = ol.extent.applyTransform(epsg4326Extent, transform); var tileRange, z, zKey; for (z = minZ; z <= maxZ; ++z) { zKey = z.toString(); tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); if (zKey in tileRanges) { tileRanges[zKey].push(tileRange); } else { tileRanges[zKey] = [tileRange]; } } }); return new ol.Attribution({html: html, tileRanges: tileRanges}); }); attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION); this.setAttributions(attributions); } this.setLogo(brandLogoUri); this.setState(ol.source.State.READY); };