Question

I am scoping out an application which will be web/mobile based. The application is designed to provide end users with geospatial information. The source of the geospatial data is ESRI Shapefiles. I have a little experience with google maps so I thought about converting these into KML and then parsing that kml file into a database. Some of the core functionality will be as follows

+Display 2000 markers with different icons
++have styled info window on this marker
+++ability to add/remove polygons from map related to this marker
+Display ~4000 polygons

Filters
+add/remove markers/polygons based on attribute filters

The biggest hurdle I think I will need to overcome is to have this map be both interactive while keeping performance. One piece of functionality is the ability to dynamically add/remove specific polygons. In the past I had rendered large number of polygons via KML files. However since I need to add/remove 1 or 2 polygons from that file at a time I am not sure how I would accomplish that.

Does anyone have any recommendation about how to handle a large number of markers and polygons, with the ability to remove/add polygons one by one?

Was it helpful?

Solution

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!

OTHER TIPS

Have you looked at Map Engine? Designed for heavy geo data

https://support.google.com/mapsengine/answer/3342103?hl=en

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top