mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-14 09:42:56 +00:00
`iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
* The `origin` function is expected to return an [x, y] tuple rather than an
{x, y} object.
* The events are `start`, `move`, and `end`.
(https://github.com/mbostock/d3/issues/563)
* The `start` event is not dispatched until the first cursor movement occurs.
(https://github.com/mbostock/d3/pull/368)
* The `move` event has a `loc` and `dxdy` [x, y] tuple properties rather
than `x`, `y`, `dx`, and `dy` properties.
* The `end` event is not dispatched if no movement occurs.
* An `off` function is available that unbinds the drag's internal event handlers.
* Delegation is supported via the `delegate` function.
120 lines
3.6 KiB
JavaScript
120 lines
3.6 KiB
JavaScript
iD.Background = function() {
|
|
var tile = d3.geo.tile(),
|
|
projection,
|
|
cache = {},
|
|
transformProp = iD.util.prefixCSSProperty('Transform'),
|
|
source = d3.functor('');
|
|
|
|
function atZoom(t, distance) {
|
|
var power = Math.pow(2, distance);
|
|
var az = [
|
|
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;
|
|
}
|
|
|
|
// derive the tiles onscreen, remove those offscreen and position tiles
|
|
// correctly for the currentstate of `projection`
|
|
function background() {
|
|
var tiles = tile
|
|
.scale(projection.scale())
|
|
.scaleExtent(source.scaleExtent || [1, 17])
|
|
.translate(projection.translate())(),
|
|
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),
|
|
tile_origin = [
|
|
projection.scale() / 2 - projection.translate()[0],
|
|
projection.scale() / 2 - projection.translate()[1]],
|
|
ups = {};
|
|
|
|
tiles.forEach(function(d) {
|
|
d.push(source(d));
|
|
// this tile has not been loaded yet
|
|
if (!cache[d] &&
|
|
cache[atZoom(d, -1)] &&
|
|
!ups[atZoom(d, -1)]) {
|
|
ups[atZoom(d, -1)] = true;
|
|
tiles.push(atZoom(d, -1));
|
|
} else if (!cache[d]) {
|
|
upZoom(d, 1).forEach(function(u) {
|
|
if (cache[u] && !ups[u]) {
|
|
ups[u] = true;
|
|
tiles.push(u);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
var image = this
|
|
.selectAll('img')
|
|
.data(tiles, function(d) { return d; });
|
|
|
|
image.exit().remove();
|
|
|
|
function load(d) {
|
|
cache[d] = true;
|
|
d3.select(this).on('load', null);
|
|
}
|
|
|
|
function error() {
|
|
d3.select(this).remove();
|
|
}
|
|
|
|
image.enter().append('img')
|
|
.attr('class', 'tile')
|
|
.attr('src', function(d) { return d[3]; })
|
|
.on('error', error)
|
|
.on('load', load);
|
|
|
|
function tileSize(d) {
|
|
return Math.ceil(256 * Math.pow(2, z - d[2])) / 256;
|
|
}
|
|
|
|
image.style(transformProp, function(d) {
|
|
var _ts = 256 * Math.pow(2, z - d[2]);
|
|
var scale = tileSize(d);
|
|
return 'translate(' +
|
|
Math.round((d[0] * _ts) - tile_origin[0]) + 'px,' +
|
|
Math.round((d[1] * _ts) - tile_origin[1]) + 'px) scale(' + scale + ',' + scale + ')';
|
|
});
|
|
|
|
if (Object.keys(cache).length > 100) cache = {};
|
|
}
|
|
|
|
background.projection = function(_) {
|
|
if (!arguments.length) return projection;
|
|
projection = _;
|
|
return background;
|
|
};
|
|
|
|
background.size = function(_) {
|
|
if (!arguments.length) return tile.size();
|
|
tile.size(_);
|
|
return background;
|
|
};
|
|
|
|
background.source = function(_) {
|
|
if (!arguments.length) return source;
|
|
source = _;
|
|
return background;
|
|
};
|
|
|
|
return background;
|
|
};
|