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;e