split backend from ffmap-d3

This commit is contained in:
Nils Schneider 2012-09-14 01:48:23 +02:00
parent 8e518a3a85
commit ec7b89c670
80 changed files with 0 additions and 11250 deletions

9414
html/d3.v2.js vendored

File diff suppressed because it is too large Load diff

View file

@ -1,65 +0,0 @@
#chart {
background: #000;
}
.node ellipse {
stroke-width: 2.5px;
}
.node text, .label text {
font-size: 10px;
fill: #000;
}
.link line {
stroke: #ddd;
stroke-width: 5px;
}
.link.vpn line {
stroke-dasharray: 1px 6px;
stroke-linecap: round;
stroke-width: 2px;
}
.link line.unidirectional {
stroke-width: 2px;
}
.node ellipse {
fill: #fff;
stroke: #48f;
}
.node ellipse.gateway {
stroke: #ff7f0e;
fill: #ff7f03;
}
.node ellipse.client {
stroke: #ff0;
fill: #ff0;
stroke-width: 5px;
}
.uplinks path, .uplinks text {
fill: #0ff;
}
.strength {
font-size: 10px;
fill: #C83771;
}
#sidebar {
color: #ddd;
}
#sidebar text {
fill: #ddd;
font-size: 0.8em;
}
.label rect {
fill: rgba(255, 255, 255, 1.0);
}

View file

@ -1,77 +0,0 @@
#chart {
background-image: url(gplaypattern.png);
}
.node ellipse {
fill: #fff;
stroke-width: 2.5px;
}
.node text, .label text {
font-size: 10px;
fill: #333;
}
.link line {
stroke: #777;
stroke-width: 2.5px;
}
.link line.unidirectional {
stroke-width: 0.8px;
}
.link.vpn line {
stroke-dasharray: 0.75px 4px;
stroke-linecap: round;
stroke-width: 1.5px;
}
.link:hover line {
stroke-width: 5px;
}
.uplinks path {
fill: #333;
}
.node ellipse {
stroke: #AEC7E8;
}
.node ellipse.gateway {
stroke: #FF7F0E;
}
.node ellipse.client {
stroke: #1F77B4;
fill: #1F77B4;
}
.link .label {
fill: transparent;
stroke: #C83771;
stroke-width: 1px;
}
.strength {
font-size: 10px;
fill: #C83771;
}
#sidebar {
color: #777;
}
#sidebar text {
fill: #777;
font-size: 0.8em;
}
.label rect {
fill: rgba(255, 255, 255, 0.8);
}
.label.highlight rect {
fill: rgba(255, 255, 100, 0.9);
}

View file

@ -1,180 +0,0 @@
#chart, #chart svg {
display: block;
vertical-align: middle;
}
#chart {
position: relative;
}
.node.marked ellipse {
stroke: #C83771 !important;
stroke-width: 5px;
}
.link {
stroke-opacity: 0.8;
}
.faded {
stroke-opacity: 0.02;
fill-opacity: 0.1;
}
.node.highlight ellipse {
fill: #FFF0B3;
}
#nodeinfo {
position: absolute;
background: #fff;
border: 1px solid #ddd;
padding: 0.5em;
font-family: arial, helvatica;
}
#nodeinfo {
top: 10px;
left: 10px;
}
#nodeinfo button.close {
float: right;
}
#controlpanel {
font-size: 10pt;
display: inline-block;
color: #fff;
}
#controlpanel * {
display: inline;
}
#controlpanel p {
margin: 0 1em;
}
#nodeinfo h1, #nodeinfo p {
color: #555;
}
#nodeinfo h1 {
font-size: 10pt;
margin: 0 0 0.5em;
}
#nodeinfo h2 {
font-size: 9pt;
}
#nodeinfo p {
font-size: 10pt;
margin: 0;
}
.btn {
color: #6e6e6e;
font: bold 12px Helvetica, Arial, sans-serif;
text-decoration: none;
padding: 2px 8px;
position: relative;
display: inline-block;
text-shadow: 0 1px 0 #fff;
-webkit-transition: border-color .218s;
-moz-transition: border .218s;
-o-transition: border-color .218s;
transition: border-color .218s;
background: #f3f3f3;
background: -webkit-gradient(linear,0% 40%,0% 70%,from(#F5F5F5),to(#F1F1F1));
background: -moz-linear-gradient(linear,0% 40%,0% 70%,from(#F5F5F5),to(#F1F1F1));
border: solid 1px #dcdcdc;
border-radius: 2px;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
margin-right: 10px;
}
.btn:hover {
color: #333;
border-color: #999;
-moz-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2) -webkit-box-shadow:0 2px 5px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.btn:active {
color: #000;
border-color: #444;
}
.btn.left {
-webkit-border-top-right-radius: 0;
-moz-border-radius-topright: 0;
border-top-right-radius: 0;
-webkit-border-bottom-right-radius: 0;
-moz-border-radius-bottomright: 0;
border-bottom-right-radius: 0;
margin: 0;
}
.btn.middle {
border-left: solid 1px #f3f3f3;
margin: 0;
border-left: solid 1px rgba(255, 255, 255, 0);
}
.btn.right {
-webkit-border-top-left-radius: 0;
-moz-border-radius-topleft: 0;
border-top-left-radius: 0;
-webkit-border-bottom-left-radius: 0;
-moz-border-radius-bottomleft: 0;
border-bottom-left-radius: 0;
margin-left: -1px;
}
.btn.active {
background: #C83771;
color: #fff;
text-shadow: none;
}
#sidebar {
position: absolute;
top: 1em;
right: 1.5em;
z-index: 0;
font-size: 9pt;
}
#legend ul {
list-style: none;
}
#legend li {
margin-bottom: 0.5em;
}
#legend li svg {
margin-right: 0.5em;
display: inline;
vertical-align: center;
}
#sidebar h2 {
margin-top: 0;
font-size: 9pt;
}
footer {
position: absolute;
bottom: 0.2em;
right: 0.2em;
font-size: 8pt;
color: #777;
}
footer a {
color: #444;
}

View file

@ -1,709 +0,0 @@
var style;
function switch_style(s) {
var el = document.getElementsByTagName("link")
for (var i = 0; i < el.length; i++ ) {
if (el[i].getAttribute("rel").indexOf("style") != -1
&& el[i].getAttribute("title")) {
/* always set to true first to workaround Chrome bug */
el[i].disabled = true
if (el[i].getAttribute("title") == s)
el[i].disabled = false
}
}
style_btn.text(s)
}
function getOffset( el ) {
var _x = 0, _y = 0
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft
_y += el.offsetTop - el.scrollTop
el = el.offsetParent
}
return { top: _y, left: _x }
}
var w, h
resize()
window.onresize = resize
function resize() {
var offset = getOffset(document.getElementById('chart'))
w = window.innerWidth - offset.left
h = window.innerHeight - offset.top - 1
d3.select("#chart")
.attr("width", w).attr("height", h)
if (vis)
vis.attr("width", w).attr("height", h)
if (force)
force.size([w, h]).start()
}
function next_style() {
var s;
if (style !== undefined)
s = d3.select("head link[title=" + style + "] + link")
if (s == null || s[0][0] == null)
s = d3.select("head link[title]")
style = s[0][0].getAttribute("title")
switch_style(style)
}
var cp = d3.select("header").append("div")
.attr("id", "controlpanel")
var updated_at = cp.append("p")
cp.append("button")
.attr("class", "btn")
.attr("value", "reload")
.text("Aktualisieren")
.on("click", reload)
var style_btn = cp.append("button")
.attr("class", "btn")
.attr("value", "reload")
.text("Farbwechsler")
.on("click", next_style)
cp.append("button")
.attr("class", "btn")
.attr("value", "reload")
.on("click", pacman)
.append("svg")
.attr("width", 12)
.attr("height", 12)
.append("path")
.attr("d", d3.svg.arc().innerRadius(0)
.outerRadius(5)
.endAngle(-Math.PI/4 + Math.PI/2 + 2*Math.PI)
.startAngle(Math.PI/4 + Math.PI/2))
.attr("fill", "#888")
.attr("transform", "translate(6,7)")
var btns = cp.append("div")
.attr("class", "btn-group")
btns.append("button")
.attr("class", "btn active left")
.attr("value", "clients")
.text("Clients")
.on("click", update_graph)
btns.append("button")
.attr("class", "btn active middle")
.attr("value", "vpn")
.text("VPN")
.on("click", update_graph)
btns.append("button")
.attr("class", "btn active right")
.attr("value", "labels")
.text("Labels")
.on("click", update_graph)
var meshinfo = d3.select("#sidebar")
.insert("div", ":first-child")
meshinfo.append("h2").text("Mesh")
meshinfo.append("p")
.attr("id", "nodecount")
meshinfo.append("p")
.attr("id", "gatewaycount")
meshinfo.append("p")
.attr("id", "clientcount")
//cp.append("input")
// .on("keyup", function(){show_node(this.value)})
// .on("change", function(){show_node(this.value)})
function show_node(mac) {
d3.selectAll("#chart .node")
.classed("marked", false)
if (mac.length == 0)
return
d3.selectAll("#chart .node")
.each( function(d) {
if (d.id == mac)
d3.select(this)
.classed("marked", true)
})
}
var hashstr = window.location.hash.substring(1)
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] ||
linkedByIndex[b.index + "," + a.index] ||
a.index == b.index
}
function highlight(b) {
return function(d) {
if (dragging) return
vis.selectAll("g.node")
.classed("faded", function(o) {
return !(isConnected(d, o)) && b
})
.classed("highlight", function(o) {
return isConnected(d, o) && b
})
vis.selectAll("g.label")
.classed("faded", function(o) {
return !isConnected(d, o) && b
})
.classed("highlight", function(o) {
return o == d && b
})
vis.selectAll(".link")
  .classed("faded", function(o) {
 return !(o.source === d || o.target === d) && b
 })
  }
}
function goto_node(d) {
show_node_info(d)
}
function show_node_info(d) {
d3.selectAll("#nodeinfo").remove()
nodeinfo = d3.select("#chart")
.append("div")
.attr("id", "nodeinfo")
nodeinfo.append("button")
.attr("class", "close")
.text("x")
.on("click", function() {
nodeinfo.remove()
})
nodeinfo.append("button")
.attr("class", "refresh")
.text("refresh")
.on("click", function() {
goto_node(d)
})
nodeinfo.append("h1")
.text(d.name + " / " + d.id)
nodeinfo.append("p")
.append("label")
.text("macs: " + d.macs)
nodeinfo.append("h2").text("VPN-Links")
nodeinfo.append("ul")
.selectAll("li")
.data(d.vpns)
.enter().append("li")
.append("a")
.on("click", goto_node)
.attr("href", "#")
.text(function(d) {
return d.name || d.macs
})
if (d.geo) {
nodeinfo.append("h2").text("Geodaten")
nodeinfo.append("p")
.text(d.geo)
url = GMaps.staticMapURL({
size: [300, 100],
lat: d.geo[0],
lng: d.geo[1],
markers: [
{lat: d.geo[0], lng: d.geo[1]}
]
})
nodeinfo.append("img")
.attr("src", url)
}
}
function update_graph() {
jQuery(this).toggleClass("active")
var value = jQuery(this).val()
visible[value] = jQuery(this).hasClass("active")
update()
}
var vis = d3.select("#chart").append("svg")
.attr("width", w)
.attr("height", h)
vis.append("g").attr("class", "links")
vis.append("g").attr("class", "nodes")
vis.append("g").attr("class", "labels")
var linkedByIndex
var force = d3.layout.force()
.charge( function (d) {
if (d.flags.client)
return -30
return -100
})
.gravity(0.035)
.friction(0.73)
.theta(0.8)
.size([w, h])
.linkDistance(function (d) {
switch (d.type) {
case "client": return 20
default: return 70
}
})
.linkStrength(function (d) {
switch (d.type) {
case "vpn": return 0.01
case "client": return 1
default: return 0.2
}
})
function tick_event(e) {
var size = force.size()
var nodes = force.nodes()
var nl = nodes.length
for (i = 0; i < nl; i++) {
var n = nodes[i]
if (!n.fixed) {
if (n.x < n.rx + 20) n.x = n.rx + 20
if (n.x > size[0] - n.rx - 20) n.x = size[0] - n.rx - 20
if (n.y < n.ry + 20) n.y = n.ry + 20
if (n.y > size[1] - n.ry - 20 ) n.y = size[1] - n.ry - 20
}
}
var link = vis.selectAll(".link")
link.selectAll("line")
.attr("x1", function(d) { return d.source.x })
.attr("y1", function(d) { return d.source.y })
.attr("x2", function(d) { return d.target.x })
.attr("y2", function(d) { return d.target.y })
vis.selectAll(".node").attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
vis.selectAll(".label").attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
}
var data
var visible = {clients: true, vpn: true, labels: true}
function reload() {
d3.json(nodes_json, function(json) {
// update existing nodes with new info
// XXX inefficient data structure
json.nodes.forEach(function(d, i) {
var n
force.nodes().forEach(function(x) {if (x.id == d.id) n = x})
if (n) {
for (var key in d)
if (d.hasOwnProperty(key))
n[key] = d[key]
json.nodes[i] = n
}
})
json.links.forEach(function(d, i) {
var n
force.links().forEach(function(x) {if (x.id == d.id) n = x})
if (n) {
for (var key in d)
if (d.hasOwnProperty(key))
n[key] = d[key]
json.links[i] = n
}
})
// replace indices with real objects
json.links.forEach( function(d) {
if (typeof d.source == "number") d.source = json.nodes[d.source];
if (typeof d.target == "number") d.target = json.nodes[d.target];
})
// count vpn links
json.nodes.forEach(function(d) {
d.vpns = []
})
json.links.forEach(function(d) {
var node, other
if (d.type == "vpn") {
d.source.vpns.push(d.target)
d.target.vpns.push(d.source)
}
})
data = json
updated_at.text(d3.time.format("%X")(new Date()))
var nNodes = data.nodes.filter(function(d) {
return !d.flags.client && d.flags.online
}).length,
nGateways = data.nodes.filter(function(d) {
return d.flags.gateway && d.flags.online
}).length,
nClients = data.nodes.filter(function(d) {
return d.flags.client && d.flags.online
}).length
d3.select("#nodecount")
.text(nNodes + " Knoten")
d3.select("#gatewaycount")
.text(nGateways + " Gateways")
d3.select("#clientcount")
.text("ungefähr " + (nClients - nNodes) + " Clients")
data = wilder_scheiß(data)
update()
})
}
function fix_geonodes(nodes, x) {
nodes.filter(function(d) {
return d.geo !== null
}).forEach(function(d) {
d.fixed = x
})
}
function wilder_scheiß(data) {
var nodes = data.nodes.filter(function(d) {
return d.geo !== null
})
var lat = nodes.map(function(d) { return d.geo[0] })
var lon = nodes.map(function(d) { return d.geo[1] })
var max_lat = Math.min.apply(null, lat)
var min_lat = Math.max.apply(null, lat)
var min_lon = Math.min.apply(null, lon)
var max_lon = Math.max.apply(null, lon)
var width = force.size()[0]
var height = force.size()[1]
var scale_x = width / (max_lon - min_lon)
var scale_y = height / (max_lat - min_lat)
nodes.forEach(function(d) {
if (d.x || d.y)
return
d.x = (d.geo[1] - min_lon) * scale_x
d.y = (d.geo[0] - min_lat) * scale_y
})
return data
}
var dragging = false
var node_drag = d3.behavior.drag()
.on("dragstart", dragstart)
.on("drag", dragmove)
.on("dragend", dragend)
var d3_layout_forceDragNode
function dragstart(d) {
dragging = true
d3_layout_forceDragNode = d
d.fixed |= 2
}
function dragmove() {
d3_layout_forceDragNode.px = d3.event.x
d3_layout_forceDragNode.py = d3.event.y
force.resume() // restart annealing
}
function dragend() {
d3_layout_forceDragNode.fixed &= 1
d3_layout_forceDragNode = null
dragging = false
}
function update() {
var links = data.links
.filter(function (d) {
if (!visible.vpn && d.type == "vpn")
return false
if (!visible.clients && (d.source.flags.client || d.target.flags.client))
return false
// hides links to clients
if (!visible.vpn && (d.source.flags.vpn || d.target.flags.vpn))
return false
return true
})
var link = vis.select("g.links")
.selectAll("g.link")
.data(links, function(d) {
return d.id
})
var linkEnter = link.enter().append("g")
.attr("class", function(d) {
return "link " + d.type
})
.on("mouseover", function(d) {
if (dragging) return
d.source.fixed |= 2
d.target.fixed |= 2
})
.on("mouseout", function(d) {
if (dragging) return
d.source.fixed &= 1
d.target.fixed &= 1
})
linkEnter.append("line")
.append("title")
link.selectAll("line")
.filter( function (d) {
return d.type != 'client'
})
.style("stroke", function(d) {
switch (d.type) {
case "vpn":
return linkcolor['default'](Math.max.apply(null, d.quality.split(",")))
default:
return linkcolor['wifi'](Math.max.apply(null, d.quality.split(",")))
}
})
.attr("class", function(d) {
return d.quality.split(",").length==1?"unidirectional":"bidirectional"
})
link.selectAll("title")
.text( function (d) {
var s = d.quality
if (d.type)
s += " (" + d.type + ")"
return s
})
link.exit().remove()
var nodes = data.nodes.filter(function (d) {
if (!visible.vpn && d.flags.vpn)
return false
if (!visible.clients && d.flags.client)
return false
if (!d.flags.online)
return false
return true
})
.sort(function(a, b) {
return (a.flags.client?1:0) < (b.flags.client?1:0)
})
var node = vis.select("g.nodes")
.selectAll("g.node")
.data(nodes,
function(d) {
return d.id
}
)
var nodeEnter = node.enter().append("g")
.attr("id", function (d) {
return d.id
})
.attr("class", "node")
.on("mouseover", highlight(true))
.on("mouseout", highlight(false))
.on("click", goto_node)
.call(node_drag)
nodeEnter.append("ellipse")
node.selectAll("ellipse")
.attr("class", function(d) {
var s = []
for (var key in d.flags)
if (d.flags.hasOwnProperty(key) && d.flags[key])
s.push(key)
return s.join(" ")
})
node.selectAll("ellipse")
.attr("rx", function(d) {
var r
if (d.flags.client) r = 4
else r = 8
d.rx = r
return r
})
.attr("ry", function(d) {
var r
if (d.flags.client) r = 4
else r = 8
d.ry = r
return r
})
var label = vis.select("g.labels")
.selectAll("g.label")
.data(nodes.filter(function(d) {
return !d.flags.client && visible.labels
}), function(d) {
return d.id
}
)
var labelEnter = label.enter()
.append("g")
.attr("id", function (d) {
return d.id
})
.attr("class", "label")
labelEnter.append("rect")
.attr("y", "10px")
.attr("x", function(d) { return - d.name.length * 7/2 })
.attr("width", function(d) { return d.name.length * 7 })
.attr("height", "15px")
labelEnter.append("text")
.attr("class", "name")
.attr("text-anchor", "middle")
.attr("y", "21px")
.attr("x", "0px")
label.selectAll("text.name")
.text(function(d) {
return d.name
})
label.exit().remove()
nodeEnter.append("title")
node.selectAll("title")
.text(function(d) { return d.name?d.name:" " })
node.selectAll(".uplinks").remove()
if (!visible.vpn) {
var uplink_info = node.filter(function (d) {
return d.vpns.length > 0
})
.append("g")
.attr("class", "uplinks")
uplink_info.append("path")
.attr("d","m -2.8850049,-13.182327"
+ "c 7.5369165,0.200772 12.1529864,-1.294922 12.3338513,-10.639456"
+ "l 2.2140476,1.018191 -3.3137621,-5.293097 -3.2945999,5.20893 2.4339957,-0.995747"
+ "c -0.4041883,5.76426 -1.1549641,10.561363 -10.3735326,10.701179 z")
uplink_info.append("text")
.attr("text-anchor", "middle")
.attr("y", 3 - 20)
.text(function (d) {return d.vpns.length})
}
node.exit().remove()
force.nodes(nodes)
.links(links)
.alpha(0.1)
.start()
if (initial == 1) {
fix_geonodes(data.nodes, true)
force.alpha(0.1)
while(force.alpha() > 0.05)
force.tick()
fix_geonodes(data.nodes, false)
force.alpha(0.1)
while(force.alpha() > 0.05)
force.tick()
force.on("tick", tick_event)
force.start()
}
initial = 0
linkedByIndex = {}
links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1
})
if (hashstr.length != 0)
show_node(hashstr)
}
var initial = 1
reload()
var timer = window.setInterval(reload, 30000)

View file

@ -1,65 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="theme/default/style.css" type="text/css" />
<link href='style.css' rel='stylesheet' type='text/css' />
<style type="text/css">
#map {
width: 100%;
box-sizing:border-box;
}
.olPopup p { margin:0px; }
.nodePopup { font-size: 0.8em; }
.nodePopup .label { font-weight: bold; }
</style>
<title>Freifunk Lübeck - Knotenkarte</title>
<script src="http://maps.burningsilicon.net/OpenLayers-2.8/OpenLayers.js"></script>
<script src="http://maps.burningsilicon.net/OpenLayers-2.8/OpenStreetMap.js"></script>
<script type="text/javascript" src="d3.v2.js"></script>
<script type="text/javascript" src="links.js"></script>
<script type="text/javascript" src="geomap.js"></script>
<script type="text/javascript">
var nodes_json = "nodes.json"
window.onresize = resize
function getOffset( el ) {
var _x = 0, _y = 0
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft
_y += el.offsetTop - el.scrollTop
el = el.offsetParent
}
return { top: _y, left: _x }
}
function resize() {
var offset = getOffset(document.getElementById('map'))
var w = window.innerWidth - offset.left
var h = window.innerHeight - offset.top - 1
d3.select("#map").style("width", w+"px").style("height", h+"px")
resizeMap()
}
</script>
</head>
<body onload="resize(); init()">
<header>
<h1>luebeck.freifunk.net</h1>
<ul>
<li><a href="nodes.html">Knotengraph</a></li>
<li><a href="geomap.html">Knotenkarte</a></li>
</ul>
<button id="gpsbutton">Koordinaten beim nächsten Klick anzeigen</button>
</header>
<div id="map"></div>
</body>
</html>

View file

@ -1,163 +0,0 @@
var map;
var vectorLayer;
var nodes_json = "nodes.json"
OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control);
function init()
{
map = new OpenLayers.Map ("map", {
controls:[
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.Attribution(),
new OpenLayers.Control.ScaleLine(),
new OpenLayers.Control.MousePosition()],
maxResolution: 156543.0399,
numZoomLevels: 19,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
} );
arrayOSM = ["http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.jpg",
"http://otile2.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.jpg",
"http://otile3.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.jpg",
"http://otile4.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.jpg"];
var baseOSM = new OpenLayers.Layer.OSM("MapQuest-OSM Tiles", arrayOSM, {opacity: 0.6});
map.addLayer(baseOSM);
var center = new OpenLayers.LonLat(10.688, 53.866).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
var zoom = 13
map.setCenter(center, zoom);
vectorLayer = new OpenLayers.Layer.Vector("Nodes");
map.addLayer(vectorLayer);
selectControl = new OpenLayers.Control.SelectFeature(map.layers[1],
{onSelect: onFeatureSelect, onUnselect: onFeatureUnselect});
map.addControl(selectControl);
selectControl.activate();
var click = new OpenLayers.Control.Click();
map.addControl(click);
click.activate();
load_json(vectorLayer, map)
d3.selectAll("#gpsbutton").on("click", function() {
function clickhandler(e) {
var lonlat = map.getLonLatFromViewPortPx(e.xy).transform(map.getProjectionObject(), new OpenLayers.Projection("EPSG:4326"))
alert(lonlat.lat + " " + lonlat.lon)
map.events.unregister("click", map, clickhandler)
}
var clickevent = map.events.register("click", map, clickhandler)
})
}
function resizeMap()
{
if (map !== undefined) {
map.updateSize()
// Did someone say Chrome bug?
map.removeLayer(vectorLayer)
map.addLayer(vectorLayer)
}
}
function onPopupClose(evt)
{
selectControl.unselect(selectedFeature);
}
function onFeatureSelect(feature)
{
selectedFeature = feature;
popup = new OpenLayers.Popup.FramedCloud("chicken",
feature.geometry.getBounds().getCenterLonLat(),
new OpenLayers.Size(100,150),
"<div class='nodePopup'><span class='label'>Name:</span> "+feature.attributes.name+"<br><span class='label'>Description:</span> "+feature.attributes.description+"</div>",
null, true, onPopupClose);
feature.popup = popup;
map.addPopup(popup);
}
function onFeatureUnselect(feature)
{
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
function kmlLoaded()
{
map.zoomToExtent(vectorLayer.getDataExtent());
}
function load_json(layer, map) {
d3.json(nodes_json, function(json) {
// replace indices with real objects
json.links.forEach( function(d) {
if (typeof d.source == "number") d.source = json.nodes[d.source]
if (typeof d.target == "number") d.target = json.nodes[d.target]
})
json.nodes.filter( function(d) {
return d.geo !== null
}).forEach( function(d) {
var lonlat = new OpenLayers.LonLat(d.geo[1], d.geo[0])
.transform( new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject()
);
var img = d.flags.online?"router-up.png":"router-down.png"
var feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat),
{name: d.name, description: d.id},
{externalGraphic: img, graphicHeight: 32, graphicWidth: 32}
)
layer.addFeatures([feature])
})
json.links.filter( function(d) {
return d.source.geo !== null && d.target.geo !== null &&
d.type != "vpn"
}).forEach( function(d) {
var a = new OpenLayers.LonLat(d.source.geo[1], d.source.geo[0])
.transform( new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject()
);
var b = new OpenLayers.LonLat(d.target.geo[1], d.target.geo[0])
.transform( new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject()
);
var color;
switch (d.type) {
case "vpn":
color = linkcolor['default'](Math.max.apply(null, d.quality.split(",")))
break;
default:
color = linkcolor['wifi'](Math.max.apply(null, d.quality.split(",")))
}
var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(
[new OpenLayers.Geometry.Point(a.lon, a.lat),
new OpenLayers.Geometry.Point(b.lon, b.lat),
]),
{name: d.name, description: d.id},
{
strokeColor: d3.rgb(color).brighter(1),
strokeOpacity: 0.8,
strokeWidth: 3
})
layer.addFeatures([feature])
})
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

4
html/jquery.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,11 +0,0 @@
var linkcolor = {'default':
d3.scale.linear()
.domain([1, 1.25, 1.5])
.range(["#0a3", "orange", "red"]),
'wifi':
d3.scale.linear()
.domain([1, 3, 10])
.range(["#0a3", "orange", "red"]),
}

View file

@ -1,93 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Freifunk Lübeck - Knotengraph</title>
<link href='style.css' rel='stylesheet' type='text/css' />
<link href='force.css' rel='stylesheet' type='text/css' />
<link href='force-big.css' rel='alternate stylesheet' type='text/css' title='big'/>
<link href='force-light.css' rel='stylesheet' type='text/css' title='light'/>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="d3.v2.js"></script>
<script type="text/javascript" src="pacman.js"></script>
<script src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script src="https://raw.github.com/HPNeo/gmaps/master/gmaps.js"></script>
<script>
var nodes_json = "nodes.json"
</script>
</head>
<body>
<header>
<h1>luebeck.freifunk.net</h1>
<ul>
<li><a href="nodes.html">Knotengraph</a></li>
<li><a href="geomap.html">Knotenkarte</a></li>
</ul>
</header>
<div id="chart">
<div id="sidebar">
<div id="legend">
<h2>Legende</h2>
<ul>
<li><svg width=30 height=20 class="node">
<ellipse cx=15 cy=10 ry=8 rx=8 />
</svg>
<label>Knoten</label>
</li>
<li><svg width=30 height=20 class="node">
<ellipse cx=15 cy=10 ry=8 rx=8 class="gateway"/>
</svg>
<label>Gateway</label>
</li>
<li><svg width=30 height=20 class="node">
<ellipse cx=15 cy=10 ry=4 rx=4 class="client"/>
</svg>
<label>Client</label>
</li>
<li><svg width=30 height=20 class="link">
<line x1="2" y1="10" x2="28" y2="10"/>
</svg>
<label>Link</label>
</li>
<li><svg width=30 height=20 class="link vpn">
<line x1="2" y1="10" x2="28" y2="10"/>
</svg>
<label>VPN-Link</label>
</li>
<li><svg width=140 height=25 class="link vpn">
<defs>
<linearGradient id="linkgrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#0a3" />
<stop offset="50%" stop-color="orange" />
<stop offset="100%" stop-color="red" />
</linearGradient>
</defs>
<rect x="18" y="12" width="88" height="6" fill="url(#linkgrad)"/>
<text text-anchor="middle" y=8 x=18>gut</text>
<text text-anchor="middle" y=8 x=106>schlecht</text>
</svg>
</li>
<li><svg width=30 height=20 class="node uplinks">
<g transform="translate(12,28)">
<line x1="2" y1="10" x2="28" y2="10" stroke="#000"/>
<path d="m -2.8850049,-13.182327 c 7.5369165,0.200772 12.1529864,-1.294922
12.3338513,-10.639456 l 2.2140476,1.018191 -3.3137621,-5.293097
-3.2945999,5.20893 2.4339957,-0.995747 c -0.4041883,5.76426
-1.1549641,10.561363 -10.3735326,10.701179 z"/>
<text text-anchor="middle" y=-17></text>
</g>
</svg>
<label>Anzahl VPN-Links</label>
</li>
</ul>
</div>
</div>
</div>
<footer>
<a href="http://tcatm.github.com/ffmap-d3/">ffmap-d3</a> — © Nils Schneider</a>
</footer>
<script src='links.js' type='text/javascript'></script>
<script src='force.js' type='text/javascript'></script>
</body>
</html>

View file

@ -1,72 +0,0 @@
function pacman() {
var angle = d3.scale.linear()
.domain([0, 1, 2, 3])
.range([0.01, Math.PI/4, 0.01, Math.PI/4])
d3.timer(pacman_animate)
var a = 0
var p = {x: 0, y: 0}
var pm = vis.append("path")
.style("fill", "#ff0")
.style("stroke", "#000")
.style("stroke-width", 2.5)
.style("stroke-linejoin", "round")
function pacman_animate() {
var size = force.size()
var nodes = force.nodes()
var n = nodes.length
if (n == 0)
return
a = (a + 0.10)%2
pm.attr("d", d3.svg.arc().innerRadius(0)
.outerRadius(24).endAngle(-angle(a) + Math.PI/2 + 2*Math.PI).startAngle(angle(a) + Math.PI/2))
var closest = null
var dd = Infinity;
for (i = 0; i < n; i++) {
var o = nodes[i]
var d = Math.pow((o.x - p.x),2) + Math.pow( o.y - p.y, 2)
if (d < dd) {
dd = d
closest = o
}
}
var dx = closest.x - p.x
var dy = closest.y - p.y
var d = Math.sqrt(Math.pow(dx,2) + Math.pow(dy,2))
dx = dx/d
dy = dy/d
if (d>8) {
p.x += dx * 2
p.y += dy * 6
} else {
var snd;
if (closest.flags.client) {
snd = new Audio("pacman_eatfruit.wav")
} else {
snd = new Audio("pacman_eatghost.wav")
}
snd.play()
data.nodes = data.nodes.filter(function (d) {
return d.id != closest.id
})
data.links = data.links.filter(function (d) {
return d.target.id != closest.id && d.source.id != closest.id
})
update()
}
pm.attr("transform", "matrix(" + [dx, dy, -dy, dx, p.x, p.y].join(",") + ")")
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -1,38 +0,0 @@
body {
margin: 0;
padding: 0;
font-family: sans serif;
}
header h1, ul {
margin: 0;
padding: 0;
}
header h1, header ul, header ul li {
display: inline-block;
font-size: 10pt;
}
header h1, header ul li a {
padding: 0.5em;
}
header ul {
list-style: none;
padding: 0;
}
header {
background: #333;
color: #fefefe;
}
header a {
text-decoration: none;
color: #FFCC01;
}
header a:hover {
background: #C83771;
}

View file

@ -1,9 +0,0 @@
.olLayerGoogleCopyright {
right: 3px;
bottom: 2px;
}
.olLayerGooglePoweredBy {
left: 2px;
bottom: 2px;
}

View file

@ -1,7 +0,0 @@
.olControlZoomPanel div {
background-image: url(img/zoom-panel-NOALPHA.png);
}
.olControlPanPanel div {
background-image: url(img/pan-panel-NOALPHA.png);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1,343 +0,0 @@
div.olMap {
z-index: 0;
padding: 0px!important;
margin: 0px!important;
cursor: default;
}
div.olMapViewport {
text-align: left;
}
div.olLayerDiv {
-moz-user-select: none;
}
.olLayerGoogleCopyright {
left: 2px;
bottom: 2px;
}
.olLayerGooglePoweredBy {
left: 2px;
bottom: 15px;
}
.olControlAttribution {
font-size: smaller;
right: 3px;
bottom: 4.5em;
position: absolute;
display: block;
}
.olControlScale {
right: 3px;
bottom: 3em;
display: block;
position: absolute;
font-size: smaller;
}
.olControlScaleLine {
left: 10px;
bottom: 15px;
font-size: xx-small;
}
.olControlScaleLineBottom {
border: solid 2px black;
border-bottom: none;
margin-top:-2px;
text-align: center;
}
.olControlScaleLineTop {
border: solid 2px black;
border-top: none;
text-align: center;
}
.olControlPermalink {
right: 3px;
bottom: 1.5em;
display: block;
position: absolute;
font-size: smaller;
}
div.olControlMousePosition {
bottom: 0em;
right: 3px;
display: block;
position: absolute;
font-family: Arial;
font-size: smaller;
}
.olControlOverviewMapContainer {
position: absolute;
bottom: 0px;
right: 0px;
}
.olControlOverviewMapElement {
padding: 10px 18px 10px 10px;
background-color: #00008B;
-moz-border-radius: 1em 0 0 0;
}
.olControlOverviewMapMinimizeButton {
right: 0px;
bottom: 80px;
}
.olControlOverviewMapMaximizeButton {
right: 0px;
bottom: 80px;
}
.olControlOverviewMapExtentRectangle {
overflow: hidden;
background-image: url("img/blank.gif");
cursor: move;
border: 2px dotted red;
}
.olControlOverviewMapRectReplacement {
overflow: hidden;
cursor: move;
background-image: url("img/overview_replacement.gif");
background-repeat: no-repeat;
background-position: center;
}
.olLayerGeoRSSDescription {
float:left;
width:100%;
overflow:auto;
font-size:1.0em;
}
.olLayerGeoRSSClose {
float:right;
color:gray;
font-size:1.2em;
margin-right:6px;
font-family:sans-serif;
}
.olLayerGeoRSSTitle {
float:left;font-size:1.2em;
}
.olPopupContent {
padding:5px;
overflow: auto;
}
.olControlNavToolbar {
width:0px;
height:0px;
}
.olControlNavToolbar div {
display:block;
width: 28px;
height: 28px;
top: 300px;
left: 6px;
position: relative;
}
.olControlNavigationHistory {
background-image: url("img/navigation_history.png");
background-repeat: no-repeat;
width: 24px;
height: 24px;
}
.olControlNavigationHistoryPreviousItemActive {
background-position: 0px 0px;
}
.olControlNavigationHistoryPreviousItemInactive {
background-position: 0px -24px;
}
.olControlNavigationHistoryNextItemActive {
background-position: -24px 0px;
}
.olControlNavigationHistoryNextItemInactive {
background-position: -24px -24px;
}
.olControlNavToolbar .olControlNavigationItemActive {
background-image: url("img/panning-hand-on.png");
background-repeat: no-repeat;
}
.olControlNavToolbar .olControlNavigationItemInactive {
background-image: url("img/panning-hand-off.png");
background-repeat: no-repeat;
}
.olControlNavToolbar .olControlZoomBoxItemActive {
background-image: url("img/drag-rectangle-on.png");
background-color: orange;
background-repeat: no-repeat;
}
.olControlNavToolbar .olControlZoomBoxItemInactive {
background-image: url("img/drag-rectangle-off.png");
background-repeat: no-repeat;
}
.olControlEditingToolbar {
float:right;
right: 0px;
height: 30px;
width: 200px;
}
.olControlEditingToolbar div {
background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
float:right;
width: 24px;
height: 24px;
margin: 5px;
}
.olControlEditingToolbar .olControlNavigationItemActive {
background-position: -103px -23px;
}
.olControlEditingToolbar .olControlNavigationItemInactive {
background-position: -103px -0px;
}
.olControlEditingToolbar .olControlDrawFeaturePointItemActive {
background-position: -77px -23px;
}
.olControlEditingToolbar .olControlDrawFeaturePointItemInactive {
background-position: -77px -0px;
}
.olControlEditingToolbar .olControlDrawFeaturePathItemInactive {
background-position: -51px 0px;
}
.olControlEditingToolbar .olControlDrawFeaturePathItemActive {
background-position: -51px -23px;
}
.olControlEditingToolbar .olControlDrawFeaturePolygonItemInactive {
background-position: -26px 0px;
}
.olControlEditingToolbar .olControlDrawFeaturePolygonItemActive {
background-position: -26px -23px ;
}
.olControlSaveFeaturesItemActive {
background-image: url(img/save_features_on.png);
background-repeat: no-repeat;
background-position: 0px 1px;
}
.olControlSaveFeaturesItemInactive {
background-image: url(img/save_features_off.png);
background-repeat: no-repeat;
background-position: 0px 1px;
}
.olHandlerBoxZoomBox {
border: 2px solid red;
position: absolute;
background-color: white;
opacity: 0.50;
font-size: 1px;
filter: alpha(opacity=50);
}
.olHandlerBoxSelectFeature {
border: 2px solid blue;
position: absolute;
background-color: white;
opacity: 0.50;
font-size: 1px;
filter: alpha(opacity=50);
}
.olControlPanPanel {
top: 10px;
left: 5px;
}
.olControlPanPanel div {
background-image: url(img/pan-panel.png);
height: 18px;
width: 18px;
cursor: pointer;
position: absolute;
}
.olControlPanPanel .olControlPanNorthItemInactive {
top: 0px;
left: 9px;
background-position: 0px 0px;
}
.olControlPanPanel .olControlPanSouthItemInactive {
top: 36px;
left: 9px;
background-position: 18px 0px;
}
.olControlPanPanel .olControlPanWestItemInactive {
position: absolute;
top: 18px;
left: 0px;
background-position: 0px 18px;
}
.olControlPanPanel .olControlPanEastItemInactive {
top: 18px;
left: 18px;
background-position: 18px 18px;
}
.olControlZoomPanel {
top: 71px;
left: 14px;
}
.olControlZoomPanel div {
background-image: url(img/zoom-panel.png);
position: absolute;
height: 18px;
width: 18px;
cursor: pointer;
}
.olControlZoomPanel .olControlZoomInItemInactive {
top: 0px;
left: 0px;
background-position: 0px 0px;
}
.olControlZoomPanel .olControlZoomToMaxExtentItemInactive {
top: 18px;
left: 0px;
background-position: 0px -18px;
}
.olControlZoomPanel .olControlZoomOutItemInactive {
top: 36px;
left: 0px;
background-position: 0px 18px;
}
.olPopupCloseBox {
background: url("img/close.gif") no-repeat;
cursor: pointer;
}
.olFramedCloudPopupContent {
padding: 5px;
overflow: auto;
}
.olControlNoSelect {
-moz-user-select: none;
}
/**
* Cursor styles
*/
.olCursorWait {
cursor: wait;
}
.olDragDown {
cursor: move;
}
.olDrawBox {
cursor: crosshair;
}
.olControlDragFeatureOver {
cursor: move;
}
.olControlDragFeatureActive.olControlDragFeatureOver.olDragDown {
cursor: -moz-grabbing;
}