For that many features, you should probably load your shapefile data into a database like MySQL or PostGREsql with the PostGIS extension. I'm going to recommend PostGREsql with PostGIS, because you can query your data as GeoJSON geometry expressions, which Google Maps can render right out of the box, or which you can optionally consume using an open 3rd-party JavaScript library.
Next, you'll want to wire-up the map object so that it loads only data that would appear within the map boundaries---this should keep your map relatively fast. To facilitate this, use the map object's "idle" event (fired when the map is finished rendering after a pan or a zoom) to fetch relevant data against the map object's bounds/extent coordinates. Basically, your event handler will make an ajax request to your service layer (PHP, Ruby, C#, etc.) to perform a spatial query like ST_Intersects
, which will return only the features that within the map area. If your query returns GeoJSON geometry expressions from the ST_AsGeoJSON
function, you should be able to push them right into the Google Map with minimal effort.
SETUP: Example OGR2OGR call that converts (-f
) a shapefile into PostGREsql/PostGIS, and translates it (-t_srs
) to EPSG 4326 (WGS 1984, a.k.a. Longitude/Latitude coordinates). Note that there may be more to this if your data is in an unusual projection.
ogr2ogr -f "PostgreSQL" "PG:host=127.0.0.1 user=dbUSERNAME dbname=dbNAME
password=dbPASSWORD" "C:/path_to/your_data.shp" -nlt GEOMETRY -lco PRECISION=no
-t_srs EPSG:4326
JavaScript: Example map's "idle" event listener that catches the idle event and creates a Well Known Text Polygon to use in an ST_Intersects spatial query.
google.maps.event.addListener(map, 'idle', function(event)
{
var bounds = map.getBounds();
var sw = bounds.getSouthWest();
var ne = bounds.getNorthEast();
// Redefine the sw..ne coordinates as a Well Known Text Polygon expression.
var wkt = encodeURIComponent("POLYGON((" + sw.lng() + " " + sw.lat() + ", " +
sw.lng() + " " + ne.lat() + ", " +
ne.lng() + " " + ne.lat() + ", " +
ne.lng() + " " + sw.lat() + ", " +
sw.lng() + " " + sw.lat() + "))");
// CALL SOME SERVER-SIDE METHOD HERE, SUBMITTING
// THE wkt PARAMETER FOR USE IN A SPATIAL QUERY.
//
// getGeoJsonData.php?bounds=wkt
});
PHP with PostGREsql/PostGIS: Example PHP script with spatial query to select any records that fall within your map object's bounds/extent:
<?php
// Required input
$ewkt = 'SRID=4326;' . urldecode($_GET["bounds"]);
// Future output
$json = '';
// Parameterized Query Spanning Multiple Lines
$query .= <<<EOD
SELECT
ST_AsGeoJSON(wkb_geometry) as geom,
field_1,
field_2,
field_n
FROM
your_data
WHERE
ST_Intersects(wkb_geometry, ST_GeomFromEWKT( $1 ));
EOD;
$conn = pg_pconnect('host=127.0.0.1 port=5432 dbname=dbNAME user=dbUSERNAME password=dbPASSWORD');
// Pass-in your bounds EWKT parameter..
$result = pg_query_params($conn, $query, array($ewkt));
if($result)
{
while($row = pg_fetch_assoc($result))
{
$json .= '{"Feature": {';
$json .= '"geom": "' . $row['geom'] . '",';
$json .= '"field_1": "' . $row['field_1'] . '",';
$json .= '"field_2": "' . $row['field_2'] . '",';
$json .= '"field_n": "' . $row['field_n1'] . '",';
$json .= "}}";
}
}
echo $json;
?>
JavaScript: Example method to render GeoJSON using the 3rd-party library, mentioned above:
<script type="text/javascript" src="GeoJSON.js"></script>
<script type="text/javascript">
var featureOverlay = []; // Create an array to hold all of your features.
// Pass your individual GeoJSON objects into a method like this.
function renderGeoJSON(geoJSON)
{
var pOptions = {
strokeColor: '#00FFFF',
strokeOpacity: 1,
strokeWidth: 2,
fillColor: '#00FFFF',
fillOpacity: 0
};
var featureGeoJSON = new GeoJSON(geoJSON, pOptions);
if (featureGeoJSON.error)
{
alert('Errors detected in GeoJSON geometry expression.');
}
else
{
for(var i=0; i<featureGeoJSON.length; i++)
{
// Attach the feature to the map..
featureGeoJSON[i].setMap(map);
// Save a reference to the feature in your array..
featureOverlay.push(featureGeoJSON[i]);
}
}
}
</script>
I put this together pretty quickly, but hopefully it conveys the overall idea with a few examples/snippets demonstrating specific steps. And hopefully I didn't litter the examples with too many mistakes. FWIW, there are gotchas and caveats at each step, and likely better ways of doing at least a few of the things. So let me stress not to take this as gospel!