Code Tags: PHP;Mysql
I needed to plot visitors to a web site onto a world map to demonstrate world wide coverage. I had an initial google around and couldn't really find anything. It didn't take too long to realise what i needed to make this work with my own script. I also chose to make it pretty so have gone for a lights at night look.
Plotting on a World Map (Website Visitors)
Problem* Put locations of visitors (for which i already had in a mysql database) on to a world map.
Pre-Requisites* The data (this example will assume from mysql)
* A World Map (I have gone for "AVHRR Pathfinder" shot from
here) the bigger the better)
* PHP with gd2 (I run this from the command line as it might take a while to render)
Understanding the MathsFirstly to make this work you need a linear
cylindrical (latitude/longitude) projection world map, the ones from the source outlined above are. This means that the latitude/longitude are directly proportional to the x/y of the image. So if you have the dimensions the image as $img_x, $img_y you can then plot a long/lat with this:
php code:
$pos_x = (int)(($img_x/2) + (($row['long']/180)*($img_x/2)));
$pos_y = (int)(($img_y/2) - (($row['lat']/90)*($img_y/2)));
For Longitude ($row['long']): the range is from -180°:180° so the above code work out the equivalent x position on the image. The same applies for Latitude($row['long']) with the range -90°:90°
With this sorted the rest of the code is simple.
The Codephp code:
//Setup Image
$imagein = "PathfinderMap.jpg";
$imageout = "output.jpg";
//Get Image Dimentions
list($img_x,$img_y) = getimagesize($imagein);
//Load in image
$im = imagecreatefromjpeg($imagein);
//Make Image "Night time"
$darkblue = imagecolorallocatealpha($im, 0x00, 0x00, 0x00, 25);
imagefilledrectangle($im, 0, 0, $img_x,$img_y, $darkblue);
//Mysql Bit
$mysqli = new mysqli("**","**","**","**");
if ($mysqli->connect_error) {
printf("Connect failed: %sn", mysqli_connect_error());
exit();
}
$sql = "** Protected for Security **";
if ($result = $mysqli->query($sql)) {
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
// work out long/lat on image
$pos_x = (int)(($img_x/2) + (($row['long']/180)*($img_x/2)));
$pos_y = (int)(($img_y/2) - (($row['lat']/90)*($img_y/2)));
//if two positions share the same pixel then combine the result
if(!isset($data["{$pos_x}_{$pos_y}"])){
$data["{$pos_x}_{$pos_y}"] = $row['Rows'];
}else{
$data["{$pos_x}_{$pos_y}"] += $row['Rows'];
}
}
//free result set
$result->close();
}
// close connection
$mysqli->close();
//Size of data array
$count = count($data);
echo "\n"; //debug
foreach($data as $key=>$value){
//Decides for each value
// $yellow is the light color
// $size is the diameter of the light
if($value>10000){
$yellow = imagecolorallocatealpha($im, 0xFF, 0xFF, 0x00,0);
$size = 15;
}elseif($value>1000){
$yellow = imagecolorallocatealpha($im, 0xFF, 0xFF, 0x00,0);
$size = 10;
}elseif($value>100){
$yellow = imagecolorallocatealpha($im, 0xFF, 0xFF, 0x00,0);
$size = 7;
}else{
$yellow = imagecolorallocatealpha($im, 0xFF, 0xFF, 0x00,0);
$size = 5;
}
// Draw light
list($pos_x,$pos_y) = split("_",$key);
imagefilledellipse($im, $pos_x, $pos_y, $size,$size, $yellow);
$i++; //Debug
echo "\r$i/$count (".number_format(($i/$count)*100,1)."%)";
}
echo "\rSaving Image this could take a bit\n";
//save Image
imagejpeg($im,$imageout);
So there we go, I welcome any comments.