From 81f5c04ac8f49670f43cf19d4eb197bcadd51604 Mon Sep 17 00:00:00 2001 From: Jon Atkins Date: Mon, 10 Jun 2013 16:52:01 +0100 Subject: [PATCH 1/3] overhaul of the max-links plugin - rather than drawing each triangle completely, draw each edge just once. prevents overdraw - use dashed lines for edges - allows existing links to be seen - change to calculate on lat/lng directly, rather than the odd offset-to-positive latE6/lngE6 used before - change the event used for detecting portals added to map - was using one fired before portals added to the map before --- plugins/max-links.user.js | 93 ++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/plugins/max-links.user.js b/plugins/max-links.user.js index 5184a20c..eddda059 100644 --- a/plugins/max-links.user.js +++ b/plugins/max-links.user.js @@ -2,7 +2,7 @@ // @id max-links@boombuler // @name IITC plugin: Max Links // @category Layer -// @version 0.3.1.@@DATETIMEVERSION@@ +// @version 0.4.0.@@DATETIMEVERSION@@ // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@ // @description [@@BUILDNAME@@-@@BUILDDATE@@] Calculates how to link the portals to create the maximum number of fields. Enable from the layer chooser. @@ -30,15 +30,24 @@ window.plugin.maxLinks.MAX_DRAWN_LINKS_INCREASED_LIMIT = 1000; window.plugin.maxLinks.STROKE_STYLE = { color: '#FF0000', opacity: 1, - weight:2, + weight: 2, clickable: false, - smoothFactor: 10 + dashArray: [8,6], + smoothFactor: 10, }; window.plugin.maxLinks.layer = null; window.plugin.maxLinks._updating = false; window.plugin.maxLinks._renderLimitReached = false; +window.plugin.maxLinks.Point = function(x,y) { + this.x=x; + this.y=y; +} +window.plugin.maxLinks.Point.prototype.toString = function() { + return this.x+","+this.y; +} + window.plugin.maxLinks.updateLayer = function() { if (window.plugin.maxLinks._updating || window.plugin.maxLinks.layer === null || @@ -48,36 +57,62 @@ window.plugin.maxLinks.updateLayer = function() { window.plugin.maxLinks.layer.clearLayers(); var locations = []; - var minX = 0; - var minY = 0; $.each(window.portals, function(guid, portal) { var loc = portal.options.details.locationE6; - var nloc = { x: loc.lngE6, y: loc.latE6 }; - if (nloc.x < minX) - minX = nloc.x; - if (nloc.y < minY) - minY = nloc.y; + var nloc = new window.plugin.maxLinks.Point(loc.latE6/1E6, loc.lngE6/1E6); locations.push(nloc); }); - $.each(locations, function(idx, nloc) { - nloc.x += Math.abs(minX); - nloc.y += Math.abs(minY); - }); - var triangles = window.delaunay.triangulate(locations); - var drawnLinks = 0; + + var drawnLinkCount = 0; window.plugin.maxLinks._renderLimitReached = false; - var renderlimit = window.USE_INCREASED_RENDER_LIMIT ? + var renderLimit = window.USE_INCREASED_RENDER_LIMIT ? window.plugin.maxLinks.MAX_DRAWN_LINKS_INCREASED_LIMIT : window.plugin.maxLinks.MAX_DRAWN_LINKS; + + var orderedPoints = function(a,b) { + if(a.x renderLimit ) { window.plugin.maxLinks._renderLimitReached = true; + return false; //$.each break } }); window.plugin.maxLinks._updating = false; @@ -89,17 +124,6 @@ window.plugin.maxLinks.setup = function() { @@INCLUDERAW:external/delaunay.js@@ try { console.log('done loading delaunay JS'); } catch(e) {} - window.delaunay.Triangle.prototype.draw = function(layer, divX, divY) { - var drawLine = function(src, dest) { - var poly = L.polyline([[(src.y + divY)/1E6, (src.x + divX)/1E6], [(dest.y + divY)/1E6, (dest.x + divX)/1E6]], window.plugin.maxLinks.STROKE_STYLE); - poly.addTo(layer); - }; - - drawLine(this.a, this.b); - drawLine(this.b, this.c); - drawLine(this.c, this.a); - } - window.plugin.maxLinks.layer = L.layerGroup([]); window.addHook('checkRenderLimit', function(e) { @@ -108,9 +132,8 @@ window.plugin.maxLinks.setup = function() { e.reached = true; }); - window.addHook('portalDataLoaded', function(e) { - if (window.map.hasLayer(window.plugin.maxLinks.layer)) - window.plugin.maxLinks.updateLayer(); + window.addHook('requestFinished', function(e) { + window.plugin.maxLinks.updateLayer(); }); window.map.on('layeradd', function(e) { From 0dc148dc9ee6c9b1566a083658777b59d7196ce6 Mon Sep 17 00:00:00 2001 From: Jon Atkins Date: Mon, 10 Jun 2013 22:25:59 +0100 Subject: [PATCH 2/3] add an empty div to the leaflet control areas, approximately matching the chat panel area this will allow leaflet controls placed bottomleft to appear above the chat bar --- code/boot.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/code/boot.js b/code/boot.js index 1277c6d8..e85cc24d 100644 --- a/code/boot.js +++ b/code/boot.js @@ -100,12 +100,6 @@ window.setupMap = function() { //OpenStreetMap attribution - required by several of the layers osmAttribution = 'Map data © OpenStreetMap contributors'; - - //CloudMade layers - only 500,000 tiles/month in their free plan. nowhere near enough for IITC - //var cmOpt = {attribution: osmAttribution+', Imagery © CloudMade', maxZoom: 18, detectRetina: true}; - //var cmMin = new L.TileLayer('http://{s}.tile.cloudmade.com/{your api key here}/22677/256/{z}/{x}/{y}.png', cmOpt); - //var cmMid = new L.TileLayer('http://{s}.tile.cloudmade.com/{your api key here}/999/256/{z}/{x}/{y}.png', cmOpt); - //MapQuest offer tiles - http://developer.mapquest.com/web/products/open/map //their usage policy has no limits (except required notification above 4000 tiles/sec - we're perhaps at 50 tiles/sec based on CloudMade stats) var mqSubdomains = [ 'otile1','otile2', 'otile3', 'otile4' ]; @@ -130,6 +124,13 @@ window.setupMap = function() { {zoomControl: window.showZoom} )); + // add empty div to leaflet control areas - to force other leaflet controls to move around IITC UI elements + // TODO? move the actual IITC DOM into the leaflet control areas, so dummy
s aren't needed + if(!isSmartphone()) { + // chat window area + $(window.map._controlCorners['bottomleft']).append($('
').width(708).height(108).addClass('leaflet-control').css('margin','0')); + } + var addLayers = {}; var hiddenLayer = []; From 740f13a2877c063040b688daca6b3c7db3ca349a Mon Sep 17 00:00:00 2001 From: Jon Atkins Date: Mon, 10 Jun 2013 22:27:17 +0100 Subject: [PATCH 3/3] minimap plugin - display a small map in the corner of the screen --- external/Control.MiniMap.css | 31 +++++ external/Control.MiniMap.js | 243 +++++++++++++++++++++++++++++++++++ images/minimap-toggle.png | Bin 0 -> 560 bytes plugins/minimap.user.js | 71 ++++++++++ 4 files changed, 345 insertions(+) create mode 100644 external/Control.MiniMap.css create mode 100644 external/Control.MiniMap.js create mode 100644 images/minimap-toggle.png create mode 100644 plugins/minimap.user.js diff --git a/external/Control.MiniMap.css b/external/Control.MiniMap.css new file mode 100644 index 00000000..c558467f --- /dev/null +++ b/external/Control.MiniMap.css @@ -0,0 +1,31 @@ +.leaflet-control-minimap { + border:solid rgba(255, 255, 255, 0.7) 3px; + box-shadow: 0 1px 7px #999; + background: #f8f8f9; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} + +.leaflet-control-minimap a { + background-color: rgba(255, 255, 255, 0.75); + background-position: 1px 2px; + background-repeat: no-repeat; + display: block; + outline: none; + z-index: 99999; +} + +.leaflet-control-minimap a.minimized { + background-position: 1px -18px; +} + +.leaflet-control-minimap-toggle-display { + background-image: url(@@INCLUDEIMAGE:images/minimap-toggle.png@@); + border-radius: 4px 4px 4px 4px; + height: 19px; + width: 19px; + position: absolute; + bottom: 0; + right: 0; +} diff --git a/external/Control.MiniMap.js b/external/Control.MiniMap.js new file mode 100644 index 00000000..db912307 --- /dev/null +++ b/external/Control.MiniMap.js @@ -0,0 +1,243 @@ +L.Control.MiniMap = L.Control.extend({ + options: { + position: 'bottomright', + toggleDisplay: false, + zoomLevelOffset: -5, + zoomLevelFixed: false, + zoomAnimation: false, + autoToggleDisplay: false, + width: 150, + height: 150 + }, + + hideText: 'Hide MiniMap', + + showText: 'Show MiniMap', + + //layer is the map layer to be shown in the minimap + initialize: function (layer, options) { + L.Util.setOptions(this, options); + this._layer = layer; + }, + + onAdd: function (map) { + + this._mainMap = map; + + //Creating the container and stopping events from spilling through to the main map. + this._container = L.DomUtil.create('div', 'leaflet-control-minimap'); + this._container.style.width = this.options.width + 'px'; + this._container.style.height = this.options.height + 'px'; + L.DomEvent.disableClickPropagation(this._container); + L.DomEvent.on(this._container, 'mousewheel', L.DomEvent.stopPropagation); + + + this._miniMap = new L.Map(this._container, + { + attributionControl: false, + zoomControl: false, + zoomAnimation: this.options.zoomAnimation, + autoToggleDisplay: this.options.autoToggleDisplay, + touchZoom: !this.options.zoomLevelFixed, + scrollWheelZoom: !this.options.zoomLevelFixed, + doubleClickZoom: !this.options.zoomLevelFixed, + boxZoom: !this.options.zoomLevelFixed, + crs: map.options.crs + }); + + this._miniMap.addLayer(this._layer); + + //These bools are used to prevent infinite loops of the two maps notifying each other that they've moved. + this._mainMapMoving = false; + this._miniMapMoving = false; + + //Keep a record of this to prevent auto toggling when the user explicitly doesn't want it. + this._userToggledDisplay = false; + this._minimized = false; + + if (this.options.toggleDisplay) { + this._addToggleButton(); + } + + this._miniMap.whenReady(L.Util.bind(function () { + this._aimingRect = L.rectangle(this._mainMap.getBounds(), {color: "#ff7800", weight: 1, clickable: false}).addTo(this._miniMap); + this._shadowRect = L.rectangle(this._mainMap.getBounds(), {color: "#000000", weight: 1, clickable: false,opacity:0,fillOpacity:0}).addTo(this._miniMap); + this._mainMap.on('moveend', this._onMainMapMoved, this); + this._mainMap.on('move', this._onMainMapMoving, this); + this._miniMap.on('movestart', this._onMiniMapMoveStarted, this); + this._miniMap.on('move', this._onMiniMapMoving, this); + this._miniMap.on('moveend', this._onMiniMapMoved, this); + }, this)); + + return this._container; + }, + + addTo: function (map) { + L.Control.prototype.addTo.call(this, map); + this._miniMap.setView(this._mainMap.getCenter(), this._decideZoom(true)); + this._setDisplay(this._decideMinimized()); + return this; + }, + + onRemove: function (map) { + this._mainMap.off('moveend', this._onMainMapMoved, this); + this._mainMap.off('move', this._onMainMapMoving, this); + this._miniMap.off('moveend', this._onMiniMapMoved, this); + + this._miniMap.removeLayer(this._layer); + }, + + _addToggleButton: function () { + this._toggleDisplayButton = this.options.toggleDisplay ? this._createButton( + '', this.hideText, 'leaflet-control-minimap-toggle-display', this._container, this._toggleDisplayButtonClicked, this) : undefined; + }, + + _createButton: function (html, title, className, container, fn, context) { + var link = L.DomUtil.create('a', className, container); + link.innerHTML = html; + link.href = '#'; + link.title = title; + + var stop = L.DomEvent.stopPropagation; + + L.DomEvent + .on(link, 'click', stop) + .on(link, 'mousedown', stop) + .on(link, 'dblclick', stop) + .on(link, 'click', L.DomEvent.preventDefault) + .on(link, 'click', fn, context); + + return link; + }, + + _toggleDisplayButtonClicked: function () { + this._userToggledDisplay = true; + if (!this._minimized) { + this._minimize(); + this._toggleDisplayButton.title = this.showText; + } + else { + this._restore(); + this._toggleDisplayButton.title = this.hideText; + } + }, + + _setDisplay: function (minimize) { + if (minimize != this._minimized) { + if (!this._minimized) { + this._minimize(); + } + else { + this._restore(); + } + } + }, + + _minimize: function () { + // hide the minimap + if (this.options.toggleDisplay) { + this._container.style.width = '19px'; + this._container.style.height = '19px'; + this._toggleDisplayButton.className += ' minimized'; + } + else { + this._container.style.display = 'none'; + } + this._minimized = true; + }, + + _restore: function () { + if (this.options.toggleDisplay) { + this._container.style.width = this.options.width + 'px'; + this._container.style.height = this.options.height + 'px'; + this._toggleDisplayButton.className = this._toggleDisplayButton.className + .replace(/(?:^|\s)minimized(?!\S)/g, ''); + } + else { + this._container.style.display = 'block'; + } + this._minimized = false; + }, + + _onMainMapMoved: function (e) { + if (!this._miniMapMoving) { + this._mainMapMoving = true; + this._miniMap.setView(this._mainMap.getCenter(), this._decideZoom(true)); + this._setDisplay(this._decideMinimized()); + } else { + this._miniMapMoving = false; + } + this._aimingRect.setBounds(this._mainMap.getBounds()); + }, + + _onMainMapMoving: function (e) { + this._aimingRect.setBounds(this._mainMap.getBounds()); + }, + + _onMiniMapMoveStarted:function (e) { + var lastAimingRect = this._aimingRect.getBounds(); + var sw = this._miniMap.latLngToContainerPoint(lastAimingRect.getSouthWest()); + var ne = this._miniMap.latLngToContainerPoint(lastAimingRect.getNorthEast()); + this._lastAimingRectPosition = {sw:sw,ne:ne}; + }, + + _onMiniMapMoving: function (e) { + if (!this._mainMapMoving && this._lastAimingRectPosition) { + this._shadowRect.setBounds(new L.LatLngBounds(this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.sw),this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.ne))); + this._shadowRect.setStyle({opacity:1,fillOpacity:0.3}); + } + }, + + _onMiniMapMoved: function (e) { + if (!this._mainMapMoving) { + this._miniMapMoving = true; + this._mainMap.setView(this._miniMap.getCenter(), this._decideZoom(false)); + this._shadowRect.setStyle({opacity:0,fillOpacity:0}); + } else { + this._mainMapMoving = false; + } + }, + + _decideZoom: function (fromMaintoMini) { + if (!this.options.zoomLevelFixed) { + if (fromMaintoMini) + return this._mainMap.getZoom() + this.options.zoomLevelOffset; + else + return this._miniMap.getZoom() - this.options.zoomLevelOffset; + } else { + if (fromMaintoMini) + return this.options.zoomLevelFixed; + else + return this._mainMap.getZoom(); + } + }, + + _decideMinimized: function () { + if (this._userToggledDisplay) { + return this._minimized; + } + + if (this.options.autoToggleDisplay) { + if (this._mainMap.getBounds().contains(this._miniMap.getBounds())) { + return true; + } + return false; + } + + return this._minimized; + } +}); + +L.Map.mergeOptions({ + miniMapControl: false +}); + +L.Map.addInitHook(function () { + if (this.options.miniMapControl) { + this.miniMapControl = (new L.Control.MiniMap()).addTo(this); + } +}); + +L.control.minimap = function (options) { + return new L.Control.MiniMap(options); +}; diff --git a/images/minimap-toggle.png b/images/minimap-toggle.png new file mode 100644 index 0000000000000000000000000000000000000000..026d4c8bbc37882a9b685b7a685917b0651aadf2 GIT binary patch literal 560 zcmV-00?+-4P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*Y> z00=daXO&d|00FQ`L_t(Y$L-ZWOCv!T2Jm-XS&Pe_780^@R>Dg-F!&F<183lhkmkz! z0M}S62Zy}}#xD^37_tN*nY?0kSh*m?fyi~UOb`xstA%B3A{>&9yRpzBPdV`Z28MZN z0A`sg#u(cevruGaZroxJ1mC*d?zz_bL&io6xuD^2csLjgzWTm@8HVBVGh~g3&T>Ju zT8$jXfh0+`g%B4?spS!}N<Pacr#?8!U z9bTnUIZ{gf6GEKCas1i${Xc1%7CY>xc%IkfoRe+aFbR1PGRB}1T{%xXK!yN)%XA{GEFjcT+A05$-81b_$2vi|0RTCJAJ@HHZS zVT{Q_?SGaBMC9X;B2a{gb;j83RPWJKY}>x8R;zOAhi!yJX`1c`A+D5CpQeHk@n@sa z*esPw!#IxDd%fOu7>3)0AVfT7j5R&a8*t9QyRMr=QB-NS+g+{oPA&)$e>298{`&+3 y=lqA`I3`Jw`ydGJUUhr5*881KXJyvoH_jtgYr?XBn0V0u0000@@INCLUDESTRING:external/Control.MiniMap.css@@'); + + +}; + +var setup = window.plugin.miniMap.setup; + +// PLUGIN END ////////////////////////////////////////////////////////// + +if(window.iitcLoaded && typeof setup === 'function') { + setup(); +} else { + if(window.bootPlugins) + window.bootPlugins.push(setup); + else + window.bootPlugins = [setup]; +} +} // wrapper end +// inject code into site context +var script = document.createElement('script'); +script.appendChild(document.createTextNode('('+ wrapper +')();')); +(document.body || document.head || document.documentElement).appendChild(script);