MediaWiki:GoogleMaps.js
//registers the Gmap_onload function as a window.onload event hookEvent('load', Gmap_onload);
//searches for all maps on the current page and calls their render function function Gmap_onload() { var maps = getElementsByClass('div', 'googleMap');
for (i = 1; i <= maps.length; i++) {
var gmap_id = 'gmap_'+i; var form_id = 'mapform_'+i;
var renderer = document.getElementById(form_id).renderer;
if (!renderer) { alert('The Google Maps extensions is broken. Could not find renderer.'); } else { if (!window[renderer.value]) { alert('The map renderer ' + renderer.value + ' is not a valid function'); } else { window[renderer.value](i); } } }
}
//renders map n on a page //data is read from a form with name and id "mapform_n" where n is an integer starting at 1 and incrementing by 1 //the creation of this form is handled by the gmap extension function Gmap_renderMapOld(n) {
gmap_id = 'gmap_'+n; form_id = 'mapform_'+n; message_id = 'gmapmessage_'+n;
document.getElementById(gmap_id).style.width = document.getElementById(form_id).width.value; document.getElementById(gmap_id).style.height = document.getElementById(form_id).height.value;
var map = new GMap2(document.getElementById(gmap_id)); map.addControl(new GSmallMapControl()); map.setCenter(new GLatLng(document.getElementById(form_id).lat.value, document.getElementById(form_id).lon.value, true), parseInt(document.getElementById(form_id).zoom.value), G_NORMAL_MAP);
if (document.getElementById(form_id).controls.value == 'yes') {
map.addControl(new GMapTypeControl());
}
if (document.getElementById(form_id).type.value == 'G_SATELLITE_MAP') {
map.setMapType(G_SATELLITE_MAP);
}
else if (document.getElementById(form_id).type.value == 'G_NORMAP_MAP') {
map.setMapType(G_NORMAL_MAP);
}
else if (document.getElementById(form_id).type.value == 'G_HYBRID_MAP') {
map.setMapType(G_HYBRID_MAP);
}
GEvent.addListener(map, "moveend", function() {
var center = map.getCenter();
var latLngStr = '(' + center.y + ', ' + center.x + ')';
document.getElementById(message_id).innerHTML = latLngStr;
});
if (document.getElementById(form_id).rss){
//if the rss form element is defined, plot datapoints from an rss feed
feedarray = document.getElementById(form_id).rss.value.split('|');
for (var i = 0; i < feedarray.length; i++) {
renderRSSFeed(map, feedarray[i]);
}
}
else {
var request = GXmlHttp.create();
//the php script returns a very simple XML document
request.open("GET", "/Special:GraphStructure/xml/locations", true);
request.onreadystatechange = function() {
if (request.readyState == 4) {
var doc = request.responseXML;
var nodes = doc.documentElement.getElementsByTagName('node');
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.hasAttribute('smw:Coordinates')) {
var nodeType = node.getAttribute('type');
var nodeTitle = node.getAttribute('title');
var nodePoint = node.getAttribute('smw:Coordinates');
var nodeURI = nodeTitle.replace(/ /g, '_');
if (nodeType == 'category') {
nodeURI = "Category:" + nodeURI;
}
var html = "Location: " + nodePoint + "
//we find entities "located in" this node by using xpath foundNodes = findNodesWithRelationTo(doc, node.getAttribute("id"), "Located in");
if (foundNodes.length > 0) {
html += "Located Here:</strong>
- ";
for (var j = 0; j < foundNodes.length; j++) {
var insertLink = foundNodes[j].getAttribute("title");
if (foundNodes[j].getAttribute("namespace") == 0) {
insertLink = "<a href=\"/" + foundNodes[j].getAttribute("title").replace(/ /g, '_') + "\">" + insertLink + "</a>";
}
html += "
- " + insertLink + " ";
}
html += "}
var point = parsePoint(nodePoint);
var marker = createMarker(point, html);
map.addOverlay(marker);
}
}
}
}
request.send(null); }
}
//finds all nodes having relation to a destination node //for example, dstNode=6 relation="Located In" function findNodesWithRelationTo(doc, dstNode, relation) { var nodes = doc.documentElement.getElementsByTagName("node"); var foundNodes = new Array();
var foundEdgesPattern = "/MediaWikiGraph/edge[@relation='"+relation+"'][@to='"+dstNode+"']";
var resultEdges = doc.evaluate(foundEdgesPattern, doc.documentElement, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
var thisEdge = resultEdges.iterateNext();
while (thisEdge) { //find the node in the document for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.getAttribute("id") == thisEdge.getAttribute("from")) { foundNodes.push(node); } }
thisEdge = resultEdges.iterateNext(); }
return foundNodes;
}
function arcDegrees(arcminutes, arcseconds) {
arcminutes = parseFloat(arcminutes); arcseconds = parseFloat(arcseconds); return (arcminutes / 60.0 + arcseconds / 3600.0);
}
function parsePoint(str) {
var values = str.split(/\s*,\s*/);
// 1 2 3 4
var expr = /(\d+)&.*?;(\d+)&.*?;(\d+.?\d*)&.*?;\s*(\w)/;
var lat = expr.exec(values[0]);
var lng = expr.exec(values[1]);
var latitude = parseFloat(lat[1]) + arcDegrees(lat[2], lat[3]);
var longitude = parseFloat(lng[1]) + arcDegrees(lng[2], lng[3]);
if (lat[4] == 'S') {
latitude *= -1;
}
if (lng[4] == 'W') {
longitude *= -1;
}
return new GLatLng(latitude, longitude, true);
}
function renderRSSFeed(map, rssurl) {
var request = GXmlHttp.create();
//the request.open method doesn't like URL's not on our server
//the proxy.php script is a very simplistic proxy with some security features
rssurl = "/misc/proxy.php?" + rssurl;
request.open("GET", rssurl, true);
request.onreadystatechange = function() {
if (request.readyState == 4) {
var xmlDoc = request.responseXML;
var items = xmlDoc.documentElement.getElementsByTagName("item");
for (var i = 0; i < items.length; i++) {
var marker = createMarkerFromRSSItem(items[i]);
map.addOverlay(marker);
}
}
}
request.send(null);
}
function createMarkerFromRSSItem(item) {
var title = item.getElementsByTagName("title")[0].childNodes[0].nodeValue;
var description = item.getElementsByTagName("description")[0].childNodes[0].nodeValue;
var link = item.getElementsByTagName("link")[0].childNodes[0].nodeValue;
var lat = item.getElementsByTagNameNS("http://www.w3.org/2003/01/geo/wgs84_pos#", "lat")[0].childNodes[0].nodeValue;
var lon = item.getElementsByTagNameNS("http://www.w3.org/2003/01/geo/wgs84_pos#", "long")[0].childNodes[0].nodeValue;
var point = new GPoint(parseFloat(lon), parseFloat(lat)); var marker = new GMarker(point); var html = '<a href="' + link + '">' + title + '</a><p />' + description;
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
function createMarker(point, html) {
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
//a helper function that returns an array of element ids of a given type and class function getElementsByClass(elem, classname) {
classes = new Array();
alltags = document.getElementsByTagName(elem);
for (i=0; i<alltags.length; i++) {
if (alltags[i].className == classname) {
classes.push(alltags[i].id);
}
}
return classes;
}
var brianScript = {
'arcDegrees': function(arcminutes, arcseconds) {
arcminutes = parseFloat(arcminutes); arcseconds = parseFloat(arcseconds); return (arcminutes / 60.0 + arcseconds / 3600.0);
},
'parsePoint': function(str) {
var values = str.split(/, /);
var expr = /(\d+)(?:\D|(?:°))(\d+)(?:\D|(?:′))(\d+\.?\d*)(?:\D|(?:″)) ([NSEW])/;
var lat = values[0].match(expr);
var lng = values[1].match(expr);
var latitude = parseFloat(lat[1]) + brianScript.arcDegrees(lat[2], lat[3]);
var longitude = parseFloat(lng[1]) + brianScript.arcDegrees(lng[2], lng[3]);
if (lat[4] == 'S') {
latitude *= -1;
}
if (lng[4] == 'W') {
longitude *= -1;
}
return new GLatLng(latitude, longitude, true);
},
'handleHttpResponse': function() {
var request = brianScript._request;
var map = brianScript._map;
if (request.readyState == 4) {
var doc = request.responseXML;
var smwNS = "http://opensource.case.edu/projects/MediaWikiHacks/"
var nodes = doc.documentElement.getElementsByTagName('node');
var nodeMap = {};
// Build a node map once so we don't have to iterate
// it scanning for node IDs every time.
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
nodeMap[node.getAttribute('id')] = node;
}
// Build a relation map for every node.
var relationMap = brianScript.buildRelationMap(doc, nodeMap, 'Located in');
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.hasAttributeNS(smwNS, 'Coordinates')) {
var nodeID = node.getAttribute('id');
var nodeType = node.getAttribute('type');
var nodeTitle = node.getAttribute('title');
var nodePoint = node.getAttributeNS(smwNS, 'Coordinates');
var nodeURI = brianScript.makeNodeURI(node);
var html = 'html += '<a href="' + nodeURI + '">' + nodeTitle + '</a>html += '
'; html += 'Location: ' + nodePoint + '
'; var related = relationMap[nodeID]; related = related ? related : new Array(); if (related.length) { html += 'Located here:
';
- ';
for (var j = 0; j < related.length; j++) {
var relNode = related[j];
var relTitle = relNode.getAttribute('title');
var relURI = brianScript.makeNodeURI(relNode);
html += '
- <a href="' + relURI + '">' + relTitle + '</a> ';
}html += '';
}html += '
var point = brianScript.parsePoint(nodePoint);
var marker = createMarker(point, html);
map.addOverlay(marker);
}
}
}
},
'makeNodeURI': function(node) {
var uri = node.getAttribute('title').replace(/ /g, '_');
if (node.getAttribute('type') == "category") {
uri = "Category:" + uri;
}
return '/' + uri;
},
'buildRelationMap': function(doc, nodeMap, relation) {
var relations = {};
if (doc.evaluate) {
var foundEdgesPattern = "/MediaWikiGraph/edge[@relation='" + relation + "']";
var resultEdges = doc.evaluate(foundEdgesPattern, doc.documentElement, null,
XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
var thisEdge = resultEdges.iterateNext();
while (thisEdge) {
var fromID = thisEdge.getAttribute('from');
var toID = thisEdge.getAttribute('to');
var node = nodeMap[fromID];
if (relations[toID]) {
relations[toID].push(node);
}
else {
relations[toID] = [node];
}
thisEdge = resultEdges.iterateNext();
}
}
else {
var edges = doc.documentElement.getElementsByTagName('edge');
for (var i = 0; i < edges.length; i++) {
var edge = edges[i];
var edgeRel = edge.getAttribute('relation');
if (edgeRel == relation) {
var fromID = edge.getAttribute('from');
var toID = edge.getAttribute('to');
var node = nodeMap[fromID];
if (relations[toID]) {
relations[toID].push(node);
}
else {
relations[toID] = [node];
}
}
}
}
return relations;
},
'renderMap': function(n) {
gmap_id = 'gmap_'+n; form_id = 'mapform_'+n; message_id = 'gmapmessage_'+n;
document.getElementById(gmap_id).style.width = document.getElementById(form_id).width.value; document.getElementById(gmap_id).style.height = document.getElementById(form_id).height.value;
var map = new GMap2(document.getElementById(gmap_id)); map.addControl(new GSmallMapControl()); map.setCenter(new GLatLng(document.getElementById(form_id).lat.value, document.getElementById(form_id).lon.value, true), parseInt(document.getElementById(form_id).zoom.value), G_NORMAL_MAP);
if (document.getElementById(form_id).controls.value == 'yes') {
map.addControl(new GMapTypeControl());
}
if (document.getElementById(form_id).type.value == 'G_SATELLITE_MAP') {
map.setMapType(G_SATELLITE_MAP);
}
else if (document.getElementById(form_id).type.value == 'G_NORMAP_MAP') {
map.setMapType(G_NORMAL_MAP);
}
else if (document.getElementById(form_id).type.value == 'G_HYBRID_MAP') {
map.setMapType(G_HYBRID_MAP);
}
GEvent.addListener(map, "moveend", function() {
var center = map.getCenter();
var latLngStr = '(' + center.y + ', ' + center.x + ')';
document.getElementById(message_id).innerHTML = latLngStr;
});
if (document.getElementById(form_id).rss) {
//if the rss form element is defined, plot datapoints from an rss feed
feedarray = document.getElementById(form_id).rss.value.split('|');
for (var i = 0; i < feedarray.length; i++) {
renderRSSFeed(map, feedarray[i]);
}
}
else {
var request = GXmlHttp.create();
//the php script returns a very simple XML document
request.open("GET", "/Special:GraphStructure/xml/locations", true);
brianScript._map = map;
brianScript._request = request;
request.onreadystatechange = brianScript.handleHttpResponse;
request.send(null);
}
}
}
var Gmap_renderMap = brianScript.renderMap;
