Attention! Do you have any ideas for reorganizing and updating the Mapki? Please leave a note here. Thank you!

EvilC's Hierarchical Bunching Method-Code

From Google Mapki

Jump to: navigation, search

<<Database

[edit] The Read Script

Given that you have a database set up in the previous format, with the tree rebuilt etc, then this script will generate the XML for any given zoom level.

Create a script, call it read.php paste in the following and edit the database connection values if needs be:

<?php
$host = 'localhost';
$user = 'root';
$pass = ;
$dbname = 'test';

// Read vars from URL
// zoom - used to tell this script what zoom level we are viewing from
if (isset($HTTP_GET_VARS['zoom']) ){
	$zoom = $HTTP_GET_VARS['zoom'];
} else {
	$zoom=1;
}
// requestid - used so that every reply has a unique id
// this enables the front end to discard old, irrelivant replies
if (isset($HTTP_GET_VARS['requestid']) ){
	$requestid = $HTTP_GET_VARS['requestid'];
} else {
	$requestid=0;
}
// Set noxml in the URL and the script displays the SQL used instead
if (isset($HTTP_GET_VARS['noxml']) ){
	$noxml = $HTTP_GET_VARS['noxml'];
}
// Set the region variable in the URL to "filter" results.
// only children of that region will be returned.
if (isset($HTTP_GET_VARS['region']) ){
	$region = $HTTP_GET_VARS['region'];
} else {
	$region = 1;
}

// connect to the db...
if (!$db = mysql_connect($host, $user, $pass)) {
	echo 'Could not connect to mysql';
	exit;
}
if (!mysql_select_db($dbname, $db)) {
	echo 'Could not select database';
	exit;
}

// Set the headers...
// Date in the past
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); 
// always modified
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// HTTP/1.1
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
// HTTP/1.0
header("Pragma: no-cache");

if (!isset($noxml)){
	//XML Header
	header("content-type:text/xml");
}

$query="SELECT DISTINCT \n";
$query .= "\n-- Select the locations table...\n";
$query .= "loc.location_id, loc.name, loc.region_id, loc.represents_region, loc.lat, loc.lng, \n";
$query .= "\n-- Pull the relevant data from the parent region as rp_* \n";
$query .= "rp.zoom AS rp_zoom, \n";
$query .= "\n-- If the location represents a region, pull relevant data for that region as rr_* \n";
$query .= "rr.zoom AS rr_zoom, \n";
$query .= "\n-- If the location represents a region, pull relevant data for the child region as rc_* \n";
$query .= "rc.zoom as rc_zoom \n";
$query .= "\n-- Specify the Tables... \n";
$query .= "FROM locations loc \n";
$query .= "-- Join the location to the region it (may) represent as rr... \n";
$query .= "LEFT OUTER JOIN regions rr \n";
$query .= "ON loc.represents_region=rr.region_id \n";
$query .= "-- Join the location to the region it belongs in as rp... \n";
$query .= "LEFT OUTER JOIN regions rp \n";
$query .= "ON loc.region_id=rp.region_id \n";
$query .= "-- Join the location to the child with the lowest zoom it (may) represent as rc... \n";
$query .= "LEFT OUTER JOIN regions rc \n";
$query .= "ON rc.zoom IN ( \n";
$query .= "	SELECT MIN(zoom) FROM regions WHERE \n";
$query .= "	parent_id = loc.represents_region \n";
$query .= ") \n";
$query .= "\n-- OK, names and everything specified, let's pick some locations !\n";
$query .= "WHERE ";
$query .= "\n";
$query .= "\n-- Pull in all points from regions that:\n";
$query .= "-- 1) Are a child of the root (filter) region\n";
$query .= "-- 2) Have a zoom <= to the current zoom\n";
$query .= "loc.region_id IN ( \n";
$query .= "	SELECT node.region_id \n";
$query .= "	FROM regions root \n";
$query .= "	INNER JOIN regions node \n";
$query .= "		ON root.lft <= node.lft \n";
$query .= "		AND root.rgt >= node.rgt \n";
$query .= "	WHERE root.region_id = '".$region."' \n";
$query .= "	AND node.zoom <= $zoom \n";
$query .= ") \n";
$query .= "\n-- Knock out the markers that represent the visible regions \n";
$query .= "AND ";
$query .= "represents_region NOT IN (\n";
$query .= "	SELECT node.region_id \n";
$query .= "	FROM regions root \n";
$query .= "	INNER JOIN regions node \n";
$query .= "		ON root.lft <= node.lft \n";
$query .= "		AND root.rgt >= node.rgt \n";
$query .= "	WHERE root.region_id = '".$region."' \n";
$query .= "	AND node.zoom <= $zoom \n";
$query .= ") \n";

// sort list
$query .= "\n-- Sort\n";
$query .= "ORDER BY loc.name \n";
$query .= "\n-- END OF QUERY\n";

if(isset($noxml)){		// set noxml to get a text output of the query used - useful for debugging
	echo "<pre><br>$query</pre>";
}

$query = mysql_query($query);

// Generate the XML
if (!isset($noxml)){
	echo "<locations>";
	while ($row=mysql_fetch_assoc($query)){
		echo '<location id="'.$row['location_id'].'" name="'.$row['name'].'" lat="'.$row['lat'].'" lng="'.$row['lng'].'"/>';
	}
	echo '<request id="'.$requestid.'"/>';
	echo "</locations>";
}
?>

The read script accepts a number of varialbles in the url, eg:

read.php?zoom=5

This would return the "view" from zoom 5 as an XML document.

read.php?zoom=5&noxml

This would return the SQL used to generate the view from zoom 5.

read.php?zoom=5&region=3

This would return the "view" from zoom 5, but only things that are a child of region 3.

The noxml setting is useful to understand how the SQL works - it is heavily commented.

Also, the child regions and parent regions are linked in to the results - not because they are needed in this example, but because it will be useful later.

If you set up things so that the zoom value of a region was closer to space (zoom 0) than that of it's parent, it would never show. So the query finds out what the min zoom of any of a region's children is, and along with the zoom value of the region's parent, you know the "safe range" in which you may alter the zoom of any given region.

[edit] The Front End Script

Paste this into an html file, make sure it and read.php are in the same directory. Also change the API key value to one that matches the URL you are using

<!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>Google Maps API Example - overlay</title>
		<style type="text/css">
		v\:* {
			behavior:url(#default#VML);
		}
		</style>
		<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAbr2Sxqdz2s597elhfo6ReBRKCps_Qnx92dsVOgzU-wqrVbaSwRQZJD0wTteSofwUqt00c9G0VVfRSg" type="text/javascript"></script>
		<script type="text/javascript">
		//<![CDATA[
		
	    function onLoad() {
			map = new GMap(document.getElementById("div_map"));
			map.addControl(new GSmallMapControl());
			map.addControl(new GMapTypeControl());
			map.setCenter(new GLatLng(54, -3), 4);
			
			requestid=0;	// holds current AJAX request ID
			markers = [];
			getMarkers();
			GEvent.addListener(map, "zoom", function mapMoved() {
				getMarkers();
			});
	      
			GEvent.addListener(map, "click", function(overlay, point) {
				if (overlay){	// marker clicked
				  overlay.openInfoWindowHtml(overlay.infowindow);	// open InfoWindow
				} else if (point) {	// background clicked
				  
				}
			});
	    }
    	
		function getMarkers(){
			// remove old overlays - map.removeOverlays() seems to have a bug as of writing.
			// using it seems to break infowindows.
			for (var i=0;i < markers.length;i++){
				map.removeOverlay(markers[i]);
			}
			requestid++;
		    var urlstr="read.php?zoom="+map.getZoom()+"&requestid="+requestid;	// call the database read script with the zoom value
		    var request = GXmlHttp.create();
		    request.open('GET', urlstr , true);	// request XML from PHP with AJAX call
		    request.onreadystatechange = function () {
				if (request.readyState == 4) {
					var xmlDoc = request.responseXML;
					//requestid
					var uniqueid = xmlDoc.documentElement.getElementsByTagName("request");
					uniqueid=uniqueid[0].getAttribute("id");	// find the uniqueid of the request
					if (uniqueid == requestid){	// only process if not an old one
						locations = xmlDoc.documentElement.getElementsByTagName("location");
						markers = [];
						if (locations.length){
							for (var i = 0; i < locations.length; i++) { // cycle thru locations
								markers[i] = new GMarker(new GLatLng(locations[i].getAttribute("lat"),locations[i].getAttribute("lng")));
								// Add attributes to the marker so we can poll them later.
								// When clicked, an overlay will have these properties.
								markers[i].infowindow = "This is "+locations[i].getAttribute("name");
								
								// Useful things to store on a marker (Not needed for this example, could be removed)
								// Tells you what index in the markers[] array an overlay is
								markers[i].markerindex = i;
								// Store the location_id of the location the marker represents.
								// Very useful to know the true id of a marker, you could then make
								// AJAX calls to the database to update the information if you had it's location_id
								markers[i].db_id = locations[i].getAttribute("location_id");
								
								map.addOverlay(markers[i]);
								
							}
						}
					}
				}
			}
			request.send(null);
	    }
		//]]>
		</script>
	</head>
	<body onload="onLoad()">
		<div id="div_map" style="width: 500px; height: 300px"></div>
	</body>
</html>

[edit] The Insert Query

More coming soon ?

For now, use phpmyadmin or the like to edit the locations and regions.

If it is to be a bunch point, make a region as well and put the region's region_id in the represents_region field of loction that represents it.

<<Database

Personal tools
Advertisement