Efficient way to return complex features.

911
8
08-24-2011 12:37 PM
TonyMonsour
New Contributor
Here is my scenario. 

I have an app where a user clicks on the map and an Identify Task is ran.  The Identify Task needs to be precise and get the exact feature the user clicks on.  However, while I want to return the geometry of that feature and draw it on the map I do not actually want to return that feature because the geometries are so complex.  An example is - feature A takes 8 seconds to be returned and drawn.  I have tried working with the Max Allowable Offset, however the best it can do is about 4 seconds for Feature A.  I have generalized the layers and put them in a Map Service and I am currently running an Identify Task (no geometries returned) on the complex layer and then getting the attribute info, using that in a Query function against the generalize layer and returning that geometry.  This works the best so far, typically 2 seconds. 

My question is is there a more efficient way to do this, I.E not having to make 2 rest calls?  Can I use related tables somehow?

Thanks,
Tony
0 Kudos
8 Replies
StephenLead
Regular Contributor III
Hi Tony,

is there a more efficient way to do this, I.E not having to make 2 rest calls?


The approach you're using (of having a separate, generalized layer which you use as the highlight feature) seems like a sensible workaround to the problem of displaying a complex layer.

To save the double-handling, you could simply run the Query directly on the generalized layer.

That is, your map will contain a Dynamic layer pointing to the complex dataset (this is what the user will see). Set up a QueryTask which points to the generalized layer, and set a listener for the map's onClick event which runs a Query directly on the generalized layer (set Query.geometry to be the XY location clicked).

The user never needs to know that the layer being queried is different to the layer being displayed.

See this sample to get an idea of how it would work.

Steve
0 Kudos
derekswingley1
Frequent Contributor
Can you elaborate on how you're using maxAllowableOffset? If you're following the guidelines from our recent blog post, I'd be surprised if any one feature is more than 10-20k.

If you're specifying a maxAllowableOffset that returns a geometry with no more than a single vertex per pixel, and you're still seeing ~4 seconds for an identify to return, I would look at the resources available on the server when you see slow response times. I would also look into the underlying data store and see if you see similar problems querying the data with other clients (try ArcMap, for instance).

I don't think a relationship class and a subsequent query for related records would be the best solution to your problem.

Is your REST endpoint public? Can you post a link? Or better yet, a link to your app? I'm also curious about your data; can you elaborate on what kind of things you're mapping? Or just about "feature A" that takes 8s to send across the wire?
0 Kudos
StephenLead
Regular Contributor III
You should also ensure that the query/identify only returns the attributes which are required. If you're only using it to highlight, you may not need any attribute at all.
0 Kudos
TonyMonsour
New Contributor
Thank you guys for your quick replies. 
Stephen,
I have taken those suggestions into consideration.  The issue is really with the geometries of the features.  The dataset is a global dataset.  The dataset is derived from raster data which has the world mapped out in a 1km X 1km grid.  I have pulled from it the Countries and Admin 1 boundaries.  As you can probably imagine something as simple as a coastline can be generalized as a couple vertexes but in the original dataset at a resolution of 1km it is thousands.  The reason i need to query on the original dataset is the user needs to be hitting the exact feature, any generalization will lead to misinformation.

Derek,
I have created a sample app and a Rest service and made it public for you to check out.  As you can see i have included both the original files and a simplified layer which i was going to use to get the geometries from.  This app will potentially be hit by many users when it is completed and thus i figured having a pre-simplified (as opposed to maxAllowableOffset) would be the best choice.  All of the code (minus the modules) is in the single .htm page.  It is pretty simple as i am just working on getting the data to come back correctly before i move into design/ detailing (i know she ain't the prettiest).
Functionality -
-click on somewhere in the US or Canada runs an Identify on the original data- brings back data and graphic (original features)
-use the input at the top to search for a country or admin unit within US or Canada (brings back simplified layer)
-click on country column in Top 25 Countries Chart to get data and graphic of that country (brings back simplified layer)

Links- http://wms.cartographic.com/test/esrisample.htm
http://wms.cartographic.com/GWS/rest/services/Open/LS_EsriSample/MapServer

Feel free to email me if need be.
Thanks Tony,
tony.monsour@cartographic.com
0 Kudos
StephenLead
Regular Contributor III
Your app definitely looks promising. I'll leave it to Derek to comment on the maxAllowableOffset approach.

The reason i need to query on the original dataset is the user needs to be hitting the exact feature, any generalization will lead to misinformation.


Since you're highlighting the feature, if someone clicks on the boundary of two features (and selects the "wrong" feature) this will be apparent to them, and they can easily click in a new location (to select the "correct" feature). It wouldn't be misinformation since you're making it quite clear which features you're referring to in the chart.

Eg, they click within Nebraska when they meant to click within Kansas - this is no big deal since your app highlights Nebraska, and clearly labels it in the chart.

So I wouldn't say it was a problem to run the query directly on the generalized feature, if you do decide to go down that route.

My two cents's worth, anyway.

Cheers,
Steve
0 Kudos
derekswingley1
Frequent Contributor
  Derek,
I have created a sample app and a Rest service and made it public for you to check out.  As you can see i have included both the original files and a simplified layer which i was going to use to get the geometries from.  This app will potentially be hit by many users when it is completed and thus i figured having a pre-simplified (as opposed to maxAllowableOffset) would be the best choice.  All of the code (minus the modules) is in the single .htm page.  It is pretty simple as i am just working on getting the data to come back correctly before i move into design/ detailing (i know she ain't the prettiest).
Functionality -
-click on somewhere in the US or Canada runs an Identify on the original data- brings back data and graphic (original features)
-use the input at the top to search for a country or admin unit within US or Canada (brings back simplified layer)
-click on country column in Top 25 Countries Chart to get data and graphic of that country (brings back simplified layer)

Links- http://wms.cartographic.com/test/esrisample.htm
http://wms.cartographic.com/GWS/rest/services/Open/LS_EsriSample/MapServer


Hi Tony,

Thanks for providing those links, very helpful. Apologies for the slow reply; I was out of commission for a couple of days last week.

I took a look and I think you could see significant benefits from using maxAllowableOffset. I encourage you to re-visit the blog post I linked to earlier in this thread.

The point of maxAllowableOffset is not to arbitrarily generalize features, but to generalize to an optimal level. Since our screens/monitors have a finite number of pixels, depending on the map scale, multiple feature vertices might fall in a single pixel. It is a waste of effort and resources to transmit, process and display these vertices. By setting maxAllowableOffset appropriately, you are telling the server to return geometries optimized for the map's scale and the display being used. Eliminating vertices that would be displayed in the same pixel does not lead to misinformation but it does have the potential to significantly improve the performance of your app.

By eliminating vertices that cannot be displayed, features are returned to the client faster and displayed faster. There's a famous quote that sums this up quite nicely:  "everything should be made as simple as possible, but no simpler".

The implementation of this is straightforward:
-when your app starts, calculate the width of a pixel in map units
-set maxAllowableOffset for your identify parameters to the width of a pixel
-re-calculate maxAllowableOffset when your map scale changes
-update your identify parameters accordinglyj

Side note:  this applies not only to identify parameters but also to query tasks and feature layers as they both can use maxAllowableOffset.

You can see maxAllowableOffset in action here:  http://servicesbeta.esri.com/demos/high-perf-feature-layers/

Here's a code snippet showing an event listener for onZoomEnd that calculates the width of a pixel in map units and updates an identifyParameters object accordingly:
dojo.connect(map, 'onZoomEnd', function() {
  // Calculate width of a pixel in map units
  var maxOffset = map.extent.getWidth() / map.width
  // Specify maxAllowableOffset as the width of a pixel
  // so that no more than one vertex per pixel is returned
  identifyParams.maxAllowableOffset(maxOffset);
});


Please experiment with something like this as it's a pretty quick change to make to any app and can make a world of difference.
0 Kudos
derekswingley1
Frequent Contributor
One more thing to add:  I did a quick test with the REST endpoint you posted.

Edit:  The two URLs below correspond to clicking somewhere in South Carolina when the map is at zoom level 5. The maxOffset used in the first URL was calculated by loading the app, opening the chrome dev tools console and entering the following:
map.extent.getWidth() / map.width


Using maxAllowableOffsethttp://wms.cartographic.com/GWS/rest/services/Open/LS_EsriSample/MapServer/identify?geometryType=esr...{%22x%22%3A-8839789.239531778%2C%22y%22%3A3982063.780911503%2C%22spatialReference%22%3A{%22wkid%22%3A3857}}&sr=3857&layers=all%3A0%2C2&time=&layerTimeOptions=&layerdefs=&tolerance=0&mapExtent={%22xmin%22%3A-11559724.454030767%2C%22ymin%22%3A2406849.5020110095%2C%22xmax%22%3A-5757848.259074291%2C%22ymax%22%3A6525888.082241492%2C%22spatialReference%22%3A{%22wkid%22%3A3857}}&imageDisplay=1186%2C842%2C96&returnGeometry=true&maxAllowableOffset=4891.96981024998&f=json
Response size:  ~196K
Response time: 2.9s


Not using maxAllowableOffsethttp://wms.cartographic.com/GWS/rest/services/Open/LS_EsriSample/MapServer/identify?geometryType=esr...{%22x%22%3A-8839789.239531778%2C%22y%22%3A3982063.780911503%2C%22spatialReference%22%3A{%22wkid%22%3A3857}}&sr=3857&layers=all%3A0%2C2&time=&layerTimeOptions=&layerdefs=&tolerance=0&mapExtent={%22xmin%22%3A-11559724.454030767%2C%22ymin%22%3A2406849.5020110095%2C%22xmax%22%3A-5757848.259074291%2C%22ymax%22%3A6525888.082241492%2C%22spatialReference%22%3A{%22wkid%22%3A3857}}&imageDisplay=1186%2C842%2C96&returnGeometry=true&maxAllowableOffset=&f=json
Response size:  ~758K
Response time: 9.0s
0 Kudos
TonyMonsour
New Contributor
Thanks a lot for your help.  I used the code you sent and it worked well.  The issue is the data is so dense, being derived from 1km resolution raster data, that small countries work no problem as graphics but a complex shape like Canada still takes 9s plus browser drawing time even with MaxAllowableOffset.  Because I need to stay true to the data and its precise boundaries the solution I am using is this:
I am using the Identify Task to return only the attributes I need I.E. Country and Admin1, then I am plugging those values into the LayerDefinitions for those layers in a Dynamic Map Service.  The whole thing only takes 2s max on the most complex feature (1.7s on the ID and .3s on the map export) and about .5s on the simpler features (.3s and .3s).

Graphics look a little sharper on the screen but as of right now my app doesn't need to utilize its functionality.

-Tony
0 Kudos