diff --git a/draw_map.py b/draw_map.py index 4f03fb9..73e52b2 100755 --- a/draw_map.py +++ b/draw_map.py @@ -36,7 +36,7 @@ m.zoom_to_box(mapnik.Envelope(-180.0,-90.0,180.0,83.623596)) ### Write file -mapnik.render_to_file(m,'output/world.png', 'png') +mapnik.render_to_file(m,'/var/lib/banditvis/output/world.png', 'png') ##### Get Metadata @@ -53,7 +53,7 @@ ##### Insert Metadata -im = Image.open('output/world.png') +im = Image.open('/var/lib/banditvis/output/world.png') draw = ImageDraw.Draw(im) font = ImageFont.truetype('fonts/LinLibertine_Bd-4.1.5.otf', 20) @@ -74,7 +74,6 @@ im.paste(im2, (27, 280), im2) ### Write file -#im.save('output/world.png') im.save('/var/lib/banditvis/output/world.png') exit() \ No newline at end of file diff --git a/interactive/banditvis.css b/interactive/banditvis.css index 9d8e852..6ae5e27 100644 --- a/interactive/banditvis.css +++ b/interactive/banditvis.css @@ -1,11 +1,37 @@ #map{ border: 1px solid black; + height: 100%; + width: 100%; } -.Popup{ - background-color:yellow; +#legend { border: 1px solid black; + position: absolute; + overflow: hidden; + z-index: 1000000; + + top: 150px; + left: 15px; + width: 40px; + height: 70%; + + text-align: center; + + background-image: -ms-linear-gradient(top, hsl(0, 100%, 50%), hsl(120, 100%, 50%)); + background-image: -moz-linear-gradient(top, red, yellow, green); + background-image: -o-linear-gradient(top, hsl(0,100%, 50%), hsl(120, 100%, 50%)); + background-image: -webkit-linear-gradient(top, hsl(0, 100%, 50%), hsl(120, 100%, 50%)); + background-image: linear-gradient(top, hsl(0, 100%, 50%), hsl(120, 100%, 50%)); } -.PopupContent{ - overflow:visible; + +#legend_upper { + position:absolute; + top: 0px; + width: 100% +} + +#legend_lower{ + position:absolute; + bottom: 0px; + width: 100% } \ No newline at end of file diff --git a/interactive/banditvis.js b/interactive/banditvis.js index 5e59db3..9098670 100644 --- a/interactive/banditvis.js +++ b/interactive/banditvis.js @@ -1,56 +1,123 @@ - var map, dataLayers, debug; - + Banditvis = new Object(); + Banditvis.max_ocount = 0; + /* Called via map.html onload */ /* Does a lot... */ /* Returns nothing */ function init(){ - map = new OpenLayers.Map('map'); + Banditvis.map = new OpenLayers.Map('map'); var osm = new OpenLayers.Layer.OSM("OpenStreetMaps"); - map.addLayer(osm); + osm.transitionEffect = "resize"; + Banditvis.map.addLayer(osm); - map.setCenter( + Banditvis.map.setCenter( new OpenLayers.LonLat(10.75, 49.1).transform( new OpenLayers.Projection("EPSG:4326"), - map.getProjectionObject() + Banditvis.map.getProjectionObject() ), 2 ); - map.addControl(new OpenLayers.Control.LayerSwitcher()); + Banditvis.map.addControl(new OpenLayers.Control.LayerSwitcher()); - debug = document.getElementById("debug"); + Banditvis.legend = document.getElementById("legend"); + Banditvis.legend.upper = document.getElementById("legend_upper"); + Banditvis.legend.lower = document.getElementById("legend_lower"); loadData(); - addStyles(); - addClustering(); - addMouseOver(); + Banditvis.map.events.on({ 'moveend': function(evt) { + Banditvis.min_ocount = null; + Banditvis.max_ocount = null; + for ( var i in Banditvis.dataLayers) { + updateMetadata(Banditvis.dataLayers[i]); + Banditvis.dataLayers[i].redraw(); + } + } }); + Banditvis.map.events.on({ 'zoomend': function(evt) { + redrawPopups(); + } }); return; } /* Called by init() */ -/* Adds layers of data to the map */ +/* Loads the offences file */ /* Returns nothing */ function loadData() { - dataLayers = new Array(); - dataLayers.push(new OpenLayers.Layer.GML("Server", "server.kml", {format: OpenLayers.Format.KML})); - dataLayers.push(new OpenLayers.Layer.GML("ssh", "output/ssh.kml", {format: OpenLayers.Format.KML})); - + var xmlHttpObject = false; + if (typeof XMLHttpRequest != 'undefined') { + xmlHttpObject = new XMLHttpRequest(); + } + if (!xmlHttpObject) { + try { + xmlHttpObject = new ActiveXObject("Msxml2.XMLHTTP"); + } catch(e) { + try { + xmlHttpObject = new ActiveXObject("Microsoft.XMLHTTP"); + } catch(e) { + xmlHttpObject = null; + } + } + } - map.addLayers(dataLayers); - return; + // var wait = true; + // var waitTime = 10; + xmlHttpObject.open("GET", "output/offences.txt"); + xmlHttpObject.onreadystatechange = function() { + if (xmlHttpObject.readyState == 4) { + loadKMLs(xmlHttpObject); + } + } + xmlHttpObject.send(null); } +/* Called by loadData() */ +/* Adds layers of data to the map */ +/* Returns nothing */ +function loadKMLs(xmlHttpObject) { + Banditvis.dataLayers = new Array(); + Banditvis.dataLayers.push(new OpenLayers.Layer.GML("Server", "server.kml", {format: OpenLayers.Format.KML})); + + var responseLines=xmlHttpObject.responseText.split("\n") + for (var i in responseLines) { + if (responseLines[i] != "") { + Banditvis.dataLayers.push(new OpenLayers.Layer.GML(responseLines[i], "output/"+responseLines[i]+".kml", {format: OpenLayers.Format.KML})); + } + } + + for (var i in Banditvis.dataLayers) { + Banditvis.map.addLayer(Banditvis.dataLayers[i]); + Banditvis.dataLayers[i].strategies = new Array(); + + Banditvis.dataLayers[i].events.on({"loadend": function() { + addMetadata(Banditvis.dataLayers[i]); + updateMetadata(Banditvis.dataLayers[i]); + Banditvis.dataLayers[i].redraw(); + } }); + + addStyles(Banditvis.dataLayers[i]); + addClustering(Banditvis.dataLayers[i]); + // addReloader(Banditvis.dataLayers[i]); + addMouseOver(Banditvis.dataLayers[i]); + + } + + return; +} -function addStyles(){ +/* Called by loadKMLs() */ +/* Adds the style to the datapoints */ +/* Returns nothing */ +function addStyles(layer){ var style = new OpenLayers.Style({ pointRadius: "${radius}", - fillColor: "#ff5454", + fillColor: "${fillColor}", fillOpacity: 0.8, strokeColor: "#000000", strokeWidth: "${width}", - strokeOpacity: 0.8 + strokeOpacity: 0.8, + label: "${label}" }, { context: { width: function(feature) { return (feature.cluster) ? 3 : 1; }, @@ -61,11 +128,58 @@ function addStyles(){ var r = 5; } return r; - } + }, + fillColor: function(feature) { + + if (!feature.attributes || !feature.attributes.ocount) { + return "#808080"; + } + var ocount = parseInt(feature.attributes.ocount); + + var r = 0; + var R; + var g = 0; + var G; + + var p = (ocount - Banditvis.min_ocount) / (Banditvis.max_ocount - Banditvis.min_ocount) * 100; + + if (p < 0 || p > 100 || isNaN(p)) + { p = 50; } + + if (p >= 50) r = 255; + if (p < 50) r = Math.round(p/50 * 255); + + if (p >= 50) g = 255 - Math.round((p-50)/50 * 255); + if (p < 50) g = 255; + + if (r < 16) R = "0"+r.toString(16); + else R = r.toString(16); + + if (g < 16) G = "0"+g.toString(16); + else G = g.toString(16); + + var color = "#"+R+G+"00"; + if (color.length != 7) { + alert(color); + } + return color; + + }, + label: function(feature) { + if (feature.cluster) { + if (feature.attributes.count <= 3) { + return ""; + } + return feature.attributes.count; + } else { + return ""; + } + } + } }); - dataLayers[1].styleMap = new OpenLayers.StyleMap({ + layer.styleMap = new OpenLayers.StyleMap({ "default": style, "select": { fillColor: "#54ffff", @@ -76,31 +190,123 @@ function addStyles(){ return; } -/* Called by init() */ +/* Called by loadKMLs() */ +/* Fills feature.data with metadata */ +/* Returns nothing */ +function addMetadata(layer) { + for (var i in layer.features) { + if ( layer.features[i].cluster) { + for (var j in layer.features[i].cluster) { + extractMetadata(layer.features[i].cluster[j]); + } + } else { + extractMetadata(layer.features[i]); + } + } + return; +} + +function extractMetadata(feature) { + var match = feature.data.description.search("offence: (.*?), count: (.*?), first_seen: (.*?), last_seen: (.*)"); + if (match != -1) { + feature.attributes.offence = RegExp.$1; + feature.attributes.ocount = RegExp.$2; + feature.attributes.first_time = RegExp.$3; + feature.attributes.last_time = RegExp.$4; + } + return; +} + +function updateMetadata(layer) { +for (var i in layer.features) { + if (layer.features[i].onScreen()){ + if (layer.features[i].cluster) { + var count = 0; + for (var j in layer.features[i].cluster) { + if (layer.features[i].cluster[j].attributes.ocount) { + count = count + parseInt(layer.features[i].cluster[j].attributes.ocount); + } + } + layer.features[i].attributes.ocount = parseInt(count); + } + if (layer.features[i].attributes.ocount > Banditvis.max_ocount) { + Banditvis.max_ocount = parseInt(layer.features[i].attributes.ocount); + } + if (!Banditvis.min_ocount || layer.features[i].attributes.ocount < Banditvis.min_ocount) { + Banditvis.min_ocount = parseInt(layer.features[i].attributes.ocount); + } + } +} + Banditvis.legend.upper.innerHTML = Banditvis.max_ocount; + Banditvis.legend.lower.innerHTML = Banditvis.min_ocount; + return; +} + +/* Called by loadKMLs() */ /* Adds the clustering strategy to the dataLayer*/ /* Returns nothing */ -function addClustering() { +function addClustering(layer) { var clustering = new OpenLayers.Strategy.Cluster({distance: 25, threshold: 2}); - clustering.setLayer(dataLayers[1]); - dataLayers[1].strategies = clustering; - dataLayers[1].strategies.activate(); + clustering.setLayer(layer); + clustering.activate(); + layer.strategies.push(clustering); return; } -/* Called by init() */ +/* Called by loadKMLs() */ /* Adds the Hover/Select-effect */ /* Returns nothing */ -function addMouseOver() { - dataLayers[1].events.on({ +function addMouseOver(layer) { + layer.events.on({ //'hoverfeature': function(evt) { showPopup(evt.feature) }, //'outfeature': function(evt) { evt.feature.popup.destroy() }, - 'featureselected': function(evt) { showPopup(evt.feature) }, - 'featureunselected': function(evt) { evt.feature.popup.destroy() } + 'featureselected': function(evt) { + //alert("evt: sel: " +evt.feature.id); + showPopup(evt.feature); + if (evt.redraw != true) { + if (evt.feature.cluster == null) { + //alert("arrayAdd: "+arrayAdd(evt.feature)); + } else { + for (var i in evt.feature.cluster) { + arrayAdd(evt.feature.cluster[i]); + } + } + } + }, + 'featureunselected': function(evt) { + //alert("evt: usel: " +evt.feature.id); + //console.log(evt.feature.popup); + if (evt.feature.popup != null) { + evt.feature.popup.destroy(); + } + if (evt.redraw != true) { + if (evt.feature.cluster == null) { + //alert("arrayRemove: "+arrayRemove(evt.feature)); + } else { + for (var i in evt.feature.cluster) { + arrayRemove(evt.feature.cluster[i]); + } + } + } + } }); + Banditvis.hover = new OpenLayers.Control.SelectFeature(Banditvis.dataLayers, {/*hover: true, */multiple: true, toggle: true}); + Banditvis.map.addControl(Banditvis.hover); + Banditvis.hover.activate(true); - hover = new OpenLayers.Control.SelectFeature(dataLayers, {/*hover: true, */multiple: true, toggle: true}); - map.addControl(hover); - hover.activate(true); + Banditvis.selectedFeatures = new Array(); + + return; +} + +/* Called by loadKMLs() */ +/* Adds a reloading strategy */ +/* Returns nothing */ +function addReloader(layer) { + var reloader = new OpenLayers.Strategy.Refresh({interval: 1000, force: true}); + reloader.setLayer(layer); + reloader.activate(); + layer.strategies.push(reloader); return; } @@ -108,15 +314,13 @@ function addMouseOver() { /* Creates a Popup and shows it */ /* Returns nothing */ function showPopup(feature) { - console.log(feature); feature.popup = new OpenLayers.Popup(null, feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(270, 85), providePopupContent(feature), false, null); feature.popup.autoSize = true; feature.popup.displayClass = "Popup"; feature.popup.contentDisplayClass = "PopupContent"; feature.popup.setBorder("1px solid black"); feature.popup.setOpacity(0.8); - //feature.popup.minSize = new OpenLayers.Size(300, 100); - map.addPopup(feature.popup); + Banditvis.map.addPopup(feature.popup); feature.popup.show(); return; } @@ -125,18 +329,89 @@ function showPopup(feature) { /* Returns the features name and description as a formatted string */ function providePopupContent(feature) { if (feature.cluster) { - content = "Cluster of " + feature.attributes.count + " IPs:"; - for (i in feature.cluster) { - content = content + "
" + feature.cluster[i].data.name; + content = "Cluster of " + feature.attributes.count + " IPs
Count: " + feature.attributes.ocount + "
"; + for (var i in feature.cluster) { + content = content + "
" + feature.cluster[i].attributes.name; } } else { - match = feature.data.description.search("offence: (.*?), count: (.*?), last_seen: (.*)"); - if (match == -1) { - console.log("Regex failed"); - content = "" + feature.data.name + "
" + feature.data.description; + if (feature.attributes.name && feature.attributes.offence && feature.attributes.ocount && feature.attributes.last_time) { + if (feature.attributes.first_time != feature.attributes.last_time) { + content = "" + feature.attributes.name + + "
Count: " + feature.attributes.ocount + + "
First time: " + feature.attributes.first_time + + "
Last time: " + feature.attributes.last_time; + } else { + content = "" + feature.attributes.name + + "
Count: " + feature.attributes.ocount + + "
Time: " + feature.attributes.last_time; + } } else { - content = "" + feature.data.name + "
Offence: " + RegExp.$1 + "
Count: " + RegExp.$2 + "
Last time seen: " + RegExp.$3; + content = "" + feature.data.name + "
" + feature.data.description; } } return content; } + +function redrawPopups() { + + //alert("Destroying all popups"); + for (var i in Banditvis.map.popups) { + Banditvis.map.popups[i].destroy(); + } + + var evt = { redraw: true, feature: null } + for (var i in Banditvis.selectedFeatures) { + for (var j in Banditvis.dataLayers) { + for (var k in Banditvis.dataLayers[j].features) { + + if (Banditvis.dataLayers[j].features[k].id == Banditvis.selectedFeatures[i].id){ + evt.feature = Banditvis.dataLayers[j].features[k]; + //alert("usel: " +evt.feature.id); + Banditvis.dataLayers[j].events.triggerEvent('featureunselected', evt); + //alert("sel: " +evt.feature.id); + Banditvis.dataLayers[j].events.triggerEvent('featureselected', evt); + + } else if (Banditvis.dataLayers[j].features[k].cluster != null) { + for (var l in Banditvis.dataLayers[j].features[k].cluster[l]) { + if(Banditvis.dataLayers[j].features[k].cluster[l].id == Banditvis.selectedFeatures[i].id) { + + evt.feature = Banditvis.dataLayers[j].features[k].cluster[l]; + Banditvis.dataLayers[j].events.triggerEvent('featureunselected', evt); + Banditvis.dataLayers[j].events.triggerEvent('featureselected', evt); + } + } + } + } + } + } + + return; +} + +function arrayAdd(feature) { + for (var i in Banditvis.selectedFeatures) { + if (Banditvis.selectedFeatures[i].id == feature.id) { + Banditvis.selectedFeatures.splice(i); + return false; + } + } + Banditvis.selectedFeatures.push(feature); + return true; +} + +function arrayRemove(feature) { + for (var i in Banditvis.selectedFeatures) { + if (Banditvis.selectedFeatures[i].id == feature.id) { + Banditvis.selectedFeatures.splice(i); + return true; + } + } + return false; +} + + + + + + + diff --git a/interactive/map.htm b/interactive/map.htm index c01dde8..9217370 100644 --- a/interactive/map.htm +++ b/interactive/map.htm @@ -4,10 +4,10 @@ + -
-
-
+
+
diff --git a/write_kml.py b/write_kml.py index 7fc2e3f..51da441 100755 --- a/write_kml.py +++ b/write_kml.py @@ -16,28 +16,35 @@ offences = db.cursor.fetchall() ### Write .kml for every offence +file1 = open("/var/lib/banditvis/output/offences.txt", "w") for offence in offences: offence = offence[0] - file = open("/var/lib/banditvis/output/"+offence+".kml", "w") - ### Print Header - file.write('\n') - file.write('\n') - file.write('\t\n') + file2 = open("/var/lib/banditvis/output/"+offence+".kml", "w") + + ### Print Prefix + file2.write('\n') + file2.write('\n') + file2.write('\t\n') ### Get and print Data - db.cursor.execute("SELECT ip_address, count, last_seen, ST_AsKML(location) FROM bandits WHERE offence = '"+offence+"'") + db.cursor.execute("SELECT ip_address, count, first_seen, last_seen, ST_AsKML(location) FROM bandits WHERE offence = '"+offence+"' ORDER BY last_seen ASC;") rows = db.cursor.fetchall() + i = 0 for row in rows: - file.write('\t\t\n') - file.write('\t\t\t'+row[0]+'\n') - file.write('\t\t\toffence: '+offence+', count: '+str(row[1])+', last_seen: '+str(row[2])+'\n') - file.write('\t\t\t'+row[3]+'\n') - file.write('\t\t\n') - - ### Print Trailer - file.write('\t\n') - file.write('') - file.close + i = i+1 + file2.write('\t\t\n') + file2.write('\t\t\t'+row[0]+'\n') + file2.write('\t\t\toffence: '+offence+', count: '+str(row[1])+', first_seen: '+str(row[2])+', last_seen: '+str(row[3])+'\n') + file2.write('\t\t\t'+row[4]+'\n') + file2.write('\t\t\n') + + ### Print Suffix + file2.write('\t\n') + file2.write('') + file2.close + file1.write(offence+'\n') + +file1.close ### Finished exit() \ No newline at end of file