From 98265766ecf3916ed8b1172228445eb9cb795600 Mon Sep 17 00:00:00 2001 From: Jon Atkins Date: Tue, 3 Sep 2013 16:24:21 +0100 Subject: [PATCH] limit portals drawn to the map in dense areas, to avoid slowing down leaflet too much unfortunately, this wasn't as much of a speed boost as i'd hoped. just downloading/processing the data for 20,000+ portals from the server, even if only 2000 are displayed, still takes a LONG time for #526 --- code/map_data_render.js | 114 +++++++++++++++++++++++++++++++++++---- code/map_data_request.js | 4 ++ 2 files changed, 108 insertions(+), 10 deletions(-) diff --git a/code/map_data_render.js b/code/map_data_render.js index 267bce45..db34d26e 100644 --- a/code/map_data_render.js +++ b/code/map_data_render.js @@ -7,7 +7,13 @@ window.Render = function() { // below this many portals displayed, we reorder the SVG at the end of the render pass to put portals above fields/links this.LOW_PORTAL_COUNT = 350; + // when there are lots of portals close together, we only add some of them to the map + // the idea is to keep the impression of the dense set of portals, without rendering them all + this.CLUSTER_SIZE = 8; // the map is divited into squares of this size in pixels for clustering purposes + this.CLUSTER_PORTAL_LIMIT = 4; // no more than this many portals are drawn in each cluster square + + this.currentPortalClusterZoom = undefined; } @@ -85,7 +91,7 @@ window.Render.prototype.processDeletedGameEntityGuids = function(deleted) { } window.Render.prototype.processGameEntities = function(entities) { - var portalGuids = []; +// var portalGuids = []; for (var i in entities) { var ent = entities[i]; @@ -93,12 +99,12 @@ window.Render.prototype.processGameEntities = function(entities) { // don't create entities in the 'deleted' list if (!(ent[0] in this.deletedGuid)) { this.createEntity(ent); - if ('portalV2' in ent[2]) portalGuids.push(ent[0]); +// if ('portalV2' in ent[2]) portalGuids.push(ent[0]); } } - // now reconstruct links 'optimised' out of the data from the portal link data - this.createLinksFromPortalData(portalGuids); +// // now reconstruct links 'optimised' out of the data from the portal link data +// this.createLinksFromPortalData(portalGuids); } @@ -137,6 +143,7 @@ window.Render.prototype.endRenderPass = function() { } this.isRendering = false; + } @@ -150,9 +157,7 @@ window.Render.prototype.deleteEntity = function(guid) { window.Render.prototype.deletePortalEntity = function(guid) { if (guid in window.portals) { var p = window.portals[guid]; - for(var i in portalsLayers) { - portalsLayers[i].removeLayer(p); - } + this.removePortalFromMapLayer(p); delete window.portals[guid]; } } @@ -304,10 +309,10 @@ window.Render.prototype.createPortalEntity = function(ent) { renderPortalDetails (selectedPortal); } - //TODO? postpone adding to the map layer - portalsLayers[parseInt(portalLevel)].addLayer(marker); - +// //TODO? postpone adding to the map layer +// portalsLayers[parseInt(portalLevel)].addLayer(marker); + this.addPortalToMapLayer(marker); } @@ -466,3 +471,92 @@ window.Render.prototype.createLinksFromPortalData = function(portalGuids) { } } } + + + +// portal clustering functionality + +window.Render.prototype.resetPortalClusters = function() { + if (this.currentPortalClusterZoom === undefined || this.currentPortalClusterZoom != map.getZoom()) { + + this.portalClusters = {}; + this.currentPortalClusterZoom = map.getZoom(); + + // first, place the portals into the clusters + for (var pguid in window.portals) { + var p = window.portals[pguid]; + var cid = this.getPortalClusterID(p); + + if (!(cid in this.portalClusters)) this.portalClusters[cid] = []; + + this.portalClusters[cid].push(p.options.guid); + } + + // now, for each cluster, sort by some arbitary data (the guid will do), and display the first CLUSTER_PORTAL_LIMIT + for (var cid in this.portalClusters) { + var c = this.portalClusters[cid]; + + c.sort(); + + for (var i=0; i= 0) { + this.portalClusters[cid].splice(index,1); + // FIXME? if this portal was in on the screen (in the first 10), and we still have 10+ portals, add the new 10to to the screen? + } + } +} + +window.Render.prototype.getPortalClusterID = function(portal) { + // project the lat/lng into absolute map pixels + var z = map.getZoom(); + + var point = map.project(portal.getLatLng(), z); + + var clusterpoint = point.divideBy(this.CLUSTER_SIZE).round(); + + return z+":"+clusterpoint.x+":"+clusterpoint.y; +} diff --git a/code/map_data_request.js b/code/map_data_request.js index 0b67b268..625aa191 100644 --- a/code/map_data_request.js +++ b/code/map_data_request.js @@ -147,6 +147,7 @@ window.MapDataRequest.prototype.refresh = function() { this.render.startRenderPass(); this.render.clearPortalsBelowLevel(minPortalLevel); + // calculate the full bounds for the data - including the part of the tiles off the screen edge var dataBounds = L.latLngBounds([ [tileToLat(y2+1,zoom), tileToLng(x1,zoom)], @@ -156,6 +157,9 @@ window.MapDataRequest.prototype.refresh = function() { //setTimeout (function(){ map.removeLayer(debugrect2); }, 10*1000); this.render.clearEntitiesOutsideBounds(dataBounds); + this.render.resetPortalClusters(); + + console.log('requesting data tiles at zoom '+zoom+' (L'+minPortalLevel+'+ portals), map zoom is '+map.getZoom());