On my current project, we need to select project locations (points) on a map, create a list of the unique “Projects” which can then be used for reporting. We are using the ArcGIS Server Google Map Extension as that’s the best fit for this project. Overall, this sounds simple enough.
Here’s the wrinkle – there are 1800+ project location points in the dataset. And, these 1800 points actually represent only 33 projects. Ah, 1 to Many’s… this will be “fun”…
500 is the Magic Number
By default, the REST API (which delegates to the SOAP API behind the scenes) only returns the first 500 features when doing a query. This setting can be changed on the server, but it’s there for a reason – you want to limit the number of features that are sent back to the browser. This limits the amount of data on the wire, and keeps your application responsive. In addition, drawing more than a few hundred features on any javascript canvas will make most browsers come to a crawl. Flex and Silverlight have less issues with this, and for applications where you are dealing with large sets of data.
Ok – but how are we going to handle this? We need to select features inside polygon, but we are only going to get 500 features back.
We did some poking at the data, and found that the distribution of project locations to projects is heavily skewed… this graph shows the number of project locations per project.
As we can see, there is one project with nearly 1700 project locations. Most of the rest of the projects have 4 or less locations.
So – even getting just 500 features back, we’ll likely cover off the project in question. Of course this is not 100% guaranteed – in the long run we may revisit this, and if the client want’s to invest time/money in some back-end ArcObjects development and we can solve the issue that way.
Doing the Query
In any event, in the callback from the GPolygon enableDrawing() method, takes the geometry, and does a query against the project locations layer. Since we don’t want to actually try to draw 500 points, we do not have the geometry returned – just the ProjectID of the features. Remember that returning the smallest set of information is always a good idea.
We then loop over the features, collecting a list of unique the ProjectId’s. At the same time, I’m creating a WHERE clause that can be used in a definition query.
var itemList = new Array();
var defQuery = "PROJECTID IN (";
for(i=0;i<fset.features.length;i++){
var feature = new esri.arcgis.gmaps.Feature();
feature = fset.features[i];
if($.inArray(feature.attributes.PROJECTID, itemList) == -1){
itemList.push(feature.attributes.PROJECTID);
defQuery += ''' + feature.attributes.PROJECTID + '',';
}
}
Layer Definitions
Instead of showing the selected project locations as push-pins, I’m using a definition query against a separate “Project Location Selection” layer in the map. Once I have all the PROJECTID’s, I update the layer definition for this selection layer…
defQuery = defQuery.substring(0,defQuery.length -1); defQuery += ")"; layerDefs[0] = defQuery; dynamicMap.setLayerDefinitions(layerDefs);
From here, I now use some jQuery to loop over the array of ProjectID’s, make Ajax calls to a controller to get the details of the project to populate the results list area. Since that get’s long, I’m going to skip those details – suffice to say I create a mess of <li> tags and float them so I get a pretty list.
Now, there is some possibly un-expected behavior with this – since the definition query is based on the “one” side of the “one to many”, the selection we end up showing is “all the project locations related to the projects in the polygon”.
This makes more sense when you see it…
This is the map right before we finish the polygon. The Project Locations are the gray dots. The Results area is currently empty, and the reporting tools are disabled.
After the polygon is finished, we get the unique list of project ID’s, set the “selection layer” definition (resulting in the green dots), and fetch the project details from the controller and fill up the results area.
As you can see, there are a lot of selected (green) dots outside the selection polygon – this is mainly because of that one project that has ~1700 locations – if we get just one of those back from the spatial query, we’ll be “selecting” all these points.
Regardless of the 1 to Many issues on this project, using a definition query against a dynamic map layer can be a good way to show the selection of a large set of features, or of features with very complex geometries.