I try to create a map with leaflet.js where it is possible to switch between different tile layers. It works great with tileservers that serve the tiles with the standard x,y and z(oom) schema. However, Microsoft Bing uses its own quadkey schema. I found a JavaScript function to convert xyz to quad, but I don't know how to use it. Please see my example:
function toQuad(x, y, z) {
var quadkey = '';
for ( var i = z; i >= 0; --i) {
var bitmask = 1 << i;
var digit = 0;
if ((x & bitmask) !== 0) {
digit |= 1;}
if ((y & bitmask) !== 0) {
digit |= 2;}
quadkey += digit;
}
return quadkey;
};
var openstreetmap = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'}),
arcgissat = L.tileLayer('http://{s}.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {subdomains: ['server', 'services'], attribution: '© <a href="http://www.arcgis.com/">ArcGIS esri</a>'})
// bingsat = L.tileLayer('http://t{s}.tiles.virtualearth.net/tiles/a'+toQuad({x},{y},{z})+'.jpeg?g=1398', {subdomains: [0,1,2,3,4,5], attribution: '© <a href="http://bing.com/maps">Bing Maps</a>'}),
var map = L.map('map', {
center: [48.85,2.33],
zoom: 10,
layers: [openstreetmap]
});
var baseLayers = {
"OpenStreetMap": openstreetmap,
// "Bing Sat": bingsat,
"ArcGIS esri Sat": arcgissat
};
L.control.layers(baseLayers, null, {collapsed: false}).addTo(map);
Basically I just don't know how to call the JavaScript function inside of the variable declaration with the {x}, {y} and {z} values that leafletjs provides.
The latitude and longitude are assumed to be on the WGS 84 datum. Even though Bing Maps uses a spherical projection, it's important to convert all geographic coordinates into a common datum, and WGS 84 was chosen to be that datum.
XYZ tile layers are layers comprised of multiple tiles that are situated on a server and are made available to the public. Unlike WMTS that follow the OGC standard, the XYZ tile layers are the de facto OpenstreetMap standard.
The name quadkey is short for quadtree key. Each of these keys encodes a square region in latitude and longitude space organized by detail levels. At the first level, the whole mappable surface of the Earth splits into four quadkeys. Think of it as a map zoom level that allows you to see the entire world.
You can create a simple "BingLayer" by extending the L.TileLayer class. Then you just have to override the getTileUrl method to use the new template you prefer (i.e. for bing maps). See the linked fiddle for an example:
http://jsfiddle.net/nkmbx/
var BingLayer = L.TileLayer.extend({
getTileUrl: function (tilePoint) {
this._adjustTilePoint(tilePoint);
return L.Util.template(this._url, {
s: this._getSubdomain(tilePoint),
q: this._quadKey(tilePoint.x, tilePoint.y, this._getZoomForUrl())
});
},
_quadKey: function (x, y, z) {
var quadKey = [];
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++;
}
quadKey.push(digit);
}
return quadKey.join('');
}
});
For leaflet=>1 above answer of @user2494854 doesnt work. Here is updated version of his answer that worked for me:
var BingLayer = L.TileLayer.extend({
getTileUrl: function(coords) {
var quadkey = this.toQuadKey(coords.x, coords.y, coords.z)
var url = L.Util.template(this._url, {
q: quadkey,
s: this._getSubdomain(coords)
})
if (typeof this.options.style === 'string') {
url += '&st=' + this.options.style
}
return url
},
toQuadKey: function(x, y, z) {
var index = ''
for (var i = z; i > 0; i--) {
var b = 0
var mask = 1 << (i - 1)
if ((x & mask) !== 0) b++
if ((y & mask) !== 0) b += 2
index += b.toString()
}
return index
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With