• Tidak ada hasil yang ditemukan

Server-Side Boundary Method

The boundary method involves requesting only the points within a specific boundary, defined using some relevant reference such as the viewport of the visible map. The success of the boundary method relies on highly dispersed data at a given zoom level.

If you have a large data set and the information is relatively dispersed over the globe, you can use the GLatLngBoundsof the GMap2object as a boundary for your query. This essentially restricts the data in your response to those points that are within the on-screen viewable area of the map. For globally dispersed data at zoom level 1, where the map covers the entire globe, you’ll see the whole world at once, so plotting the data set using markers is still is going to go beyond the suggested 100 marker limit and cause problems, as shown in Figure 7-1. At closer zoom levels, say 5 or higher, you’ll have a smaller portion of the markers on the map at one time, and this method will work great, as shown in Figure 7-2. The same would apply for localized data dispersed across a smaller area or large, less dispersed data, but you’ll need to zoom in much closer to have success.

Figure 7-1. Server-side boundary method with the entire world at zoom level 1

Figure 7-2. Server-side boundary method at a closer zoom level

To experiment with a smaller, globally dispersed data set, suppose you want to create a map of capital cities around the world. There are 192 countries, so that would mean 192 markers to display. Capital cities are an appropriate data set for the boundary method because there are relatively few points and they are dispersed throughout the globe. If you adjust the zoom of the map to something around 5, you’ll have only a small portion of those points on the map at the same time.

Tip

The boundary method is usually used in combination with one of the other solutions. You’ll notice that in many of the server-based methods, the first SQL query still uses the boundary method to initially limit the data set to a particular area, and then additional optimizations are performed.

Listings 7-1 and 7-2 contain a working example of the server-side boundary method (http://googlemapsbook.com/chapter7/ServerBounds/) using the SQL database of capital city locations you created in Chapter 5 (in the screen scraping example). If you haven’t created the database from Chapter 5, you can quickly do so using the Chapter 7 capital_cities_seed.sqlfile in the supplemental code for the book.

Listing 7-1. Client-Side JavaScript for the Server-Side Boundary Method var map;

var centerLatitude = 49.224773;

var centerLongitude = -122.991943;

var startZoom = 4;

C H A P T E R 7■ O P T I M I Z I N G A N D S C A L I N G F O R L A R G E D ATA S E T S 150

function init() {

map = new GMap2(document.getElementById("map"));

map.addControl(new GSmallMapControl());

map.setCenter(new GLatLng(centerLatitude, centerLongitude), startZoom);

updateMarkers();

GEvent.addListener(map,'zoomend',function() { updateMarkers();

});

GEvent.addListener(map,'moveend',function() { updateMarkers();

});

}

function updateMarkers() { //remove the existing points map.clearOverlays();

//create the boundary for the data var bounds = map.getBounds();

var southWest = bounds.getSouthWest();

var northEast = bounds.getNorthEast();

var getVars = 'ne=' + northEast.toUrlValue() + '&sw=' + southWest.toUrlValue()

//log the URL for testing

GLog.writeUrl('server.php?'+getVars);

//retrieve the points using Ajax var request = GXmlHttp.create();

request.open('GET', 'server.php?'+getVars, true);

request.onreadystatechange = function() { if (request.readyState == 4) {

var jscript = request.responseText;

var points;

eval(jscript);

//create each point from the list for (i in points) {

var point = new GLatLng(points[i].lat,points[i].lng);

var marker = createMarker(point,points[i].city);

map.addOverlay(marker);

} } }

request.send(null);

}

function createMarker(point, html) { var marker = new GMarker(point);

GEvent.addListener(marker, 'click', function() { var markerHTML = html;

marker.openInfoWindowHtml(markerHTML);

});

return marker;

}

window.onload = init;

Listing 7-2. PHP Server-Side Script for the Server-Side Boundary Method

<?php

//retrieve the variables from the GET vars list($nelat,$nelng) = explode(',',$_GET['ne']);

list($swlat,$swlng) = explode(',',$_GET['sw']);

//clean the data

$nelng=(float)$nelng;

$swlng=(float)$swlng;

$nelat=(float)$nelat;

$swlat=(float)$swlat;

//connect to the database

require($_SERVER['DOCUMENT_ROOT'] . '/db_credentials.php');

$conn = mysql_connect("localhost", $db_name, $db_pass);

mysql_select_db("googlemapsbook", $conn);

if($nelng > $swlng) {

//retrieve all points in the southwest/northeast boundary

$result = mysql_query(

"SELECT

lat,lng,capital,country FROM

capital_cities WHERE

(lng > $swlng AND lng < $nelng) AND (lat <= $nelat AND lat >= $swlat) ORDER BY

lat"

, $conn);

C H A P T E R 7■ O P T I M I Z I N G A N D S C A L I N G F O R L A R G E D ATA S E T S 152

} else {

//retrieve all points in the southwest/northeast boundary //split over the meridian

$result = mysql_query(

"SELECT

lat,lng,capital,country FROM

capital_cities WHERE

(lng >= $swlng OR lng <= $nelng) AND (lat <= $nelat AND lat >= $swlat) ORDER BY

lat"

, $conn);

}

$list = array();

$i=0;

$row = mysql_fetch_assoc($result);

while($row) {

$i++;

extract($row);

$city = addcslashes($capital.', '.$country,"'");

$list[] = "p{$i}:{lat:{$lat},lng:{$lng},city:'{$city}'}";

$row = mysql_fetch_assoc($result);

}

//echo back the JavaScript object nicely formatted header('content-type:text/plain;');

echo "var points = {\n\t".join(",\n\t",$list)."\n}";

?>

This method has two key parts. The first is the request to the server in Listing 7-1, which includes the bounds of the map by sending the southwest and northeast corners:

//create the boundary for the data var bounds = map.getBounds();

var southWest = bounds.getSouthWest();

var northEast = bounds.getNorthEast();

var getVars = 'ne=' + northEast.toUrlValue() + '&sw=' + southWest.toUrlValue()

The second is the SQL query to the database in Listing 7-2, which limits the points to the boundary defined by the southwest and northeast corners:

if($nelng > $swlng) {

//retrieve all points in the southwest/northeast boundary

$result = mysql_query(

"SELECT

lat,lng,capital,country FROM

capital_cities WHERE

(lng > $swlng AND lng < $nelng) AND (lat <= $nelat AND lat >= $swlat) ORDER BY

lat"

, $conn);

} else {

//retrieve all points in the southwest/northeast boundary //split over the meridian

$result = mysql_query(

"SELECT

lat,lng,capital,country FROM

capital_cities WHERE

(lng >= $swlng OR lng <= $nelng) AND (lat <= $nelat AND lat >= $swlat) ORDER BY

lat"

, $conn);

}

Caution

You may have noticed the SQL is wrapped in an ifstatement and two different queries are per- formed depending on the relationship of the longitudes. This is due to the meridian in the Mercator projection of the map. The map is displayed using a Mercator projection where the meridian of the earth is at the left and right edges. When you slide to the left or right, the map will wrap as you move past the meridian at +/– 180 degrees. In that case, the bounds are partially split across the left and right edges of the map and the northeast corner is actually positioned at a point that is greater than 180 degrees. The Google Maps API (and probably your data) automatically adjusts the longitude values to fit between –180 and + 180 degrees, so you need to request two portions of the map from your database covering the left and right sides.

When you move the map around or change the zoom level, a new request is created by the moveendand zoomendevents in Listing 7-1. The request to the server retrieves a new JSON object, which is then processed by the JavaScript to create the necessary markers.

C H A P T E R 7■ O P T I M I Z I N G A N D S C A L I N G F O R L A R G E D ATA S E T S 154

As you would expect, there are both pros and cons to using the boundary method. The advantages are as follows:

• This technique uses the standard existing Google Maps API methods to create the markers on the map.

• It doesn’t drastically change your code from the simple examples presented earlier in the book.

• The PHP requires little server-side processing and little overhead.

The following are the boundary method’s disadvantages:

• It works for only dispersed data or higher zoom levels.

• It may not work for lower zoom levels, as too many markers will be shown at once.

• The client’s web browser makes a new request for markers after each map movement, which could increase server traffic.