Skip to content

Commit

Permalink
Merge pull request #220 from mapbox/optimize-zoom
Browse files Browse the repository at this point in the history
Significantly improve zoom performance
  • Loading branch information
ansis committed Dec 16, 2013
2 parents 7a7a9ec + 206bfea commit 5c36053
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 58 deletions.
105 changes: 47 additions & 58 deletions js/ui/datasource.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Layer.prototype._getCoveringTiles = function() {
this.map.transform.pointCoordinate(tileCenter, {x:this.map.transform.width, y:0}),
this.map.transform.pointCoordinate(tileCenter, {x:this.map.transform.width, y:this.map.transform.height}),
this.map.transform.pointCoordinate(tileCenter, {x:0, y:this.map.transform.height})
], t = [];
], t = {};

points.forEach(function(p) {
Coordinate.izoomTo(p, z);
Expand All @@ -161,28 +161,23 @@ Layer.prototype._getCoveringTiles = function() {
this._scanTriangle(points[0], points[1], points[2], 0, tiles, scanLine);
this._scanTriangle(points[2], points[3], points[0], 0, tiles, scanLine);

var uniques = util.unique(t);

var first = true;
uniques.sort(fromCenter);

return uniques;
return Object.keys(t).sort(fromCenter);

function fromCenter(a, b) {
var at = Tile.fromID(a),
bt = Tile.fromID(b),
ad = Math.abs(at.x - tileCenter.column) +
Math.abs(at.y - tileCenter.row),
bd = Math.abs(bt.x - tileCenter.column) +
Math.abs(bt.y - tileCenter.row);
var ad = Math.abs(a.x - tileCenter.column) +
Math.abs(a.y - tileCenter.row),
bd = Math.abs(b.x - tileCenter.column) +
Math.abs(b.y - tileCenter.row);

return ad - bd;
}

function scanLine(x0, x1, y) {
var x, wx;
if (y >= 0 && y <= tiles) {
for (var x = x0; x < x1; x++) {
t.push(Tile.toID(z, (x + tiles) % tiles, y, Math.floor(x/tiles)));
for (x = x0; x < x1; x++) {
wx = (x + tiles) % tiles;
t[Tile.toID(z, wx, y, Math.floor(x/tiles))] = {x: wx, y: y};
}
}
}
Expand Down Expand Up @@ -221,7 +216,7 @@ Layer.prototype._updateTiles = function() {

var map = this,
zoom = this.map.transform.zoom,
required = this._getCoveringTiles(),
covering = this._getCoveringTiles(),
panTile = this._getPanTile(zoom),
missing = [],
i,
Expand All @@ -236,15 +231,19 @@ Layer.prototype._updateTiles = function() {
else maxCoveringZoom = level;
}

var required = {};

// Add every tile, and add parent/child tiles if they are not yet loaded.
for (i = 0; i < required.length; i++) {
id = required[i];
for (i = 0; i < covering.length; i++) {
id = +covering[i];
var tile = this._addTile(id);

if (!tile.loaded) {
// We need either parent or child tiles that are available immediately
missing.push(id);
}

required[id] = true;
}

findTile: for (i = 0; i < missing.length; i++) {
Expand All @@ -260,61 +259,50 @@ Layer.prototype._updateTiles = function() {
// Potentially add items from the MRU cache.
if (this.cache.has(parent)) {
this._addTile(parent);
}
else if (this.tiles[parent] && this.tiles[parent].loaded) {
continue findTile;
} else if (this.tiles[parent] && this.tiles[parent].loaded) {
// Retain the existing parent tile
if (required.indexOf(parent) < 0) {
required.push(parent);
}
required[parent] = true;
continue findTile;
}
}


// Go down for max 1 zoom levels to find child tiles.
z = missingZoom;
while (z <= maxCoveringZoom && z !== null) {
z = this._childZoomLevel(z);
var childID, parentID;

// Go through the MRU cache and try to find existing tiles that are
// children of this tile.
var keys = this.cache.keys();
var childID, parentID;
for (var j = 0; j < keys.length; j++) {
childID = keys[j];
parentID = Tile.parentWithZoom(childID, missingZoom);
if (parentID == id) {
// Go through the MRU cache and try to find existing tiles that are
// children of this tile.
for (childID in this.cache.list) {
if (this.cache.list[childID].zoom <= maxCoveringZoom) {
parentID = Tile.parentWithZoom(+childID, missingZoom);
if (parentID === id) {
this._addTile(childID);
}
}
}

// Go through all existing tiles and retain those that are children
// of the current missing tile.
for (var child in this.tiles) {
child = +child;
parentID = Tile.parentWithZoom(child, missingZoom);
if (parentID == id && this.tiles[child].loaded) {
// Go through all existing tiles and retain those that are children
// of the current missing tile.
for (childID in this.tiles) {
if (this.tiles[childID].zoom <= maxCoveringZoom) {
var parentID = Tile.parentWithZoom(+childID, missingZoom);
if (parentID === id && this.tiles[childID].loaded) {
// Retain the existing child tile
if (required.indexOf(child) < 0) {
required.push(child);
}
required[childID] = true;
}
}
}

// TODO: panTile causes severe flickering
// if (required.indexOf(panTile) < 0) {
// this._addTile(panTile);
// required.push(panTile);
// }
if (!required[panTile]) {
this._addTile(panTile);
required[panTile] = true;
}
}


var existing = Object.keys(this.tiles).map(parseFloat),
remove = util.difference(existing, required);
var remove = util.keysDifference(this.tiles, required);

for (i = 0; i < remove.length; i++) {
id = remove[i];
id = +remove[i];
map._removeTile(id);
}
};
Expand Down Expand Up @@ -354,9 +342,9 @@ Layer.prototype._addTile = function(id) {
var tile;
if (this.tiles[id]) {
tile = this.tiles[id];
// } else if (this.cache.has(id)) {
// this.tiles[id] = this.cache.get(id);
// return this.tiles[id];
} else if (this.cache.has(id)) {
tile = this.tiles[id] = this.cache.get(id);
return tile;
} else {
tile = this._loadTile(id);
this.fire('tile.add', tile);
Expand All @@ -381,13 +369,14 @@ Layer.prototype._removeTile = function(id) {
// Only add it to the MRU cache if it's already available.
// Otherwise, there's no point in retaining it.
if (tile.loaded) {
// this.cache.add(id, tile);
this.cache.add(id, tile);
} else {
tile.abort();
tile.remove();
}

this.map.removeTile(tile);
tile.remove();

this.fire('tile.remove', tile);
}
}
Expand Down
10 changes: 10 additions & 0 deletions js/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ exports.difference = function difference(arr, other) {
});
};

exports.keysDifference = function keysDifference(obj, other) {
var difference = [];
for (var i in obj) {
if (!(i in other)) {
difference.push(i);
}
}
return difference;
}

exports.pluck = function pluck(arr, prop) {
return arr.map(function(el) {
return el[prop];
Expand Down

0 comments on commit 5c36053

Please sign in to comment.