From 55c055425b6b3c36693a8f1f15db0874ce2fed77 Mon Sep 17 00:00:00 2001 From: Inye Date: Fri, 2 Aug 2013 20:00:03 +0400 Subject: [PATCH 1/3] Avoid using Object.keys(obj).length in hot code paths Complexity of Object.keys(obj).length is O(n) where n is the number of object keys. Unfortunately, JavaScript have no built-in means of determining number of object keys in constant time. Therefore, we have to count object keys using separate counter variable. It may look ugly (and indeed it is), but it greatly improves smoothness and overall feel of IITC. --- code/debugging.js | 6 +++--- code/map_data.js | 20 +++++++++++++++----- code/portal_render_limit.js | 5 ++++- code/utils_misc.js | 6 +++--- main.js | 3 +++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/code/debugging.js b/code/debugging.js index f688e292..af0bf775 100644 --- a/code/debugging.js +++ b/code/debugging.js @@ -5,9 +5,9 @@ window.debug = function() {} window.debug.renderDetails = function() { - console.log('portals: ' + Object.keys(portals).length); - console.log('links: ' + Object.keys(links).length); - console.log('fields: ' + Object.keys(fields).length); + console.log('portals: ' + window.portalsCount); + console.log('links: ' + window.linksCount); + console.log('fields: ' + window.fieldsCount); } window.debug.printStackTrace = function() { diff --git a/code/map_data.js b/code/map_data.js index a709fdf6..de643823 100644 --- a/code/map_data.js +++ b/code/map_data.js @@ -572,7 +572,7 @@ window.getMarker = function(ent, portalLevel, latlng, team) { // renders a portal on the map from the given entity window.renderPortal = function(ent) { - if(Object.keys(portals).length >= MAX_DRAWN_PORTALS && ent[0] !== selectedPortal) + if(window.portalsCount >= MAX_DRAWN_PORTALS && ent[0] !== selectedPortal) return removeByGuid(ent[0]); // hide low level portals on low zooms @@ -633,6 +633,7 @@ window.renderPortal = function(ent) { removeByGuid(portalResonatorGuid(portalGuid, i)); } delete window.portals[portalGuid]; + window.portalsCount --; if(window.selectedPortal === portalGuid) { window.unselectOldPortal(); } @@ -642,6 +643,7 @@ window.renderPortal = function(ent) { // enable for debugging if(window.portals[this.options.guid]) throw('duplicate portal detected'); window.portals[this.options.guid] = this; + window.portalsCount ++; window.renderResonators(this.options.guid, this.options.details, this); // handles the case where a selected portal gets removed from the @@ -781,7 +783,7 @@ window.resonatorsSetStyle = function(portalGuid, resoStyle, lineStyle) { // renders a link on the map from the given entity window.renderLink = function(ent) { - if(Object.keys(links).length >= MAX_DRAWN_LINKS) + if(window.linksCount >= MAX_DRAWN_LINKS) return removeByGuid(ent[0]); // some links are constructed from portal linkedEdges data. These have no valid 'creator' data. @@ -823,11 +825,15 @@ window.renderLink = function(ent) { if(!getPaddedBounds().intersects(poly.getBounds())) return; - poly.on('remove', function() { delete window.links[this.options.guid]; }); + poly.on('remove', function() { + delete window.links[this.options.guid]; + window.linksCount--; + }); poly.on('add', function() { // enable for debugging if(window.links[this.options.guid]) throw('duplicate link detected'); window.links[this.options.guid] = this; + window.linksCount++; this.bringToBack(); }); poly.addTo(linksLayer); @@ -835,7 +841,7 @@ window.renderLink = function(ent) { // renders a field on the map from a given entity window.renderField = function(ent) { - if(Object.keys(fields).length >= MAX_DRAWN_FIELDS) + if(window.fieldsCount >= MAX_DRAWN_FIELDS) return window.removeByGuid(ent[0]); var old = findEntityInLeaflet(fieldsLayer, window.fields, ent[0]); @@ -921,11 +927,15 @@ window.renderField = function(ent) { // events, thus this listener will be attached to the field. It // doesn’t matter to which element these are bound since Leaflet // will add/remove all elements of the LayerGroup at once. - poly.on('remove', function() { delete window.fields[this.options.guid]; }); + poly.on('remove', function() { + delete window.fields[this.options.guid]; + window.fieldsCount--; + }); poly.on('add', function() { // enable for debugging if(window.fields[this.options.guid]) console.warn('duplicate field detected'); window.fields[this.options.guid] = f; + window.fieldsCount++; this.bringToBack(); }); f.addTo(fieldsLayer); diff --git a/code/portal_render_limit.js b/code/portal_render_limit.js index 98a31095..65f42ddd 100644 --- a/code/portal_render_limit.js +++ b/code/portal_render_limit.js @@ -41,6 +41,7 @@ window.portalRenderLimit.previousMinLevel = -1; window.portalRenderLimit.previousZoomLevel = null; window.portalRenderLimit.newPortalsPerLevel = new Array(MAX_PORTAL_LEVEL + 1); window.portalRenderLimit.portalsLowerThanPrevMinLv = new Array(MAX_PORTAL_LEVEL + 1); +window.portalRenderLimit.portalsLowerThanPrevMinLvCnt = new Array(MAX_PORTAL_LEVEL + 1); window.portalRenderLimit.init = function () { var currentZoomLevel = map.getZoom(); @@ -72,6 +73,7 @@ window.portalRenderLimit.resetCounting = function() { window.portalRenderLimit.resetPortalsLowerThanPrevMinLv = function() { for(var i = 0; i <= MAX_PORTAL_LEVEL; i++) { portalRenderLimit.portalsLowerThanPrevMinLv[i] = {}; + portalRenderLimit.portalsLowerThanPrevMinLvCnt[i] = 0; } } @@ -125,6 +127,7 @@ window.portalRenderLimit.splitLowLevelPortals = function(portals) { if(!portalOnMap && portalLevel < portalRenderLimit.previousMinLevel) { portalRenderLimit.portalsLowerThanPrevMinLv[portalLevel][guid] = portal; + portalRenderLimit.portalsLowerThanPrevMinLvCnt[portalLevel]++; } else { resultPortals[guid] = portal; } @@ -158,7 +161,7 @@ window.portalRenderLimit.setMinLevel = function() { // Find the min portal level under render limit while(newMinLevel > 0) { var oldPortalCount = layerGroupLength(portalsLayers[newMinLevel - 1]); - var storedPortalCount = Object.keys(portalRenderLimit.portalsLowerThanPrevMinLv[newMinLevel - 1]).length; + var storedPortalCount = portalRenderLimit.portalsLowerThanPrevMinLvCnt[newMinLevel - 1]; var newPortalCount = Math.max(storedPortalCount, portalRenderLimit.newPortalsPerLevel[newMinLevel - 1]); totalPortalsCount += oldPortalCount + newPortalCount; diff --git a/code/utils_misc.js b/code/utils_misc.js index b40fba62..4e118b78 100644 --- a/code/utils_misc.js +++ b/code/utils_misc.js @@ -245,9 +245,9 @@ window.getPaddedBounds = function() { // cally detect if the render limit will be hit. window.renderLimitReached = function(ratio) { ratio = ratio || 1; - if(Object.keys(portals).length*ratio >= MAX_DRAWN_PORTALS) return true; - if(Object.keys(links).length*ratio >= MAX_DRAWN_LINKS) return true; - if(Object.keys(fields).length*ratio >= MAX_DRAWN_FIELDS) return true; + if(window.portalsCount*ratio >= MAX_DRAWN_PORTALS) return true; + if(window.linksCount*ratio >= MAX_DRAWN_LINKS) return true; + if(window.fieldsCount*ratio >= MAX_DRAWN_FIELDS) return true; var param = { 'reached': false }; window.runHooks('checkRenderLimit', param); return param.reached; diff --git a/main.js b/main.js index 90d7bc05..e783d772 100644 --- a/main.js +++ b/main.js @@ -250,8 +250,11 @@ var portalsLayers, linksLayer, fieldsLayer; // automatically kept in sync with the items on *sLayer, so never ever // write to them. window.portals = {}; +window.portalsCount = 0; window.links = {}; +window.linksCount = 0; window.fields = {}; +window.fieldsCount = 0; window.resonators = {}; // contain current status(on/off) of overlay layerGroups. From e9da0150f5dd6ce734bc5627d97e142690c275ec Mon Sep 17 00:00:00 2001 From: Jon Atkins Date: Fri, 2 Aug 2013 18:33:00 +0100 Subject: [PATCH 2/3] fix website typo --- website/page/home.php | 2 +- website/page/news.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/page/home.php b/website/page/home.php index 126427e5..b6756d0a 100644 --- a/website/page/home.php +++ b/website/page/home.php @@ -32,7 +32,7 @@ Important IITC release 0.13.0, to fix enlightened from showing up as the wrong c
  • IPAS plugin updated. This had been done earlier on desktop, but not mobile
  • Plugins
      -
    • Update mod highlither plugin
    • +
    • Update mod highlighter plugin
    • Portals list plugin updates
  • plus various other tweaks, bug fixes, etc
  • diff --git a/website/page/news.php b/website/page/news.php index a43c39c3..9313b184 100644 --- a/website/page/news.php +++ b/website/page/news.php @@ -19,7 +19,7 @@ Important IITC release 0.13.0, to fix enlightened from showing up as the wrong c
  • IPAS plugin updated. This had been done earlier on desktop, but not mobile
  • Plugins
      -
    • Update mod highlither plugin
    • +
    • Update mod highlighter plugin
    • Portals list plugin updates
  • plus various other tweaks, bug fixes, etc
  • From 124242ed861f81e0a9660e2a8d75a3a9c7c89541 Mon Sep 17 00:00:00 2001 From: Jon Atkins Date: Sat, 3 Aug 2013 05:52:52 +0100 Subject: [PATCH 3/3] draw tools - first pass at saving/loading drawn items in localStorage --- plugins/draw-tools.user.js | 123 ++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 7 deletions(-) diff --git a/plugins/draw-tools.user.js b/plugins/draw-tools.user.js index e26b1131..75bb0138 100644 --- a/plugins/draw-tools.user.js +++ b/plugins/draw-tools.user.js @@ -2,7 +2,7 @@ // @id iitc-plugin-draw-tools@breunigs // @name IITC plugin: draw tools // @category Layer -// @version 0.4.1.@@DATETIMEVERSION@@ +// @version 0.5.0.@@DATETIMEVERSION@@ // @namespace https://github.com/jonatkins/ingress-intel-total-conversion // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@ @@ -32,6 +32,33 @@ window.plugin.drawTools.loadExternals = function() { $('head').append(''); } +window.plugin.drawTools.setOptions = function() { + window.plugin.drawTools.lineOptions = { + stroke: true, + color: '#f06eaa', + weight: 4, + opacity: 0.5, + fill: false, + clickable: true + }; + + window.plugin.drawTools.polygonOptions = { + stroke: true, + color: '#f06eaa', + weight: 4, + opacity: 0.5, + fill: true, + fillColor: null, + fillOpacity: 0.2, + clickable: true + }; + + window.plugin.drawTools.markerOptions = { + icon: new L.Icon.Default(), + zIndexOffset: 2000 + }; + +} // renders the draw control buttons in the top left corner @@ -45,7 +72,8 @@ window.plugin.drawTools.addDrawControl = function() { + 'define the start of the polygon. Continue clicking\n' + 'to draw the line you want. Click the first or last\n' + 'point of the line (a small white rectangle) to\n' - + 'finish. Double clicking also works.' + + 'finish. Double clicking also works.', + shapeOptions: window.plugin.drawTools.polygonOptions, }, polyline: { @@ -54,7 +82,8 @@ window.plugin.drawTools.addDrawControl = function() { + 'define the start of the line. Continue clicking\n' + 'to draw the line you want. Click the last\n' + 'point of the line (a small white rectangle) to\n' - + 'finish. Double clicking also works.' + + 'finish. Double clicking also works.', + shapeOptions: window.plugin.drawTools.lineOptions, }, circle: { @@ -62,13 +91,15 @@ window.plugin.drawTools.addDrawControl = function() { + 'Click on the button, then click-AND-HOLD on the\n' + 'map where the circle’s center should be. Move\n' + 'the mouse to control the radius. Release the mouse\n' - + 'to finish.' + + 'to finish.', + shapeOptions: window.plugin.drawTools.polygonOptions, }, marker: { title: 'Add a marker.\n\n' + 'Click on the button, then click on the map where\n' - + 'you want the marker to appear.' + + 'you want the marker to appear.', + shapeOptions: window.plugin.drawTools.markerOptions, }, }, @@ -114,11 +145,79 @@ window.plugin.drawTools.getSnapLatLng = function(containerPoint) { } -window.plugin.drawTools.boot = function() { - //create a leaflet FeatureGroup to hold drawn items +window.plugin.drawTools.save = function() { + var data = []; + window.plugin.drawTools.drawnItems.eachLayer( function(layer) { + var item = {}; + if (layer instanceof L.GeodesicCircle || layer instanceof L.Circle) { + item.type = 'circle'; + item.latLng = layer.getLatLng(); + item.radius = layer.getRadius(); + } else if (layer instanceof L.GeodesicPolygon || layer instanceof L.Polygon) { + item.type = 'polygon'; + item.latLngs = layer.getLatLngs(); + } else if (layer instanceof L.GeodesicPolyline || layer instanceof L.Polyline) { + item.type = 'polyline'; + item.latLngs = layer.getLatLngs(); + } else if (layer instanceof L.Marker) { + item.type = 'marker'; + item.latLng = layer.getLatLng(); + } else { + console.warn('Unknown layer type when saving draw tools layer'); + return; //.eachLayer 'continue' + } + + data.push(item); + }); + + localStorage['plugin-draw-tools-layer'] = JSON.stringify(data); + + console.log('draw-tools: saved to localStorage'); +} + +window.plugin.drawTools.load = function() { + var dataStr = localStorage['plugin-draw-tools-layer']; + if (dataStr === undefined) return; + + var data = JSON.parse(dataStr); + $.each(data, function(index,item) { + var layer = null; + switch(item.type) { + case 'polyline': + layer = L.geodesicPolyline(item.latLngs,window.plugin.drawTools.lineOptions); + break; + case 'polygon': + layer = L.geodesicPolygon(item.latLngs,window.plugin.drawTools.polygonOptions); + break; + case 'circle': + layer = L.circle(item.latLng,item.radius,window.plugin.drawTools.polygonOptions); + break; + case 'marker': + layer = L.marker(item.latLng,window.plugin.drawTools.markerOptions) + break; + default: + console.warn('unknown layer type "'+item.type+'" when loading draw tools layer'); + break; + } + if (layer) { + window.plugin.drawTools.drawnItems.addLayer(layer); + } + + }); + +} + + +window.plugin.drawTools.boot = function() { + window.plugin.drawTools.setOptions(); + + //create a leaflet FeatureGroup to hold drawn items window.plugin.drawTools.drawnItems = new L.FeatureGroup(); + //load any previously saved items + plugin.drawTools.load(); + //add the draw control - this references the above FeatureGroup for editing purposes plugin.drawTools.addDrawControl(); @@ -147,8 +246,18 @@ window.plugin.drawTools.boot = function() { var type=e.layerType; var layer=e.layer; window.plugin.drawTools.drawnItems.addLayer(layer); + window.plugin.drawTools.save(); }); + map.on('draw:deleted', function(e) { + window.plugin.drawTools.save(); + }); + + map.on('draw:edited', function(e) { + window.plugin.drawTools.save(); + }); + + }