Mercurial > linkmap
changeset 0:fb5784aa45e6 default tip
from monotone. problematic https vs v2 API
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 21 Oct 2012 23:03:51 +0800 |
parents | |
children | |
files | bluedot.png conv.py freenet_data.js labeled_marker.js linkmap.html yellowdot.png |
diffstat | 6 files changed, 522 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conv.py Sun Oct 21 23:03:51 2012 +0800 @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# This Python file uses the following encoding: utf-8 + +import re +import sys + +s = """ +PerthAP: 31°57'34.78"S 115°52'20.29"E +WannerooAP: 31°47'26.03"S 115°49'12.34"E +Belmont2: 31°57'34.19"S 115°55'42.52"E +MitchLand: 31°47'17.81"S 115°46'10.70"E +Mystic: 31°46'19.51"S 115°45'43.89"E +NHE (Welvis): 31°46'29.52"S 115°49'7.87"E +Doubleview: 31°53'41.14"S 115°46'50.86"E +BelmontAP: 31°57'4.63"S 115°55'15.38"E +Zaphod: 31°46'13.77"S 115°46'11.24"E +TIC Hill: 31°49'32.77"S 116°3'51.87"E +kaelnorr: 31°40'40.79"S 115°42'58.29"E +""" + +l = s.split('\n') + +r = re.compile(r'(\d+)°(\d+)\'([\d\.]+)".') + +def coord_to_decimal(coord): + lparts = r.match(coord) + deg, min, sec = map(float, lparts.groups()) + val = deg + min/60.0 + sec/(60.0**2) + + return val + +for i in l: + try: + name, coords = i.split(':') + + lat, long = coords.strip().split() + + lat_dec = -coord_to_decimal(lat) + long_dec = coord_to_decimal(long) + + print '"%s": [%f, %f, "%s", ""],' % (name.lower(), lat_dec, long_dec, name) + + except Exception, e: + print>>sys.stderr, "Error for line '%s': %s" % (i, e) + continue + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freenet_data.js Sun Oct 21 23:03:51 2012 +0800 @@ -0,0 +1,62 @@ +// format is +// 'nodeid': [lat, long, "Name", "Description", "url"] +// nodeid should be lowercase (for simplicity) +// lat/long must be decimal coords. +// Name and Description can be anything, valid HTML helps, so escape ampersands etc... +// url is optional + +freenet_nodes = { + + "perthap": [-31.959661, 115.872303, "PerthAP", ""], + "wannerooap": [-31.790564, 115.820094, "WannerooAP", ""], + "belmont2": [-31.959497, 115.928478, "Belmont2", ""], + "mitchland": [-31.788281, 115.769639, "MitchLand", ""], + "mystic": [-31.772086, 115.762192, "Mystic", ""], + "nhe": [-31.774867, 115.818853, "NHE (Welvis)", ""], + "doubleview": [-31.894761, 115.780794, "KodEBlaK", ""], + "belmontap": [-31.951286, 115.920939, "BelmontAP", ""], + "frogstar1": [-31.770429, 115.76983, "Frogstar 1", "15m", "http://www.wafreenet.org/node-Frogstar"], + "frogstar2": [-31.767973, 115.771309, "Frogstar 2", "22m", "http://www.wafreenet.org/node-Frogstar"], + "tichill": [-31.825769, 116.064408, "TIC Hill", ""], + "niak": [-32.101311, 115.943632, "niak", ""], + "msh": [-31.9285, 115.9085, "msh", ""], + "kaelnorr": [-31.6779966, 115.7161922, "kaelnorr", "", ""], + // the following are guessed from the map. + "duncraig": [-31.83017,115.772552, "Duncraig", "", "http://www.wafreenet.org/node-Duncraig"], + "spiked": [-31.812521,115.86113, "Spiked", "", "http://www.wafreenet.org/node-Spiked"], + "dericote": [-31.831774,115.803795, "Dericote", "", "http://www.wafreenet.org/node-Dericote"], + "vipernet": [-31.842566,115.801907, "Vipernet", "", "http://www.wafreenet.org/node-Vipernet"], + "bungknee": [-31.739263,115.801392, "Bungknee", "", ""], + "wirelesshill": [-32.030754,115.827302, "Wireless Hill", "", ""], + "jandakot": [-32.099736,115.870743, "Jandakot", "", "http://www.wafreenet.org/node-Jandakot"], + "armadale": [-32.128669,116.002235, "ArmadaleAP", "", "http://www.wafreenet.org/node-ArmadaleAP"], + "sgnet": [-32.132304,115.997772, "SGNet", "", "http://www.wafreenet.org/node-SGNet"] +}; + +// format is ['kind', 'node1', 'node2']. +// Make sure that nodes are defined in the freenet_nodes list above. +// Defined kinds are: +// '2ghz', '5ghz', 'vpn'. + +freenet_links = [ + [ '5ghz', 'perthap', 'tichill'], + [ '5ghz', 'niak', 'tichill'], + [ '5ghz', 'mitchland', 'mystic'], + [ '5ghz', 'nhe', 'mitchland'], + [ '5ghz', 'belmontap', 'belmont2'], + [ '5ghz', 'perthap', 'belmont2'], + [ '5ghz', 'msh', 'perthap'], + [ '5ghz', 'mystic', 'frogstar1'], + [ '5ghz', 'mitchland', 'frogstar1'], + [ 'vpn', 'mitchland', 'kaelnorr'], + [ '5ghz', 'mitchland', 'wannerooap'], + [ '5ghz', 'mystic', 'wannerooap'], + [ '5ghz', 'doubleview', 'wannerooap'], + [ '5ghz', 'doubleview', 'perthap'], + [ '5ghz', 'duncraig', 'nhe'], + [ '2ghz', 'mystic', 'spiked'], + [ '2ghz', 'mystic', 'dericote'], + [ '5ghz', 'mystic', 'vipernet'], + [ '2ghz', 'jandakot', 'armadale'], + [ '2ghz', 'sgnet', 'armadale'] +];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/labeled_marker.js Sun Oct 21 23:03:51 2012 +0800 @@ -0,0 +1,106 @@ +/* +* LabeledMarker Class +* +* Copyright 2007 Mike Purvis (http://uwmike.com) +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This class extends the Maps API's standard GMarker class with the ability +* to support markers with textual labels. Please see articles here: +* +* http://googlemapsbook.com/2007/01/22/extending-gmarker/ +* http://googlemapsbook.com/2007/03/06/clickable-labeledmarker/ +*/ + +/* Constructor */ +function LabeledMarker(latlng, options){ + this.latlng = latlng; + this.labelText = options.labelText || ""; + this.labelClass = options.labelClass || "markerLabel"; + this.labelOffset = options.labelOffset || new GSize(0, 0); + + this.clickable = options.clickable || true; + + if (options.draggable) { + // This version of LabeledMarker doesn't support dragging. + options.draggable = false; + } + + GMarker.apply(this, arguments); +} + + +/* It's a limitation of JavaScript inheritance that we can't conveniently + extend GMarker without having to run its constructor. In order for the + constructor to run, it requires some dummy GLatLng. */ +LabeledMarker.prototype = new GMarker(new GLatLng(0, 0)); + + +// Creates the text div that goes over the marker. +LabeledMarker.prototype.initialize = function(map) { + // Do the GMarker constructor first. + GMarker.prototype.initialize.apply(this, arguments); + + var div = document.createElement("div"); + div.className = this.labelClass; + div.innerHTML = this.labelText; + div.style.position = "absolute"; + map.getPane(G_MAP_MARKER_PANE).appendChild(div); + + if (this.clickable) { + // Pass through events fired on the text div to the marker. + var eventPassthrus = ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout']; + for(var i = 0; i < eventPassthrus.length; i++) { + var name = eventPassthrus[i]; + GEvent.addDomListener(div, name, newEventPassthru(this, name)); + } + + // Mouseover behaviour for the cursor. + div.style.cursor = "pointer"; + } + + this.map = map; + this.div = div; +} + +function newEventPassthru(obj, event) { + return function() { + GEvent.trigger(obj, event); + }; +} + +// Redraw the rectangle based on the current projection and zoom level +LabeledMarker.prototype.redraw = function(force) { + GMarker.prototype.redraw.apply(this, arguments); + + // We only need to do anything if the coordinate system has changed + if (!force) return; + + // Calculate the DIV coordinates of two opposite corners of our bounds to + // get the size and position of our rectangle + var p = this.map.fromLatLngToDivPixel(this.latlng); + var z = GOverlay.getZIndex(this.latlng.lat()); + + // Now position our DIV based on the DIV coordinates of our bounds + this.div.style.left = (p.x + this.labelOffset.width) + "px"; + this.div.style.top = (p.y + this.labelOffset.height) + "px"; + this.div.style.zIndex = z + 1; // in front of the marker +} + +// Remove the main DIV from the map pane, destroy event handlers +LabeledMarker.prototype.remove = function() { + GEvent.clearInstanceListeners(this.div); + this.div.parentNode.removeChild(this.div); + this.div = null; + GMarker.prototype.remove.apply(this, arguments); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linkmap.html Sun Oct 21 23:03:51 2012 +0800 @@ -0,0 +1,307 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"> + <head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"/> + + <title>Link Map</title> + + <style type="text/css"><!-- + body{font-family: sans-serif; height:99%; margin:0; padding:0;} + html{height:99%; margin:0; padding:0;} + #error_log { + font-family: Courier, "Courier New", monospace, Fixed; + border: 3px solid red; + padding: 0.5em; + margin: 0.5em; + display: none; + } + #map_canvas { + height:99%; + width: 100%; + margin:0; + padding:0; + } + + #legend { + font-size: small; + background-color: #fff; + opacity: 0.7; + text-align: left; + padding: 0.5em; + border: 1px solid black; + } + + #legend div { + vertical-align: middle; + display: inline-block; + margin-right: 1em; + } + + .node_label_id { + font-size: smaller; + } + .node_marker_label { + font-size: small; + font-weight: bold; + color: #800; + opacity: 0.9; + } + //--> + </style> + + <script> + // define some constants for colours etc: + LINKED_ICON = 'bluedot.png'; + UNLINKED_ICON = 'yellowdot.png'; + ICON_SIZE_W = 18; + ICON_SIZE_H = 18; + + LINK_COLOUR_5GHZ = '#080'; + LINK_COLOUR_2GHZ = '#00f'; + LINK_COLOUR_VPN = '#777'; + LINK_OPACITY = 0.7; + LINK_WIDTH = 4; + + LEGEND_X_OFFSET = 7; + LEGEND_Y_OFFSET = 240; + + CENTRE_COORDS_LAT = -31.9554; + CENTRE_COORDS_LNG = 115.85859; + + // Note that these don't really help with privacy - people + // can always inspect the raw javascript. Manually alter coordinates + // if desired. + MAX_ZOOM = 13; + MIN_ZOOM = 3; + INIT_ZOOM = 10; + + </script> + + <!-- load the nodes and links. --> + <script src="freenet_data.js"></script> + + <script> + + var key = { + 'localhost': 'ABQIAAAAN6v4BE-QSU4eUIUlNyDwJBT2yXp_ZAY8_ufC3CFXhHIE1NvwkxQeuZtV4Gh5jn5-Mzkw8HaJ-hZUxQ', + 'matt.ucc.asn.au': 'ABQIAAAAN6v4BE-QSU4eUIUlNyDwJBTcvFJ22Qq_4Wpg4VhVaFRl5W3cyxRmrAk6RVdmqxBPO7KK8gwSWsrFVg', + 'www.wafreenet.org': 'ABQIAAAAN6v4BE-QSU4eUIUlNyDwJBRTyFF_GlE7_llDeWLTuKgydpOCLhQydqjQALO8ZGbbZw5VaoTB-DBcMw', + }[window.location.host] + if (!key) { + key = + 'ABQIAAAAN6v4BE-QSU4eUIUlNyDwJBTR5ei7CukQRzAV2g5VZ7MlqVyAPxSs6pg6K2o24gSmaclijIuM-Q9KcA'; + } + document.write([ + '<script src="https://maps.google.com/maps?file=api&v=2&key=', + key, + '" type="text/javascript"><\/script>' + ].join('')); + </script> + + <!-- 3rd party labelled marker code --> + <script src="labeled_marker.js"></script> + + <script type="text/javascript"> + + // define a few constants after loading the gmaps API + ICON_SIZE = new GSize(ICON_SIZE_W, ICON_SIZE_H); + CENTRE_COORDS = new GLatLng(CENTRE_COORDS_LAT, CENTRE_COORDS_LNG); + + function add_node(map, nodeid, lat, lng, name, desc, url, is_linked) { + var latlng = GLatLng.fromUrlValue('') + var latlng = new GLatLng(lat, lng); + + var icon = new GIcon(G_DEFAULT_ICON); + icon.shadow = ""; + if (is_linked) { + icon.image = LINKED_ICON; + } else { + icon.image = UNLINKED_ICON; + } + var middle = new GPoint(ICON_SIZE.width / 2.0, ICON_SIZE.height / 2.0); + icon.iconAnchor = middle; + icon.infoWindowAnchor = middle; + icon.iconSize = ICON_SIZE; + + var marker_opts = { + icon: icon, + labelText: '<div class="node_marker_label">' + name + "</div>", + labelOffset: new GSize(ICON_SIZE.width/2.0, 0), + }; + + var marker = new LabeledMarker(latlng, marker_opts); + + var desc_text = ''; + if (desc) { + desc_text = '<br/>' + desc; + } + + var name_text = nodeid; + if (name) { + name_text = name; + } + if (url) { + name_text = '<a href="' + url + '">' + name_text + '</a>'; + } + var myhtml = '<div class="node_label"><b>' + name_text + "</b>" + desc_text + '<br/><div class="node_label_id">' + nodeid + "</div></div>"; + GEvent.addListener(marker, "click", function() { + map.openInfoWindowHtml(latlng, myhtml); + }); + map.addOverlay(marker); + } + + function add_link(map, kind, lat1, lng1, lat2, lng2) { + var pos1 = new GLatLng(lat1, lng1); + var pos2 = new GLatLng(lat2, lng2); + var polyOptions = {geodesic:true}; + + // line styling defined here. + var colour = null; + if (kind == '2ghz') { + colour = LINK_COLOUR_2GHZ; + } else if (kind == '5ghz') { + colour = LINK_COLOUR_5GHZ; + } else if (kind == 'vpn') { + colour = LINK_COLOUR_VPN; + } + else { + throw ("Link kind '" + kind + "' is not known."); + } + + var line = new GPolyline([ + pos1, pos2, + ], colour, LINK_WIDTH, LINK_OPACITY, polyOptions); + map.addOverlay(line); + } + + function make_legend(map, legend_html) { + // from + // http://code.google.com/apis/maps/documentation/examples/control-custom.html + function LegendControl() { + } + + LegendControl.prototype = new GControl(); + + // Creates a one DIV for each of the buttons and places them in a container + // DIV which is returned as our control element. We add the control to + // to the map container and return the element for the map class to + // position properly. + LegendControl.prototype.initialize = function(map) { + var legendDiv = document.createElement("div"); + legendDiv.id = "legend"; + legendDiv.innerHTML = legend_html; + + var container = document.createElement("div"); + container.appendChild(legendDiv); + map.getContainer().appendChild(container); + return container; + } + + // By default, the control will appear in the top left corner of the + // map with 7 pixels of padding. + LegendControl.prototype.getDefaultPosition = function() { + return new GControlPosition(G_ANCHOR_TOP_LEFT, + new GSize(LEGEND_X_OFFSET, LEGEND_Y_OFFSET)); + } + + map.addControl(new LegendControl()); + } + + function limit_zoom(map, minMapScale, maxMapScale) { + // get array of map types + var mapTypes = map.getMapTypes(); + // overwrite the getMinimumResolution() and getMaximumResolution() methods + // for each map type + for (var i=0; i<mapTypes.length; i++) { + mapTypes[i].getMinimumResolution = function() {return minMapScale;} + mapTypes[i].getMaximumResolution = function() {return maxMapScale;} + } + } + + function initialize() { + if (GBrowserIsCompatible()) { + var map = new GMap2(document.getElementById("map_canvas")); + + // turn on the zoom and terrain/sat buttons + + var customUI = map.getDefaultUI(); + customUI.maptypes.hybrid = false; + customUI.controls.scalecontrol = false; + map.setUI(customUI); + + map.setMapType(G_PHYSICAL_MAP); + map.enableContinuousZoom(); + + limit_zoom(map, MIN_ZOOM, MAX_ZOOM); + + // centered kind of on perth city. + map.setCenter(CENTRE_COORDS, INIT_ZOOM); + + var legend_html = '<div><img src="' + LINKED_ICON + '"/></div><div>Linked Node</div>' + + '<br/><div><img src="' + UNLINKED_ICON + '"/></div><div>Unlinked Node</div>' + + '<br/><div style="background-color: ' + LINK_COLOUR_5GHZ + '; width: 3em; height: ' + LINK_WIDTH + 'px"></div><div>5GHz Link</div>' + + '<br/><div style="background-color: ' + LINK_COLOUR_2GHZ + '; width: 3em; height: ' + LINK_WIDTH + 'px"></div><div>2GHz Link</div>' + + '<br/><div style="background-color: ' + LINK_COLOUR_VPN + '; width: 3em; height: ' + LINK_WIDTH + 'px"></div><div>VPN Link</div>' + ; +; + make_legend(map, legend_html); + + var linked_nodes = {}; + for (var i = 0; i < freenet_links.length; i++) + { + try { + var l = freenet_links[i]; + var kind = l[0]; + var nodeid1 = l[1]; + var nodeid2 = l[2]; + + var node1 = freenet_nodes[nodeid1]; + var node2 = freenet_nodes[nodeid2]; + + if (node1 == undefined) { + throw "Node ID " + nodeid1 + " is not in the node list."; + } + if (node2 == undefined) { + throw "Node ID " + nodeid2 + " is not in the node list."; + } + + if (kind != 'vpn') { + linked_nodes[nodeid1] = true; + linked_nodes[nodeid2] = true; + } + + var lat1 = node1[0]; + var lng1 = node1[1]; + var lat2 = node2[0]; + var lng2 = node2[1]; + + add_link(map, kind, lat1, lng1, lat2, lng2); + } catch (e) { + var error_log = document.getElementById("error_log"); + error_log.innerHTML += "Error adding node link '" + + l + "': '" + String(e) + "'<br/>"; + error_log.style.display = "block"; + } + } + + for (var nodeid in freenet_nodes) { + var n = freenet_nodes[nodeid]; + var lat = n[0]; + var lng = n[1]; + var name = n[2]; + var desc = n[3]; + var url = n[4]; + var is_linked = linked_nodes[nodeid]; + add_node(map, nodeid, lat, lng, name, desc, url, is_linked); + } + } + } + + </script> + </head> + <body onload="initialize()" onunload="GUnload()"> + <div id="error_log"></div> + <div id="map_canvas"></div> + </body> +</html>