diff --git a/web/css/dynmap_style.css b/web/css/dynmap_style.css index fe5be88f..b9d4785b 100644 --- a/web/css/dynmap_style.css +++ b/web/css/dynmap_style.css @@ -1,3 +1,10 @@ +/* DEBUGGING */ +.leaflet-tile { + margin: -1; + border: 1px solid red; +} + + /******************* * Page setup */ @@ -39,13 +46,6 @@ margin-left:-20px } -/* Google branding */ - -.dynmap > div.map > DIV > DIV:first-child + DIV, -.dynmap > div.map > DIV > DIV:first-child + DIV + DIV { - visibility: hidden !important; -} - /******************* * Alerts are pretty. @@ -705,4 +705,4 @@ } .infowindow { color:black; -} \ No newline at end of file +} diff --git a/web/images/layers.png b/web/images/layers.png new file mode 100644 index 00000000..9be965fc Binary files /dev/null and b/web/images/layers.png differ diff --git a/web/images/marker-shadow.png b/web/images/marker-shadow.png new file mode 100644 index 00000000..a64f6a67 Binary files /dev/null and b/web/images/marker-shadow.png differ diff --git a/web/images/marker.png b/web/images/marker.png new file mode 100644 index 00000000..bef032e6 Binary files /dev/null and b/web/images/marker.png differ diff --git a/web/images/popup-close.png b/web/images/popup-close.png new file mode 100644 index 00000000..c8faec5e Binary files /dev/null and b/web/images/popup-close.png differ diff --git a/web/images/zoom-in.png b/web/images/zoom-in.png new file mode 100644 index 00000000..9f473d64 Binary files /dev/null and b/web/images/zoom-in.png differ diff --git a/web/images/zoom-out.png b/web/images/zoom-out.png new file mode 100644 index 00000000..f0a5b5d6 Binary files /dev/null and b/web/images/zoom-out.png differ diff --git a/web/index.html b/web/index.html index a2d246f7..acafd42f 100644 --- a/web/index.html +++ b/web/index.html @@ -14,19 +14,24 @@ + + + + + + + + - - - - + diff --git a/web/js/custommarker.js b/web/js/custommarker.js index 81c6b4aa..e40c4640 100644 --- a/web/js/custommarker.js +++ b/web/js/custommarker.js @@ -1,90 +1,111 @@ -function CustomMarker(latlng, map, oncreated) { - google.maps.OverlayView.call(this); - - this.latlng_ = latlng; - - // Once the LatLng and text are set, add the overlay to the map. This will - // trigger a call to panes_changed which should in turn call draw. - this.setMap(map); - - this.oncreated = oncreated; -} +L.CustomMarker = L.Class.extend({ -CustomMarker.prototype = new google.maps.OverlayView(); - -CustomMarker.prototype.draw = function() { - var me = this; - if (this.removed) - return; - // Check if the div has been created. - var div = this.div_; - if (!div) { - // Create a overlay text DIV - div = this.div_ = document.createElement('DIV'); - // Create the DIV representing our CustomMarker - div.style.position = "absolute"; + includes: L.Mixin.Events, + + options: { + contentCreator: undefined, + shadowCreator: undefined, + clickable: true, + draggable: false + }, + + initialize: function(latlng, options) { + L.Util.setOptions(this, options); + this._latlng = latlng; + }, + + onAdd: function(map) { + this._map = map; - google.maps.event.addDomListener(div, "click", function(event) { - google.maps.event.trigger(me, "click"); - }); + if (!this._element && this.options.elementCreator) { + this._element = this.options.elementCreator(); + + + // TODO: Pass this fix to Leaflet-dev(s), it may be a bug in Leaflet. + this._element.style.position = 'absolute'; + + + this._initInteraction(); + } + if (!this._shadow && this.options.shadowCreator) { + this._shadow = this.options.shadowCreator(); + } - this.oncreated(div); + if (this._element) { + map._panes.markerPane.appendChild(this._element); + } + if (this._shadow) { + map._panes.shadowPane.appendChild(this._shadow); + } - // Then add the overlay to the DOM - var panes = this.getPanes(); - panes.overlayLayer.appendChild(div); - } + map.on('viewreset', this._reset, this); + this._reset(); + }, - // Position the overlay - var point = this.getProjection().fromLatLngToDivPixel(this.latlng_); - if (point) { - div.style.left = point.x + 'px'; - div.style.top = point.y + 'px'; - } -}; + onRemove: function(map) { + if (this._element) { + map._panes.markerPane.removeChild(this._element); + } + if (this._shadow) { + map._panes.shadowPane.removeChild(this._elementShadow); + } + + map.off('viewreset', this._reset, this); + }, + + getLatLng: function() { + return this._latlng; + }, + + setLatLng: function(latlng) { + this._latlng = latlng; + this._reset(); + }, + + _reset: function() { + var pos = this._map.latLngToLayerPoint(this._latlng); + + if (this._element) { + L.DomUtil.setPosition(this._element, pos); + } + if (this._shadow) { + L.DomUtil.setPosition(this._shadow, pos); + } + + if (this._element) { + this._element.style.zIndex = pos.y; + } + }, + + _initInteraction: function() { + if (this._element && this.options.clickable) { + this._element.className += ' leaflet-clickable'; + + L.DomEvent.addListener(this._element, 'click', this._onMouseClick, this); -CustomMarker.prototype.setPosition = function(p) { - this.latlng_ = p; - var projection = this.getProjection(); - if (projection) { - var point = projection.fromLatLngToDivPixel(this.latlng_); - this.div_.style.left = point.x + 'px'; - this.div_.style.top = point.y + 'px'; + var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout']; + for (var i = 0; i < events.length; i++) { + L.DomEvent.addListener(this._element, events[i], this._fireMouseEvent, this); + } + } + + if (this._element && L.Handler.MarkerDrag) { + this.dragging = new L.Handler.MarkerDrag(this); + + if (this.options.draggable) { + this.dragging.enable(); + } + } + }, + + _onMouseClick: function(e) { + L.DomEvent.stopPropagation(e); + if (this.dragging && this.dragging.moved()) { return; } + this.fire(e.type); + }, + + _fireMouseEvent: function(e) { + this.fire(e.type); + L.DomEvent.stopPropagation(e); } -}; - -CustomMarker.prototype.getPosition = function(p) { - return this.latlng_; -}; - -CustomMarker.prototype.hide = function() { - if (this.div_ && !this.isHidden) { - this.div_.style.display = 'none'; - this.isHidden = true; - } -} - -CustomMarker.prototype.show = function() { - if (this.div_ && this.isHidden) { - this.div_.style.display = 'block'; - this.isHidden = false; - } -} - -CustomMarker.prototype.toggle = function(t) { - if ((typeof t) == "boolean") { - if (t) { this.show(); } - else { this.hide(); } - } else { - this.toggle((this.isHidden) == true); - } -} - -CustomMarker.prototype.remove = function() { - // Check if the overlay was on the map and needs to be removed. - if (this.div_) { - this.div_.parentNode.removeChild(this.div_); - this.div_ = null; - this.removed = true; - } -}; +}); \ No newline at end of file diff --git a/web/js/dynmaputils.js b/web/js/dynmaputils.js new file mode 100644 index 00000000..f97f0964 --- /dev/null +++ b/web/js/dynmaputils.js @@ -0,0 +1,181 @@ +var DynmapProjection = L.Class.extend({ + fromLocationToLatLng: function(location) { + throw "fromLocationToLatLng not implemented"; + } +}); + +var DynmapTileLayer = L.TileLayer.extend({ + _currentzoom: undefined, + getProjection: function() { + return this.projection; + }, + onTileUpdated: function(tile, tileName) { + var src = this.dynmap.getTileUrl(tileName); + tile.attr('src', src); + tile.show(); + }, + + getTileName: function(tilePoint, zoom) { + throw "getTileName not implemented"; + }, + + getTileUrl: function(tilePoint, zoom) { + var tileName = this.getTileName(tilePoint, zoom); + var url = this._cachedTileUrls[tileName]; + if (!url) { + this._cachedTileUrls[tileName] = url = this.options.dynmap.getTileUrl(tileName) + '?' + new Date().getUTCMilliseconds(); + } + return url; + }, + + updateNamedTile: function(name) { + var tile = this._namedTiles[name]; + delete this._cachedTileUrls[name]; + if (tile) { + this.updateTile(tile); + } + }, + + updateTile: function(tile) { + this._loadTile(tile, tile.tilePoint, this._map.getZoom()); + }, + + // We should override this, since Leaflet does modulo on tilePoint by default. (https://github.com/CloudMade/Leaflet/blob/master/src/layer/tile/TileLayer.js#L151) + _addTile: function(tilePoint) { + var tilePos = this._getTilePos(tilePoint), + zoom = this._map.getZoom(), + key = tilePoint.x + ':' + tilePoint.y, + name = this.getTileName(tilePoint, zoom); + + // create tile + var tile = this._createTile(); + tile.tileName = name; + tile.tilePoint = tilePoint; + L.DomUtil.setPosition(tile, tilePos); + + this._tiles[key] = tile; + this._namedTiles[name] = tile; + + this._loadTile(tile, tilePoint, zoom); + + this._container.appendChild(tile); + }, + + _removeOtherTiles: function(bounds) { + var kArr, x, y, key; + + for (key in this._tiles) { + if (this._tiles.hasOwnProperty(key)) { + kArr = key.split(':'); + x = parseInt(kArr[0], 10); + y = parseInt(kArr[1], 10); + + // remove tile if it's out of bounds + if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { + var tile = this._tiles[key]; + if (tile.parentNode === this._container) { + this._container.removeChild(this._tiles[key]); + } + delete this._namedTiles[tile.tileName]; + delete this._tiles[key]; + } + } + } + }, + _updateTileSize: function() { + var newzoom = this._map.getZoom(); + if (this._currentzoom !== newzoom) { + var newTileSize = this.calculateTileSize(newzoom); + this._currentzoom = newzoom; + if (newTileSize !== this.options.tileSize) { + this.setTileSize(newTileSize); + } + } + }, + + _reset: function() { + this._updateTileSize(); + this._tiles = {}; + this._namedTiles = {}; + this._cachedTileUrls = {}; + this._initContainer(); + this._container.innerHTML = ''; + }, + + _update: function() { + this._updateTileSize(); + var bounds = this._map.getPixelBounds(), + tileSize = this.options.tileSize; + + var nwTilePoint = new L.Point( + Math.floor(bounds.min.x / tileSize), + Math.floor(bounds.min.y / tileSize)), + seTilePoint = new L.Point( + Math.floor(bounds.max.x / tileSize), + Math.floor(bounds.max.y / tileSize)), + tileBounds = new L.Bounds(nwTilePoint, seTilePoint); + + this._addTilesFromCenterOut(tileBounds); + + if (this.options.unloadInvisibleTiles) { + this._removeOtherTiles(tileBounds); + } + }, + calculateTileSize: function(zoom) { + return this.options.tileSize; + }, + setTileSize: function(tileSize) { + this.options.tileSize = tileSize; + this._tiles = {}; + this._container.innerHTML = ''; + this._createTileProto(); + }, + updateTileSize: function(zoom) {} +}); + +function loadjs(url, completed) { + var script = document.createElement('script'); + script.setAttribute('src', url); + script.setAttribute('type', 'text/javascript'); + var isloaded = false; + script.onload = function() { + if (isloaded) { return; } + isloaded = true; + completed(); + }; + + // Hack for IE, don't know whether this still applies to IE9. + script.onreadystatechange = function() { + script.onload(); + }; + (document.head || document.getElementsByTagName('head')[0]).appendChild(script); +} + +function splitArgs(s) { + var r = s.split(' '); + delete arguments[0]; + var obj = {}; + var index = 0; + $.each(arguments, function(argumentIndex, argument) { + if (!argumentIndex) { return; } + var value = r[argumentIndex-1]; + obj[argument] = value; + }); + return obj; +} + +function swtch(value, options, defaultOption) { + return (options[value] || defaultOption || function(){})(value); +} +(function( $ ){ + $.fn.scrollHeight = function(height) { + return this[0].scrollHeight; + }; +})($); + +function Location(world, x, y, z) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; +} diff --git a/web/js/flatmap.js b/web/js/flatmap.js index 11cbf3b8..3235235b 100644 --- a/web/js/flatmap.js +++ b/web/js/flatmap.js @@ -1,23 +1,39 @@ -function FlatProjection() {} -FlatProjection.prototype = { - extrazoom: 0, - fromLatLngToPoint: function(latLng) { - return new google.maps.Point(latLng.lat()*config.tileWidth, latLng.lng()*config.tileHeight); - }, - fromPointToLatLng: function(point) { - return new google.maps.LatLng(point.x/config.tileWidth, point.y/config.tileHeight); - }, - fromWorldToLatLng: function(x, y, z) { - return new google.maps.LatLng(-z / config.tileWidth / (1 << this.extrazoom), x / config.tileHeight / (1 << this.extrazoom)); - } -}; +var FlatProjection = DynmapProjection.extend({ + fromLocationToLatLng: function(location) { + return new L.LatLng(-location.z, location.x, true); + } +}); +var FlatMapType = DynmapTileLayer.extend({ + projection: new FlatProjection({}), + options: { + minZoom: 0, + maxZoom: 4 + }, + initialize: function(options) { + L.Util.setOptions(this, options); + }, + getTileName: function(tilePoint, zoom) { + var tileName; + var dnprefix = ''; + if(this.options.nightandday && this.dynmap.serverday) { + dnprefix = '_day'; + } + tileName = this.options.prefix + dnprefix + '_128_' + tilePoint.x + '_' + tilePoint.y + '.png'; + return tileName; + }, + calculateTileSize: function(zoom) { + return Math.pow(2, 7+zoom); + } +}) + +/* function FlatMapType(configuration) { $.extend(this, configuration); } FlatMapType.prototype = $.extend(new DynMapType(), { constructor: FlatMapType, projection: new FlatProjection(), - tileSize: new google.maps.Size(128.0, 128.0), + tileSize: 128.0, minZoom: 0, maxZoom: 3, prefix: null, @@ -81,8 +97,8 @@ FlatMapType.prototype = $.extend(new DynMapType(), { else { size = Math.pow(2, 7+zoom-extrazoom); } - this.tileSize = new google.maps.Size(size, size); + this.tileSize = size; } }); - -maptypes.FlatMapType = function(configuration) { return new FlatMapType(configuration); }; \ No newline at end of file +*/ +maptypes.FlatMapType = function(options) { return new FlatMapType(options); }; \ No newline at end of file diff --git a/web/js/map.js b/web/js/map.js index fbc17716..39e821a3 100644 --- a/web/js/map.js +++ b/web/js/map.js @@ -158,17 +158,25 @@ DynMap.prototype = { if(urlzoom != null) me.options.defaultzoom = urlzoom; - var map = this.map = new google.maps.Map(mapContainer.get(0), { - zoom: me.options.defaultzoom || 0, - center: new google.maps.LatLng(0, 1), - navigationControl: true, - navigationControlOptions: { - style: google.maps.NavigationControlStyle.DEFAULT - }, - scaleControl: false, - mapTypeControl: false, - streetViewControl: false, - backgroundColor: '#000000' + var map = this.map = new L.Map(mapContainer.get(0), { + zoom: 1, //TODO: me.options.defaultzoom || 1, + center: new L.LatLng(0, 0), + zoomAnimation: true, + crs: L.Util.extend({}, L.CRS, { + code: 'simple', + projection: { + project: function(latlng) { + return new L.Point(latlng.lat, latlng.lng); + }, + unproject: function(point, unbounded) { + return new L.LatLng(point.x, point.y, true); + } + }, + transformation: new L.Transformation(1, 0, 1, 0) + }), + scale: function(zoom) { + return (1 << zoom); + } }); map.zoom_changed = function() { @@ -176,18 +184,9 @@ DynMap.prototype = { $(me).trigger('zoomchanged'); }; - google.maps.event.addListener(map, 'dragstart', function(mEvent) { + /*google.maps.event.addListener(map, 'dragstart', function(mEvent) { me.followPlayer(null); - }); - // TODO: Enable hash-links. - /* - google.maps.event.addListener(map, 'zoom_changed', function() { - me.updateLink(); - }); - google.maps.event.addListener(map, 'center_changed', function() { - me.updateLink(); - }); - */ + });*/ // Sidebar var panel; @@ -239,7 +238,7 @@ DynMap.prototype = { .appendTo(worldlist); $.each(world.maps, function(index, map) { - me.map.mapTypes.set(map.world.name + '.' + map.name, map); + //me.map.mapTypes.set(map.world.name + '.' + map.name, map); map.element = $('
  • ') .addClass('map') @@ -349,14 +348,17 @@ DynMap.prototype = { }); }); }, + getProjection: function() { return this.maptype.getProjection(); }, selectMap: function(map, completed) { if (!map) { throw "Cannot select map " + map; } + console.log('Selecting map...'); var me = this; if (me.maptype === map) { return; } $(me).trigger('mapchanging'); + var mapWorld = map.options.world; if (me.maptype) { $('.compass').removeClass('compass_' + me.maptype.compassview); $('.compass').removeClass('compass_' + me.maptype.name); @@ -364,31 +366,33 @@ DynMap.prototype = { $('.compass').addClass('compass_' + map.compassview); $('.compass').addClass('compass_' + map.name); var worldChanged = me.world !== map.world; - var projectionChanged = me.map.getProjection() !== map.projection; - me.map.setMapTypeId('none'); - me.world = map.world; + var projectionChanged = (me.maptype && me.maptype.getProjection()) !== (map && map.projection); + if (me.maptype) { + me.map.removeLayer(me.maptype); + } + me.world = mapWorld; me.maptype = map; - me.maptype.updateTileSize(me.map.zoom); - window.setTimeout(function() { - me.map.setMapTypeId(map.world.name + '.' + map.name); - if (worldChanged) { - $(me).trigger('worldchanged'); - } - if (projectionChanged || worldChanged) { - if (map.world.center) { - me.map.panTo(map.projection.fromWorldToLatLng(map.world.center.x||0,map.world.center.y||64,map.world.center.z||0)); - } else { - me.map.panTo(map.projection.fromWorldToLatLng(0,64,0)); - } - } - $(me).trigger('mapchanged'); - if (completed) { - completed(); - } - }, 1); + me.map.addLayer(me.maptype); + + if (worldChanged) { + $(me).trigger('worldchanged'); + } + if (projectionChanged || worldChanged) { + var centerLocation = $.extend({ x: 0, y: 64, z: 0 }, mapWorld.center); + var centerPoint = map.getProjection().fromLocationToLatLng(centerLocation); + me.map.setView(centerPoint, 0, true); + } + $(me).trigger('mapchanged'); + $('.map', me.worldlist).removeClass('selected'); $(map.element).addClass('selected'); me.updateBackground(); + + + if (completed) { + completed(); + } + console.log('Map selected.'); }, selectWorld: function(world, completed) { var me = this; @@ -399,12 +403,34 @@ DynMap.prototype = { } me.selectMap(world.defaultmap, completed); }, - panTo: function(location, completed) { + panToLocation: function(location, completed) { var me = this; - me.selectWorld(location.world, function() { - var position = me.map.getProjection().fromWorldToLatLng(location.x, location.y, location.z); - me.map.panTo(position); - }); + var pan = function() { + var latlng = me.maptype.getProjection().fromLocationToLatLng(location); + me.panToLatLng(latlng, completed); + }; + + if (location.world) { + me.selectWorld(location.world, function() { + pan(); + }); + } else { + pan(); + } + }, + panToLayerPoint: function(point, completed) { + var me = this; + var latlng = me.map.layerPointToLatLng(point); + me.map.panToLatLng(latlng); + if (completed) { + completed(); + } + }, + panToLatLng: function(latlng, completed) { + this.map.panTo(latlng); + if (completed) { + completed(); + } }, update: function() { var me = this; @@ -473,12 +499,13 @@ DynMap.prototype = { if(me.serverday != oldday) { me.updateBackground(); var mtid = me.map.mapTypeId; - if(me.map.mapTypes[mtid].nightandday) { + console.log('TODO: RENDER NIGHTANDDAY!!!') + /*if(me.map.mapTypes[mtid].nightandday) { me.map.setMapTypeId('none'); window.setTimeout(function() { me.map.setMapTypeId(mtid); }, 0.1); - } + }*/ } $(me).trigger('worldupdated', [ update ]); @@ -526,6 +553,7 @@ DynMap.prototype = { tile.lastseen = timestamp; tile.mapType.onTileUpdated(tile.tileElement, tileName); } + me.maptype.updateNamedTile(tileName); }, addPlayer: function(update) { var me = this; @@ -563,7 +591,7 @@ DynMap.prototype = { if (me.followingPlayer !== player) { me.followPlayer(null); } - me.panTo(player.location); + me.panToLocation(player.location); }) .appendTo(me.playerlist); if (me.options.showplayerfacesinmenu) { @@ -586,7 +614,7 @@ DynMap.prototype = { if (player === me.followingPlayer) { // Follow the updated player. - me.panTo(player.location); + me.panToLocation(player.location); } }, removePlayer: function(player) { @@ -605,7 +633,7 @@ DynMap.prototype = { if(player) { $(player.menuitem).addClass('following'); - me.panTo(player.location); + me.panToLocation(player.location); } this.followingPlayer = player; }, diff --git a/web/js/playermarkers.js b/web/js/playermarkers.js index d4432fc7..3459f018 100644 --- a/web/js/playermarkers.js +++ b/web/js/playermarkers.js @@ -2,11 +2,12 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) { var me = this; $(dynmap).bind('playeradded', function(event, player) { // Create the player-marker. - var markerPosition = dynmap.map.getProjection().fromWorldToLatLng(player.location.x, player.location.y, player.location.z); - player.marker = new CustomMarker(markerPosition, dynmap.map, function(div) { + var markerPosition = dynmap.getProjection().fromLocationToLatLng(player.location); + player.marker = new L.CustomMarker(markerPosition, { elementCreator: function() { + var div = document.createElement('div'); var playerImage; - player.marker.toggle(dynmap.world === player.location.world); + $(player.marker._element).toggle(dynmap.world === player.location.world); $(div) .addClass('Marker') @@ -62,17 +63,19 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) { player.healthContainer.css('display','none'); } } - }); + return div; + }}); + dynmap.map.addLayer(player.marker); }); $(dynmap).bind('playerremoved', function(event, player) { // Remove the marker. - player.marker.remove(); + dynmap.map.removeLayer(player.marker); }); $(dynmap).bind('playerupdated', function(event, player) { // Update the marker. - var markerPosition = dynmap.map.getProjection().fromWorldToLatLng(player.location.x, player.location.y, player.location.z); - player.marker.toggle(dynmap.world === player.location.world); - player.marker.setPosition(markerPosition); + var markerPosition = dynmap.getProjection().fromLocationToLatLng(player.location); + $(player.marker._element).toggle(dynmap.world === player.location.world); + player.marker.setLatLng(markerPosition); // Update health if (configuration.showplayerhealth) { if (player.health !== undefined && player.armor !== undefined) { @@ -90,7 +93,7 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) { for(name in dynmap.players) { var player = dynmap.players[name]; // Turn off marker - let update turn it back on - player.marker.hide(); + $(player.marker._element).toggle(false); } }); // Remove marker on map change - let update place it again @@ -98,9 +101,9 @@ componentconstructors['playermarkers'] = function(dynmap, configuration) { var name; for(name in dynmap.players) { var player = dynmap.players[name]; - var markerPosition = dynmap.map.getProjection().fromWorldToLatLng(player.location.x, player.location.y, player.location.z); - player.marker.setPosition(markerPosition); - player.marker.toggle(dynmap.world === player.location.world); + var markerPosition = dynmap.getProjection().fromLocationToLatLng(player.location); + player.marker.setLatLng(markerPosition); + $(player.marker._element).toggle(dynmap.world === player.location.world); } }); }; diff --git a/web/js/projectiontest.js b/web/js/projectiontest.js new file mode 100644 index 00000000..6b6dad16 --- /dev/null +++ b/web/js/projectiontest.js @@ -0,0 +1,31 @@ +componentconstructors['projectiontest'] = function(dynmap, configuration) { + var me = this; + var marker = new L.CustomMarker(new L.LatLng(0,0,true), { + elementCreator: function() { + var div = document.createElement('div'); + var textContainer; + $(div) + .css({margin: '10px 10px 10px 10px'}) + .append( + textContainer = $('') + .css({'white-space': 'pre'}) + .text('') + ); + marker.setText = function(text) { + $(textContainer).text(text); + }; + return div; + } + }); + dynmap.map.addLayer(marker); + + dynmap.map.on('mousemove', function(event) { + marker.setLatLng(event.latlng); + if (marker.setText) { + marker.setText('LatLng: (' + event.latlng.lat + ',' + event.latlng.lng + ')\n'+ + 'LayerPoint: (' + event.layerPoint.x + ',' + event.layerPoint.y + ')\n'+ + 'World: (?,?,?)' + ); + } + }); +}; \ No newline at end of file diff --git a/web/leaflet.css b/web/leaflet.css new file mode 100644 index 00000000..4cb788c7 --- /dev/null +++ b/web/leaflet.css @@ -0,0 +1,321 @@ +/* required styles */ + +.leaflet-map-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-pane, +.leaflet-overlay-pane, +.leaflet-shadow-pane, +.leaflet-marker-pane, +.leaflet-popup-pane, +.leaflet-overlay-pane svg, +.leaflet-zoom-box, +.leaflet-image-layer { /* TODO optimize classes */ + position: absolute; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile-pane { + -webkit-transform: translate3d(0,0,0); + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +.leaflet-clickable { + cursor: pointer; + } +.leaflet-container img { + max-width: auto; + } + +.leaflet-tile-pane { z-index: 2; } +.leaflet-overlay-pane { z-index: 3; } +.leaflet-shadow-pane { z-index: 4; } +.leaflet-marker-pane { z-index: 5; } +.leaflet-popup-pane { z-index: 6; } + +.leaflet-zoom-box { + width: 0; + height: 0; + } + +.leaflet-tile { + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } + +a.leaflet-active { + outline: 2px solid orange; + } + + +/* Leaflet controls */ + +.leaflet-control { + position: relative; + z-index: 7; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + +.leaflet-control-zoom, .leaflet-control-layers { + -moz-border-radius: 7px; + -webkit-border-radius: 7px; + border-radius: 7px; + } +.leaflet-control-zoom { + padding: 5px; + background: rgba(0, 0, 0, 0.25); + } +.leaflet-control-zoom a { + background-color: rgba(255, 255, 255, 0.75); + } +.leaflet-control-zoom a, .leaflet-control-layers a { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-control-zoom a { + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + width: 19px; + height: 19px; + } +.leaflet-control-zoom a:hover { + background-color: #fff; + } +.leaflet-big-buttons .leaflet-control-zoom a { + width: 27px; + height: 27px; + } +.leaflet-control-zoom-in { + background-image: url(images/zoom-in.png); + margin-bottom: 5px; + } +.leaflet-control-zoom-out { + background-image: url(images/zoom-out.png); + } + +.leaflet-control-layers { + -moz-box-shadow: 0 0 7px #999; + -webkit-box-shadow: 0 0 7px #999; + box-shadow: 0 0 7px #999; + + background: #f8f8f9; + } +.leaflet-control-layers a { + background-image: url(images/layers.png); + width: 36px; + height: 36px; + } +.leaflet-big-buttons .leaflet-control-layers a { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + color: #333; + background: #fff; + } +.leaflet-control-layers input { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +.leaflet-container .leaflet-control-attribution { + margin: 0; + padding: 0 5px; + + font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + color: #333; + + background-color: rgba(255, 255, 255, 0.7); + + -moz-box-shadow: 0 0 7px #ccc; + -webkit-box-shadow: 0 0 7px #ccc; + box-shadow: 0 0 7px #ccc; + } + + +/* Fade animations */ + +.leaflet-fade-anim .leaflet-tile { + opacity: 0; + + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-tile-loaded { + opacity: 1; + } + +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } + +.leaflet-zoom-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-objects-pane { + visibility: hidden; + } + + +/* Popup layout */ + +.leaflet-popup { + position: absolute; + text-align: center; + -webkit-transform: translate3d(0,0,0); + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + } +.leaflet-popup-content { + margin: 19px; + } +.leaflet-popup-tip-container { + margin: 0 auto; + width: 40px; + height: 16px; + position: relative; + overflow: hidden; + } +.leaflet-popup-tip { + width: 15px; + height: 15px; + padding: 1px; + + margin: -8px auto 0; + + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-close-button { + position: absolute; + top: 9px; + right: 9px; + + width: 10px; + height: 10px; + + overflow: hidden; + } +.leaflet-popup-content p { + margin: 18px 0; + } + + +/* Visual appearance */ + +.leaflet-container { + background: #ddd; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-zoom-box { + border: 2px dotted #05f; + background: white; + opacity: 0.5; + } +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + background: white; + + box-shadow: 0 1px 10px #888; + -moz-box-shadow: 0 1px 10px #888; + -webkit-box-shadow: 0 1px 14px #999; + } +.leaflet-popup-content-wrapper { + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; + } +.leaflet-popup-content { + font: 12px/1.4 "Helvetica Neue", Arial, Helvetica, sans-serif; + } +.leaflet-popup-close-button { + background: white url(images/popup-close.png); + } \ No newline at end of file diff --git a/web/leaflet.ie.css b/web/leaflet.ie.css new file mode 100644 index 00000000..a120c0cb --- /dev/null +++ b/web/leaflet.ie.css @@ -0,0 +1,48 @@ +.leaflet-tile { + filter: inherit; + } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + +.leaflet-control { + display: inline; + } + +.leaflet-popup-tip { + width: 21px; + _width: 27px; + margin: 0 auto; + _margin-top: -3px; + + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + } +.leaflet-popup-tip-container { + margin-top: -1px; + } +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + border: 1px solid #bbb; + } + +.leaflet-control-zoom { + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#3F000000',EndColorStr='#3F000000'); + } +.leaflet-control-zoom a { + background-color: #eee; + } +.leaflet-control-zoom a:hover { + background-color: #fff; + } +.leaflet-control-layers-toggle { + } +.leaflet-control-attribution, .leaflet-control-layers { + background: white; + } \ No newline at end of file diff --git a/web/leaflet.js b/web/leaflet.js new file mode 100644 index 00000000..4ca74d8c --- /dev/null +++ b/web/leaflet.js @@ -0,0 +1,118 @@ +/* + Copyright (c) 2010-2011, CloudMade, Vladimir Agafonkin + Leaflet is a BSD-licensed JavaScript library for map display and interaction. + See http://cloudmade.github.com/Leaflet/ for more information. +*/ +(function(a){var b={VERSION:"0.2",ROOT_URL:function(){for(var a=document.getElementsByTagName("script"),b=/^(.*\/)leaflet-?([\w-]*)\.js.*$/,e=0,f=a.length;e0},removeEventListener:function(a,b,c){if(!this.hasEventListeners(a))return this;for(var d=0,e=this._leaflet_events,f=e[a].length;d=this.min.x&&a.x<=this.max.x&&b.y>=this.min.y&&a.y<=this.max.y}});L.Transformation=L.Class.extend({initialize:function(a,b,c,d){this._a=a;this._b=b;this._c=c;this._d=d},transform:function(a,b){return this._transform(a.clone(),b)},_transform:function(a,b){b=b||1;a.x=b*(this._a*a.x+this._b);a.y=b*(this._c*a.y+this._d);return a},untransform:function(a,b){b=b||1;return new L.Point((a.x/b-this._b)/this._a,(a.y/b-this._d)/this._c)}});L.LineUtil={simplify:function(a,b){if(!b)return a.slice();a=this.reducePoints(a,b);return a=this.simplifyDP(a,b)},pointToSegmentDistance:function(a,b,c){return Math.sqrt(this._sqPointToSegmentDist(a,b,c))},simplifyDP:function(a,b){for(var c=0,d=0,e=b*b,f=1,g=a.length,h;fc&&(d=f,c=h);return c>=e?(c=a.slice(0,d),d=a.slice(d),g=this.simplifyDP(c,b).slice(0,g-2),d=this.simplifyDP(d,b),g.concat(d)):[a[0],a[g-1]]},reducePoints:function(a,b){for(var c= +[a[0]],d=b*b,e=1,f=0,g=a.length;eb.max.x&&(c|=2);a.yb.max.y&&(c|=8);return c},_sqDist:function(a,b){var c=b.x-a.x,d=b.y-a.y;return c*c+d*d},_sqPointToSegmentDist:function(a,b,c){var d=c.x-b.x,e=c.y-b.y;if(!d&&!e)return this._sqDist(a,b);var f=((a.x-b.x)*d+(a.y-b.y)*e)/this._sqDist(b,c);if(f< +0)return this._sqDist(a,b);if(f>1)return this._sqDist(a,c);b=new L.Point(b.x+d*f,b.y+e*f);return this._sqDist(a,b)}};L.PolyUtil={};L.PolyUtil.clipPolygon=function(a,b){var c,d=[1,4,2,8],e,f,g,h,j,k,l=L.LineUtil;e=0;for(j=a.length;e0&&c<=h;f=b}}function e(){if(g)j.type="dblclick",b(j),f=null}var f,g=!1,h=250,j;a["_leaflet_touchstart"+c]=d;a["_leaflet_touchend"+c]=e;a.addEventListener("touchstart",d,!1);a.addEventListener("touchend",e,!1)},removeDoubleTapListener:function(a,b){a.removeEventListener(a,a["_leaflet_touchstart"+b],!1);a.removeEventListener(a,a["_leaflet_touchend"+b], +!1)}});L.DomUtil={get:function(a){return typeof a=="string"?document.getElementById(a):a},getStyle:function(a,b){var c=a.style[b];!c&&a.currentStyle&&(c=a.currentStyle[b]);if(!c||c=="auto")c=(c=document.defaultView.getComputedStyle(a,null))?c[b]:null;return c=="auto"?null:c},getCumulativeOffset:function(a){var b=0,c=0;do b+=a.offsetTop||0,c+=a.offsetLeft||0,a=a.offsetParent;while(a);return new L.Point(c,b)},create:function(a,b,c){a=document.createElement(a);a.className=b;c&&c.appendChild(a);return a},disableTextSelection:function(){document.selection&& +document.selection.empty&&document.selection.empty();if(!this._onselectstart)this._onselectstart=document.onselectstart,document.onselectstart=L.Util.falseFn},enableTextSelection:function(){document.onselectstart=this._onselectstart;this._onselectstart=null},CLASS_RE:/(\\s|^)'+cls+'(\\s|$)/,hasClass:function(a,b){return a.className.length>0&&RegExp("(^|\\s)"+b+"(\\s|$)").test(a.className)},addClass:function(a,b){L.DomUtil.hasClass(a,b)||(a.className+=(a.className?" ":"")+b)},setOpacity:function(a, +b){L.Browser.ie?a.style.filter="alpha(opacity="+Math.round(b*100)+")":a.style.opacity=b},testProp:function(a){for(var b=document.documentElement.style,c=0;c1)){var b=a.touches&&a.touches.length==1?a.touches[0]:a;L.DomEvent.preventDefault(a);L.Browser.touch&&(b.target.className+=" leaflet-active");this._moved=!1;L.DomUtil.disableTextSelection();this._setMovingCursor();this._startPos=this._newPos=L.DomUtil.getPosition(this._element);this._startPoint=new L.Point(b.clientX,b.clientY);L.DomEvent.addListener(document, +L.Draggable.MOVE,this._onMove,this);L.DomEvent.addListener(document,L.Draggable.END,this._onUp,this)}},_onMove:function(a){if(!(a.touches&&a.touches.length>1)){L.DomEvent.preventDefault(a);a=a.touches&&a.touches.length==1?a.touches[0]:a;if(!this._moved)this.fire("dragstart"),this._moved=!0;this._newPos=this._startPos.add(new L.Point(a.clientX,a.clientY)).subtract(this._startPoint);L.Util.requestAnimFrame(this._updatePosition,this,!0);this.fire("drag")}},_updatePosition:function(){L.DomUtil.setPosition(this._element, +this._newPos)},_onUp:function(a){if(a.changedTouches){var a=a.changedTouches[0],b=a.target,c=this._newPos&&this._newPos.distanceTo(this._startPos)||0;b.className=b.className.replace(" leaflet-active","");c=b.lat&&a.lat<=c.lat&&d.lng>=b.lng&&a.lng<=c.lng}});L.Projection={};L.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=a.lng*b,a=Math.max(Math.min(c,a.lat),-c)*b,a=Math.log(Math.tan(Math.PI/4+a/2));return new L.Point(d,a)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG;return new L.LatLng((2*Math.atan(Math.exp(a.y))-Math.PI/2)*c,a.x*c,b)}};L.Projection.LonLat={project:function(a){return new L.Point(a.lng,a.lat)},unproject:function(a,b){return new L.LatLng(a.y,a.x,b)}};L.Projection.Mercator={MAX_LATITUDE:85.0840591556,R_MINOR:6356752.3142,R_MAJOR:6378137,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=this.R_MAJOR,e=a.lng*b*d,a=Math.max(Math.min(c,a.lat),-c)*b,b=this.R_MINOR/d,b=Math.sqrt(1-b*b),c=b*Math.sin(a),c=Math.pow((1-c)/(1+c),b*0.5),a=-d*Math.log(Math.tan(0.5*(Math.PI*0.5-a))/c);return new L.Point(e,a)},unproject:function(a,b){for(var c=L.LatLng.RAD_TO_DEG,d=this.R_MAJOR,e=a.x*c/d,f=this.R_MINOR/d,f=Math.sqrt(1-f*f),d=Math.exp(-a.y/d), +g=Math.PI/2-2*Math.atan(d),h=15,j=0.1;Math.abs(j)>1.0E-7&&--h>0;)j=f*Math.sin(g),j=Math.PI/2-2*Math.atan(d*Math.pow((1-j)/(1+j),0.5*f))-g,g+=j;return new L.LatLng(g*c,e,b)}};L.CRS={latLngToPoint:function(a,b){return this.transformation._transform(this.projection.project(a),b)},pointToLatLng:function(a,b,c){return this.projection.unproject(this.transformation.untransform(a,b),c)},project:function(a){return this.projection.project(a)}};L.CRS.EPSG3857=L.Util.extend({},L.CRS,{code:"EPSG:3857",projection:L.Projection.SphericalMercator,transformation:new L.Transformation(0.5/Math.PI,0.5,-0.5/Math.PI,0.5),project:function(a){return this.projection.project(a).multiplyBy(6378137)}});L.CRS.EPSG900913=L.Util.extend({},L.CRS.EPSG3857,{code:"EPSG:900913"});L.CRS.EPSG4326=L.Util.extend({},L.CRS,{code:"EPSG:4326",projection:L.Projection.LonLat,transformation:new L.Transformation(1/360,0.5,-1/360,0.5)});L.CRS.EPSG3395=L.Util.extend({},L.CRS,{code:"EPSG:3395",projection:L.Projection.Mercator,transformation:function(){var a=L.Projection.Mercator;return new L.Transformation(0.5/(Math.PI*a.R_MAJOR),0.5,-0.5/(Math.PI*a.R_MINOR),0.5)}()});L.LayerGroup=L.Class.extend({initialize:function(a){this._layers={};if(a)for(var b=0,c=a.length;ba.max.x||ba.max.y)){if(!L.Browser.android)this._tiles[d].src="";this._tiles[d].parentNode==this._container&&this._container.removeChild(this._tiles[d]);delete this._tiles[d]}}, +_addTile:function(a,b){var c=this._getTilePos(a),d=this._map.getZoom(),e=a.x+":"+a.y,f=1<=f)){var g=this._createTile();L.DomUtil.setPosition(g,c);this._tiles[e]=g;if(this.options.scheme=="tms")a.y=f-a.y-1;this._loadTile(g,a,d);b.appendChild(g)}},_getTilePos:function(a){var b=this._map.getPixelOrigin();return a.multiplyBy(this.options.tileSize).subtract(b)},getTileUrl:function(a,b){return this._url.replace("{s}",this.options.subdomains[(a.x+ +a.y)%this.options.subdomains.length]).replace("{z}",b).replace("{x}",a.x).replace("{y}",a.y)},_createTileProto:function(){this._tileImg=L.DomUtil.create("img","leaflet-tile");this._tileImg.galleryimg="no";var a=this.options.tileSize;this._tileImg.style.width=a+"px";this._tileImg.style.height=a+"px"},_createTile:function(){var a=this._tileImg.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){a._layer=this;a.onload=this._tileOnLoad;a.onerror=this._tileOnError; +a.src=this.getTileUrl(b,c)},_tileOnLoad:function(){var a=this._layer;this.className+=" leaflet-tile-loaded";a.fire("tileload",{tile:this,url:this.src});a._tilesToLoad--;a._tilesToLoad||a.fire("load")},_tileOnError:function(){var a=this._layer;a.fire("tileerror",{tile:this,url:this.src});if(a=a.options.errorTileUrl)this.src=a}});L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a;this.wmsParams=L.Util.extend({},this.defaultWmsParams);this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);L.Util.setOptions(this,b)},onAdd:function(a){this.wmsParams[parseFloat(this.wmsParams.version)>=1.3?"crs":"srs"]=a.options.crs.code; +L.TileLayer.prototype.onAdd.call(this,a)},getTileUrl:function(a){var b=this.options.tileSize,a=a.multiplyBy(b),b=a.add(new L.Point(b,b)),a=this._map.unproject(a,this._zoom,!0),b=this._map.unproject(b,this._zoom,!0),a=this._map.options.crs.project(a),b=this._map.options.crs.project(b),b=[a.x,b.y,b.x,a.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+b}});L.TileLayer.Canvas=L.TileLayer.extend({options:{async:!1},initialize:function(a){L.Util.setOptions(this,a)},_createTileProto:function(){this._canvasProto=L.DomUtil.create("canvas","leaflet-tile");var a=this.options.tileSize;this._canvasProto.width=a;this._canvasProto.height=a},_createTile:function(){var a=this._canvasProto.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){a._layer=this;this.drawTile(a,b,c);this.options.async||this.tileDrawn(a)},drawTile:function(){}, +tileDrawn:function(a){this._tileOnLoad.call(a)}});L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a;this._bounds=b},onAdd:function(a){this._map=a;this._image||this._initImage();a.getPanes().overlayPane.appendChild(this._image);a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image);a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer");this._image.style.visibility="hidden";L.Util.extend(this._image, +{galleryimg:"no",onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:this._onImageLoad,src:this._url})},_reset:function(){var a=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),b=this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(a);L.DomUtil.setPosition(this._image,a);this._image.style.width=b.x+"px";this._image.style.height=b.y+"px"},_onImageLoad:function(){this.style.visibility=""}});L.Popup=L.Class.extend({includes:L.Mixin.Events,options:{maxWidth:300,autoPan:!0,closeButton:!0,offset:new L.Point(0,2),autoPanPadding:new L.Point(5,5)},initialize:function(a){L.Util.setOptions(this,a)},onAdd:function(a){this._map=a;this._container||this._initLayout();this._updateContent();this._container.style.opacity="0";this._map._panes.popupPane.appendChild(this._container);this._map.on("viewreset",this._updatePosition,this);if(this._map.options.closePopupOnClick)this._map.on("preclick",this._close, +this);this._update();this._container.style.opacity="1";this._opened=!0},onRemove:function(a){a._panes.popupPane.removeChild(this._container);a.off("viewreset",this._updatePosition,this);a.off("click",this._close,this);this._container.style.opacity="0";this._opened=!1},setLatLng:function(a){this._latlng=a;this._opened&&this._update();return this},setContent:function(a){this._content=a;this._opened&&this._update();return this},_close:function(){this._opened&&this._map.removeLayer(this)},_initLayout:function(){this._container= +L.DomUtil.create("div","leaflet-popup");if(this.options.closeButton)this._closeButton=L.DomUtil.create("a","leaflet-popup-close-button",this._container),this._closeButton.href="#close",this._closeButton.onclick=L.Util.bind(this._onCloseButtonClick,this);this._wrapper=L.DomUtil.create("div","leaflet-popup-content-wrapper",this._container);L.DomEvent.disableClickPropagation(this._wrapper);this._contentNode=L.DomUtil.create("div","leaflet-popup-content",this._wrapper);this._tipContainer=L.DomUtil.create("div", +"leaflet-popup-tip-container",this._container);this._tip=L.DomUtil.create("div","leaflet-popup-tip",this._tipContainer)},_update:function(){this._container.style.visibility="hidden";this._updateContent();this._updateLayout();this._updatePosition();this._container.style.visibility="";this._adjustPan()},_updateContent:function(){if(this._content)typeof this._content=="string"?this._contentNode.innerHTML=this._content:(this._contentNode.innerHTML="",this._contentNode.appendChild(this._content))},_updateLayout:function(){this._container.style.width= +"";this._container.style.whiteSpace="nowrap";var a=this._container.offsetWidth;this._container.style.width=(a>this.options.maxWidth?this.options.maxWidth:a)+"px";this._container.style.whiteSpace="";this._containerWidth=this._container.offsetWidth},_updatePosition:function(){var a=this._map.latLngToLayerPoint(this._latlng);this._containerBottom=-a.y-this.options.offset.y;this._containerLeft=a.x-Math.round(this._containerWidth/2)+this.options.offset.x;this._container.style.bottom=this._containerBottom+ +"px";this._container.style.left=this._containerLeft+"px"},_adjustPan:function(){if(this.options.autoPan){var a=this._container.offsetHeight,b=this._map.layerPointToContainerPoint(new L.Point(this._containerLeft,-a-this._containerBottom)),c=new L.Point(0,0),d=this.options.autoPanPadding,e=this._map.getSize();if(b.x<0)c.x=b.x-d.x;if(b.x+this._containerWidth>e.x)c.x=b.x+this._containerWidth-e.x+d.x;if(b.y<0)c.y=b.y-d.y;if(b.y+a>e.y)c.y=b.y+a-e.y+d.y;(c.x||c.y)&&this._map.panBy(c)}},_onCloseButtonClick:function(a){this._close(); +L.DomEvent.stop(a)}});L.Icon=L.Class.extend({iconUrl:L.ROOT_URL+"images/marker.png",shadowUrl:L.ROOT_URL+"images/marker-shadow.png",iconSize:new L.Point(25,41),shadowSize:new L.Point(41,41),iconAnchor:new L.Point(13,41),popupAnchor:new L.Point(0,-33),initialize:function(a){if(a)this.iconUrl=a},createIcon:function(){return this._createIcon("icon")},createShadow:function(){return this._createIcon("shadow")},_createIcon:function(a){var b=this[a+"Size"],c=this[a+"Url"],d=this._createImg(c);if(!c)return null;d.className="leaflet-marker-"+ +a;d.style.marginLeft=-this.iconAnchor.x+"px";d.style.marginTop=-this.iconAnchor.y+"px";if(b)d.style.width=b.x+"px",d.style.height=b.y+"px";return d},_createImg:function(a){var b;L.Browser.ie6?(b=document.createElement("div"),b.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+a+'")'):(b=document.createElement("img"),b.src=a);return b}});L.Marker=L.Class.extend({includes:L.Mixin.Events,options:{icon:new L.Icon,title:"",clickable:!0,draggable:!1},initialize:function(a,b){L.Util.setOptions(this,b);this._latlng=a},onAdd:function(a){this._map=a;this._initIcon();a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){this._removeIcon();a.off("viewreset",this._reset,this)},getLatLng:function(){return this._latlng},setLatLng:function(a){this._latlng=a;this._reset()},setIcon:function(a){this._removeIcon();this._icon=this._shadow= +null;this.options.icon=a;this._initIcon()},_initIcon:function(){if(!this._icon){this._icon=this.options.icon.createIcon();if(this.options.title)this._icon.title=this.options.title;this._initInteraction()}if(!this._shadow)this._shadow=this.options.icon.createShadow();this._map._panes.markerPane.appendChild(this._icon);this._shadow&&this._map._panes.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this._map._panes.markerPane.removeChild(this._icon);this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow)}, +_reset:function(){var a=this._map.latLngToLayerPoint(this._latlng).round();L.DomUtil.setPosition(this._icon,a);this._shadow&&L.DomUtil.setPosition(this._shadow,a);this._icon.style.zIndex=a.y},_initInteraction:function(){if(this.options.clickable){this._icon.className+=" leaflet-clickable";L.DomEvent.addListener(this._icon,"click",this._onMouseClick,this);for(var a=["dblclick","mousedown","mouseover","mouseout"],b=0;b';a=a.firstChild;a.style.behavior="url(#default#VML)";return a&&typeof a.adj=="object"}(); +L.Path=L.Browser.svg||!L.Browser.vml?L.Path:L.Path.extend({statics:{VML:!0,CLIP_PADDING:0.02},_createElement:function(){try{return document.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(a){return document.createElement("')}}catch(a){return function(a){return document.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_initRoot:function(){if(!this._map._pathRoot)this._map._pathRoot=document.createElement("div"),this._map._pathRoot.className= +"leaflet-vml-container",this._map._panes.overlayPane.appendChild(this._map._pathRoot),this._map.on("moveend",this._updateViewport,this),this._updateViewport()},_initPath:function(){this._container=this._createElement("shape");this._container.className+=" leaflet-vml-shape"+(this.options.clickable?" leaflet-clickable":"");this._container.coordsize="1 1";this._path=this._createElement("path");this._container.appendChild(this._path);this._map._pathRoot.appendChild(this._container)},_initStyle:function(){this.options.stroke? +(this._stroke=this._createElement("stroke"),this._stroke.endcap="round",this._container.appendChild(this._stroke)):this._container.stroked=!1;this.options.fill?(this._container.filled=!0,this._fill=this._createElement("fill"),this._container.appendChild(this._fill)):this._container.filled=!1;this._updateStyle()},_updateStyle:function(){if(this.options.stroke)this._stroke.weight=this.options.weight+"px",this._stroke.color=this.options.color,this._stroke.opacity=this.options.opacity;if(this.options.fill)this._fill.color= +this.options.fillColor||this.options.color,this._fill.opacity=this.options.fillOpacity},_updatePath:function(){this._container.style.display="none";this._path.v=this.getPathString()+" ";this._container.style.display=""}});L.Browser.canvas=function(){return!!document.createElement("canvas").getContext}(); +L.Path=L.Path.SVG&&!window.L_PREFER_CANVAS||!L.Browser.canvas?L.Path:L.Path.extend({statics:{CANVAS:!0,SVG:!1},options:{updateOnMoveEnd:!0},_initElements:function(){this._initRoot()},_initRoot:function(){var a=this._map._pathRoot,b=this._map._canvasCtx;if(!a)a=this._map._pathRoot=document.createElement("canvas"),a.style.position="absolute",b=this._map._canvasCtx=a.getContext("2d"),b.lineCap="round",b.lineJoin="round",this._map._panes.overlayPane.appendChild(a),this._map.on("moveend",this._updateCanvasViewport, +this),this._updateCanvasViewport();this._ctx=b},_updateStyle:function(){if(this.options.stroke)this._ctx.lineWidth=this.options.weight,this._ctx.strokeStyle=this.options.color;if(this.options.fill)this._ctx.fillStyle=this.options.fillColor||this.options.color},_drawPath:function(){var a,b,c,d,e,f;this._ctx.beginPath();a=0;for(c=this._parts.length;aa.y!=e.y>a.y&&a.x<(e.x-d.x)*(a.y-d.y)/(e.y-d.y)+d.x&&(b=!b)}return b}});(function(){function a(a){return L.FeatureGroup.extend({initialize:function(c,d){this._layers={};for(var e=0,f=c.length;ea.max.x||c.y-b>a.max.y||c.x+b0?Math.ceil(b):Math.floor(b))),a=b-a,c=this._centerOffset.subtract(this._delta).divideBy(this._scale),d=this._map.unproject(this._map.getPixelOrigin().add(this._startCenter).add(c));L.DomEvent.removeListener(document,"touchmove",this._onTouchMove);L.DomEvent.removeListener(document,"touchend",this._onTouchEnd);this._map._runAnimation(d,b,Math.pow(2,a)/this._scale,this._startCenter.add(c))}}});L.Handler.ScrollWheelZoom=L.Handler.extend({enable:function(){if(!this._enabled)L.DomEvent.addListener(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0,this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._map._container,"mousewheel",this._onWheelScroll),this._enabled=!1},_onWheelScroll:function(a){this._delta+=L.DomEvent.getWheelDelta(a);this._lastMousePos=this._map.mouseEventToContainerPoint(a);clearTimeout(this._timer);this._timer=setTimeout(L.Util.bind(this._performZoom, +this),50);L.DomEvent.preventDefault(a)},_performZoom:function(){var a=Math.round(this._delta);this._delta=0;if(a){var b=this._getCenterForScrollWheelZoom(this._lastMousePos,a),a=this._map.getZoom()+a;this._map._limitZoom(a)!=this._map._zoom&&this._map.setView(b,a)}},_getCenterForScrollWheelZoom:function(a,b){var c=this._map.getPixelBounds().getCenter(),d=this._map.getSize().divideBy(2),d=a.subtract(d).multiplyBy(1-Math.pow(2,-b));return this._map.unproject(c.add(d),this._map._zoom,!0)}});L.Handler.DoubleClickZoom=L.Handler.extend({enable:function(){if(!this._enabled)this._map.on("dblclick",this._onDoubleClick,this._map),this._enabled=!0},disable:function(){if(this._enabled)this._map.off("dblclick",this._onDoubleClick,this._map),this._enabled=!1},_onDoubleClick:function(a){this.setView(a.latlng,this._zoom+1)}});L.Handler.ShiftDragZoom=L.Handler.extend({initialize:function(a){this._map=a;this._container=a._container;this._pane=a._panes.overlayPane},enable:function(){if(!this._enabled)L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this),this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown),this._enabled=!1},_onMouseDown:function(a){if(!a.shiftKey||a.which!=1&&a.button!=1)return!1;L.DomUtil.disableTextSelection(); +this._startLayerPoint=this._map.mouseEventToLayerPoint(a);this._box=L.DomUtil.create("div","leaflet-zoom-box",this._pane);L.DomUtil.setPosition(this._box,this._startLayerPoint);this._container.style.cursor="crosshair";L.DomEvent.addListener(document,"mousemove",this._onMouseMove,this);L.DomEvent.addListener(document,"mouseup",this._onMouseUp,this);L.DomEvent.preventDefault(a)},_onMouseMove:function(a){var b=this._map.mouseEventToLayerPoint(a),a=b.x-this._startLayerPoint.x,c=b.y-this._startLayerPoint.y, +b=new L.Point(Math.min(b.x,this._startLayerPoint.x),Math.min(b.y,this._startLayerPoint.y));L.DomUtil.setPosition(this._box,b);this._box.style.width=Math.abs(a)-4+"px";this._box.style.height=Math.abs(c)-4+"px"},_onMouseUp:function(a){this._pane.removeChild(this._box);this._container.style.cursor="";L.DomUtil.enableTextSelection();L.DomEvent.removeListener(document,"mousemove",this._onMouseMove);L.DomEvent.removeListener(document,"mouseup",this._onMouseUp);a=this._map.mouseEventToLayerPoint(a);this._map.fitBounds(new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint), +this._map.layerPointToLatLng(a)))}});L.Handler.MarkerDrag=L.Handler.extend({initialize:function(a){this._marker=a},enable:function(){if(!this._enabled){if(!this._draggable)this._draggable=new L.Draggable(this._marker._icon,this._marker._icon),this._draggable.on("dragstart",this._onDragStart,this),this._draggable.on("drag",this._onDrag,this),this._draggable.on("dragend",this._onDragEnd,this);this._draggable.enable();this._enabled=!0}},disable:function(){if(this._enabled)this._draggable.disable(),this._enabled=!1},moved:function(){return this._draggable&& +this._draggable._moved},_onDragStart:function(){this._marker.closePopup();this._marker.fire("movestart");this._marker.fire("dragstart")},_onDrag:function(){var a=L.DomUtil.getPosition(this._marker._icon);this._marker._shadow&&L.DomUtil.setPosition(this._marker._shadow,a);this._marker._latlng=this._marker._map.layerPointToLatLng(a);this._marker.fire("move");this._marker.fire("drag")},_onDragEnd:function(){this._marker.fire("moveend");this._marker.fire("dragend")}});L.Control={};L.Control.Position={TOP_LEFT:"topLeft",TOP_RIGHT:"topRight",BOTTOM_LEFT:"bottomLeft",BOTTOM_RIGHT:"bottomRight"};L.Control.Zoom=L.Class.extend({onAdd:function(a){this._map=a;this._container=L.DomUtil.create("div","leaflet-control-zoom");this._zoomInButton=this._createButton("Zoom in","leaflet-control-zoom-in",this._map.zoomIn,this._map);this._zoomOutButton=this._createButton("Zoom out","leaflet-control-zoom-out",this._map.zoomOut,this._map);this._container.appendChild(this._zoomInButton);this._container.appendChild(this._zoomOutButton)},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_LEFT}, +_createButton:function(a,b,c,d){var e=document.createElement("a");e.href="#";e.title=a;e.className=b;L.DomEvent.disableClickPropagation(e);L.DomEvent.addListener(e,"click",L.DomEvent.preventDefault);L.DomEvent.addListener(e,"click",c,d);return e}});L.Control.Attribution=L.Class.extend({onAdd:function(a){this._container=L.DomUtil.create("div","leaflet-control-attribution");this._map=a;this._prefix='Powered by Leaflet';this._attributions={};this._update()},getPosition:function(){return L.Control.Position.BOTTOM_RIGHT},getContainer:function(){return this._container},setPrefix:function(a){this._prefix=a},addAttribution:function(a){a&&(this._attributions[a]=!0,this._update())},removeAttribution:function(a){a&& +(delete this._attributions[a],this._update())},_update:function(){if(this._map){var a=[],b;for(b in this._attributions)this._attributions.hasOwnProperty(b)&&a.push(b);b=[];this._prefix&&b.push(this._prefix);a.length&&b.push(a.join(", "));this._container.innerHTML=b.join(" — ")}}});L.Map=L.Class.extend({includes:L.Mixin.Events,options:{crs:L.CRS.EPSG3857||L.CRS.EPSG4326,scale:function(a){return 256*(1<