Render only new features when a data tile is loaded

This commit is contained in:
John Firebaugh
2013-05-20 10:08:48 -07:00
parent d2e775ac65
commit 1db99586c4
7 changed files with 100 additions and 39 deletions

View File

@@ -275,40 +275,44 @@ iD.Connection = function() {
if (off) return;
var scaleExtent = [16, 16],
s = projection.scale() * 2 * Math.PI,
tiles = d3.geo.tile()
.scaleExtent(scaleExtent)
.scale(s)
.size(dimensions)
.translate(projection.translate())(),
var s = projection.scale() * 2 * Math.PI,
z = Math.max(Math.log(s) / 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 = [
ts = 256 * Math.pow(2, z - 16),
origin = [
s / 2 - projection.translate()[0],
s / 2 - projection.translate()[1]];
function bboxUrl(tile) {
var x = (tile[0] * ts) - tile_origin[0];
var y = (tile[1] * ts) - tile_origin[1];
var b = [
projection.invert([x, y]),
projection.invert([x + ts, y + ts])];
var tiles = d3.geo.tile()
.scaleExtent([16, 16])
.scale(s)
.size(dimensions)
.translate(projection.translate())()
.map(function(tile) {
var x = tile[0] * ts - origin[0],
y = tile[1] * ts - origin[1];
return url + '/api/0.6/map?bbox=' + [b[0][0], b[1][1], b[1][0], b[0][1]];
return {
id: tile.toString(),
extent: iD.geo.Extent(
projection.invert([x, y + ts]),
projection.invert([x + ts, y]))
}
});
function bboxUrl(tile) {
return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
}
_.filter(inflight, function(v, i) {
var wanted = _.find(tiles, function(tile) {
return i === tile.toString();
return i === tile.id;
});
if (!wanted) delete inflight[i];
return !wanted;
}).map(abortRequest);
tiles.forEach(function(tile) {
var id = tile.toString();
var id = tile.id;
if (loadedTiles[id] || inflight[id]) return;
@@ -320,7 +324,7 @@ iD.Connection = function() {
loadedTiles[id] = true;
delete inflight[id];
event.load(err, parsed);
event.load(err, _.extend({data: parsed}, tile));
if (_.isEmpty(inflight)) {
event.loaded();

View File

@@ -41,7 +41,7 @@ iD.History = function(context) {
return stack[index].graph;
},
merge: function(entities) {
merge: function(entities, extent) {
var base = stack[0].graph.base(),
newentities = Object.keys(entities).filter(function(i) {
@@ -54,7 +54,7 @@ iD.History = function(context) {
tree.rebase(newentities);
dispatch.change();
dispatch.change(undefined, extent);
},
perform: function() {

View File

@@ -35,6 +35,14 @@ _.extend(iD.geo.Extent.prototype, {
obj[1][1] >= this[0][1];
},
intersection: function(obj) {
if (!this.intersects(obj)) return new iD.geo.Extent();
return new iD.geo.Extent([Math.max(obj[0][0], this[0][0]),
Math.max(obj[0][1], this[0][1])],
[Math.min(obj[1][0], this[1][0]),
Math.min(obj[1][1], this[1][1])]);
},
padByMeters: function(meters) {
var dLat = meters / 111200,
dLon = meters / 111200 / Math.abs(Math.cos(this.center()[1]));

View File

@@ -31,7 +31,7 @@ window.iD = function () {
}
connection.on('load.context', function loadContext(err, result) {
history.merge(result);
history.merge(result.data, result.extent);
});
context.preauth = function(options) {

View File

@@ -96,16 +96,12 @@ iD.Map = function(context) {
function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
function drawVector(difference) {
function drawVector(difference, extent) {
var filter, all,
extent = map.extent(),
graph = context.graph();
if (!difference) {
all = context.intersects(extent);
filter = d3.functor(true);
} else {
var complete = difference.complete(extent);
if (difference) {
var complete = difference.complete(map.extent());
all = _.compact(_.values(complete));
filter = function(d) {
if (d.type === 'midpoint') {
@@ -131,15 +127,24 @@ iD.Map = function(context) {
return d.id in complete;
}
};
} else if (extent) {
all = context.intersects(map.extent().intersection(extent));
var set = d3.set(_.pluck(all, 'id'));
filter = function(d) { return set.has(d.id); };
} else {
all = context.intersects(map.extent());
filter = d3.functor(true);
}
surface
.call(points, graph, all, filter)
.call(vertices, graph, all, filter, extent, map.zoom())
.call(vertices, graph, all, filter, map.extent(), map.zoom())
.call(lines, graph, all, filter)
.call(areas, graph, all, filter)
.call(midpoints, graph, all, filter, extent)
.call(labels, graph, all, filter, dimensions, !difference);
.call(midpoints, graph, all, filter, map.extent())
.call(labels, graph, all, filter, dimensions, !difference && !extent);
dispatch.drawn(map);
}
@@ -192,7 +197,7 @@ iD.Map = function(context) {
return true;
}
function redraw(difference) {
function redraw(difference, extent) {
if (!surface) return;
@@ -202,7 +207,7 @@ iD.Map = function(context) {
// It would result in artifacts where differenced entities are redrawn with
// one transform and unchanged entities with another.
if (resetTransform()) {
difference = undefined;
difference = extent = undefined;
}
var zoom = String(~~map.zoom());
@@ -218,7 +223,7 @@ iD.Map = function(context) {
if (map.editable()) {
context.connection().loadTiles(projection, dimensions);
drawVector(difference);
drawVector(difference, extent);
} else {
editOff();
}

View File

@@ -23,10 +23,11 @@ describe("iD.History", function () {
expect(history.graph().entity('n')).to.equal(n);
});
it("emits a change event", function () {
it("emits a change event with the specified extent", function () {
var extent = {};
history.on('change', spy);
history.merge({});
expect(spy).to.have.been.called;
history.merge({}, extent);
expect(spy).to.have.been.calledWith(undefined, extent);
});
});

View File

@@ -109,4 +109,47 @@ describe("iD.geo.Extent", function () {
expect(iD.geo.Extent([[6, 6], [7, 7]]).intersects([[0, 0], [5, 5]])).to.be.false;
});
});
describe("#intersection", function () {
it("returns an empty extent if self does not intersect with other", function () {
var a = iD.geo.Extent([0, 0], [5, 5]),
b = iD.geo.Extent([6, 6], [7, 7]);
expect(a.intersection(b)).to.eql(iD.geo.Extent());
});
it("returns the intersection of self with other (1)", function () {
var a = iD.geo.Extent([0, 0], [5, 5]),
b = iD.geo.Extent([3, 4], [7, 7]);
expect(a.intersection(b)).to.eql(iD.geo.Extent([3, 4], [5, 5]));
expect(b.intersection(a)).to.eql(iD.geo.Extent([3, 4], [5, 5]));
});
it("returns the intersection of self with other (2)", function () {
var a = iD.geo.Extent([0, 0], [5, 5]),
b = iD.geo.Extent([3, -4], [7, 2]);
expect(a.intersection(b)).to.eql(iD.geo.Extent([3, 0], [5, 2]));
expect(b.intersection(a)).to.eql(iD.geo.Extent([3, 0], [5, 2]));
});
it("returns the intersection of self with other (3)", function () {
var a = iD.geo.Extent([0, 0], [5, 5]),
b = iD.geo.Extent([3, 3], [4, 7]);
expect(a.intersection(b)).to.eql(iD.geo.Extent([3, 3], [4, 5]));
expect(b.intersection(a)).to.eql(iD.geo.Extent([3, 3], [4, 5]));
});
it("returns the intersection of self with other (4)", function () {
var a = iD.geo.Extent([0, 0], [5, 5]),
b = iD.geo.Extent([3, -2], [4, 2]);
expect(a.intersection(b)).to.eql(iD.geo.Extent([3, 0], [4, 2]));
expect(b.intersection(a)).to.eql(iD.geo.Extent([3, 0], [4, 2]));
});
it("returns the intersection of self with other (5)", function () {
var a = iD.geo.Extent([0, 0], [5, 5]),
b = iD.geo.Extent([1, 1], [2, 2]);
expect(a.intersection(b)).to.eql(iD.geo.Extent([1, 1], [2, 2]));
expect(b.intersection(a)).to.eql(iD.geo.Extent([1, 1], [2, 2]));
});
});
});