diff --git a/js/id/renderer/background.js b/js/id/renderer/background.js index 6476e7a28..752853e6b 100644 --- a/js/id/renderer/background.js +++ b/js/id/renderer/background.js @@ -1,4 +1,10 @@ iD.Background = function() { + + var deviceRatio = (window.devicePixelRatio && + window.devicePixelRatio === 2) ? 0.5 : 1; + // tileSize = (deviceRatio === 0.5) ? [128,128] : [256,256]; + tileSize = [256, 256]; + var tile = d3.geo.tile(), projection, cache = {}, @@ -13,7 +19,12 @@ iD.Background = function() { '-o-transform-origin:0 0;' + '-webkit-user-select: none;' + '-webkit-user-drag: none;' + - '-moz-user-drag: none;'; + '-moz-user-drag: none;' + + 'opacity:0;'; + + function tileSizeAtZoom(d, z) { + return Math.ceil(tileSize[0] * Math.pow(2, z - d[2])) / tileSize[0]; + } function atZoom(t, distance) { var power = Math.pow(2, distance); @@ -21,108 +32,101 @@ iD.Background = function() { Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance]; - az.push(source(az)); return az; } - function upZoom(t, distance) { - var az = atZoom(t, distance), tiles = []; - for (var x = 0; x < 2; x++) { - for (var y = 0; y < 2; y++) { - var up = [az[0] + x, az[1] + y, az[2]]; - up.push(source(up)); - tiles.push(up); - } - } - return tiles; - } - - function tileSize(d, z) { - return Math.ceil(256 * Math.pow(2, z - d[2])) / 256; - } - function lookUp(d) { for (var up = -1; up > -d[2]; up--) { if (cache[atZoom(d, up)] !== false) return atZoom(d, up); } } + function uniqueBy(a, n) { + var o = [], seen = {}; + for (var i = 0; i < a.length; i++) { + if (seen[a[i][n]] === undefined) { + o.push(a[i]); + seen[a[i][n]] = true; + } + } + return o; + } + + function addSource(d) { + d.push(source(d)); + return d; + } + // derive the tiles onscreen, remove those offscreen and position tiles // correctly for the currentstate of `projection` function background() { - var tiles = tile + var sel = this, + tiles = tile .scale(projection.scale()) .scaleExtent(source.scaleExtent || [1, 17]) .translate(projection.translate())(), + requests = [], scaleExtent = tile.scaleExtent(), z = Math.max(Math.log(projection.scale()) / Math.log(2) - 8, 0), - rz = Math.max(scaleExtent[0], Math.min(scaleExtent[1], Math.floor(z))), - ts = 256 * Math.pow(2, z - rz), + rz = Math.max(scaleExtent[0], + Math.min(scaleExtent[1], Math.floor(z))), + ts = tileSize[0] * Math.pow(2, z - rz), tile_origin = [ projection.scale() / 2 - projection.translate()[0], - projection.scale() / 2 - projection.translate()[1]], - ups = {}; + projection.scale() / 2 - projection.translate()[1]]; tiles.forEach(function(d) { - - if (cache[d] === true) { - d.push(source(d)); - } else if (cache[d] === false && - cache[atZoom(d, -1)] !== false && - !ups[atZoom(d, -1)]) { - - ups[atZoom(d, -1)] = true; - tiles.push(atZoom(d, -1)); - - } else if (cache[d] === undefined && - lookUp(d)) { - - var upTile = lookUp(d); - if (!ups[upTile]) { - ups[upTile] = true; - tiles.push(upTile); - } - - } else if (cache[d] === undefined || - cache[d] === false) { - upZoom(d, 1).forEach(function(u) { - if (cache[u] && !ups[u]) { - ups[u] = true; - tiles.push(u); - } - }); + addSource(d); + requests.push(d); + if (!cache[d[3]] && lookUp(d)) { + requests.push(addSource(lookUp(d))); } }); - var image = this - .selectAll('img') - .data(tiles, function(d) { return d; }); + requests = uniqueBy(requests, 3); function load(d) { - cache[d.slice(0, 3)] = true; - d3.select(this).on('load', null); + cache[d[3]] = true; + d3.select(this) + .on('load', null) + .transition() + .style('opacity', 1); + background.apply(sel); } function error(d) { - cache[d.slice(0, 3)] = false; + cache[d[3]] = false; + d3.select(this).on('load', null); d3.select(this).remove(); + background.apply(sel); } + function imageTransform(d) { + var _ts = tileSize[0] * Math.pow(2, z - d[2]); + var scale = tileSizeAtZoom(d, z); + return 'translate(' + + (Math.round((d[0] * _ts) - tile_origin[0]) + offset[0]) + 'px,' + + (Math.round((d[1] * _ts) - tile_origin[1]) + offset[1]) + 'px)' + + 'scale(' + scale + ',' + scale + ')'; + } + + var image = this + .selectAll('img') + .data(requests, function(d) { return d[3]; }); + + image.exit() + .style(transformProp, imageTransform) + .transition() + .style('opacity', 0) + .remove(); + image.enter().append('img') .attr('style', imgstyle) .attr('src', function(d) { return d[3]; }) .on('error', error) .on('load', load); - - image.exit().remove(); - - image.style(transformProp, function(d) { - var _ts = 256 * Math.pow(2, z - d[2]); - var scale = tileSize(d, z); - return 'translate(' + - (Math.round((d[0] * _ts) - tile_origin[0]) + offset[0]) + 'px,' + - (Math.round((d[1] * _ts) - tile_origin[1]) + offset[1]) + 'px) scale(' + scale + ',' + scale + ')'; - }); + + image.style(transformProp, imageTransform); if (Object.keys(cache).length > 100) cache = {}; }