Can I turn off layer events, and still hook mouse events and pass some to map?

986
11
11-04-2011 05:46 AM
RexBradford
New Contributor II
I have developed some Javascript code to solve the problem of selecting markers where there are multiple markers overlapping.  By default, the UI seems to act as if obscured markers just don't exist.  My replacement system tracks all my layer markers, spatially organizes them for fast lookup, and then has a UI for tooltips and clicking which presents all the markers under the mouse cursor tip, rather than just the topmost.

It works fine, except that to get the mouse event in the first place to my system, I have had to tie into the layer's event handlers.  I.e., each layer gets its mouse events, and then just hands them off to the new system, which handles all layers together.  I would much rather turn off the marker layers' event handlers altogether, as I don't need them anymore, and just handle all mouse events directly, but still pass those that aren't over a marker on to the underlying map event handlers (for pan, zoom, etc.).  This would be faster (the toolkit has an unnecessary delay when clicking on markers in crowded areas), and I wouldn't have to worry about my marker detection having any pixel-level inaccuracies vis-a-vis the layer's detection, which is currently the "mouse gatekeeper".

Is there a way to capture all the mouse events in the map area, and then grab those I want, and pass the rest on?

Thanks,

Rex Bradford
Direct Relief International
0 Kudos
11 Replies
derekswingley1
Frequent Contributor
By default, the UI seems to act as if obscured markers just don't exist.

Can you elaborate? Maybe post some code that reproduces this? It's pretty straightforward to get all graphics under a mouse click:  http://blogs.esri.com/dev/blogs/arcgisserver/archive/2010/02/08/find-graphics-under-a-mouse-click-wi...


It works fine, except that to get the mouse event in the first place to my system, I have had to tie into the layer's event handlers.  I.e., each layer gets its mouse events, and then just hands them off to the new system, which handles all layers together.  I would much rather turn off the marker layers' event handlers altogether, as I don't need them anymore, and just handle all mouse events directly, but still pass those that aren't over a marker on to the underlying map event handlers (for pan, zoom, etc.).  This would be faster (the toolkit has an unnecessary delay when clicking on markers in crowded areas), and I wouldn't have to worry about my marker detection having any pixel-level inaccuracies vis-a-vis the layer's detection, which is currently the "mouse gatekeeper".

I think we need to back up for a second and confirm you're solving a problem that needs to be solved (and not just re-writing the API). Can you talk more about "the toolkit has an unnecessary delay when clicking on markers in crowded areas" and how you solved that? Again, repro code would be the simplest way to show this problem exists. I would like to hear more specifics about those "pixel-level inaccuracies"  as well.

How many graphics are in your map?

Apologies if I'm not answering your question directly. You're outlining some significant issues and rather than talking about how to circumvent the existing API, I'd like to isolate any existing issue(s) so we can potentially fix them.
0 Kudos
RexBradford
New Contributor II
Thanks for the quick reply.  I had no idea that the mechanism you sent a link about existed - I've been working off a toolkit that just used layer onclick handlers which pass an evt for the top marker at that layer.  Most of the sample code I've seen seems to do the same thing.

The delay I meant was that, in an crowded area (in one map of ours, there may be a few dozen markers under the mouse if you're zoomed out), it can take a couple of seconds between the time of the click and the time the onclick handler is called.  I have been assuming that this is a round-trip to the map server for a query of some kind, though haven't verified that and it seems odd since the tooltips are instantaneous and need to do the same thing.

In the mechanism you sent me a link to, does this spatial query involve a server round trip or not?

Thanks again - I will study what you sent.

Rex Bradford
Direct Relief International
0 Kudos
derekswingley1
Frequent Contributor
Hi Rex,

Glad to help.

When you mention "toolkit" ...what specifically are you talking about? Is this something you or someone else assembled? How does it differ from the core API?

The link I posted uses a GraphicsLayer which does not require a server round trip as all feature information is stored on the client. Graphics layers (and Feature layers) are a great when you need interactivity but can lead to performance issues if you try and use them with more than a couple thousand features.

I'm guessing your using a dynamic map service layer. If that's the case, then yes, it does require a server round trip to get actual feature geometry and feature attributes. The mechanism to do this is an identify or query task.
0 Kudos
RexBradford
New Contributor II
Hi Rex,

When you mention "toolkit" ...what specifically are you talking about? Is this something you or someone else assembled? How does it differ from the core API?


By "toolkit", I just mean that we started off using a sample Javascript map application that uses what seems to be a commonly used base; here's one of many maps that uses it:
http://www.esri.com/news/maps/2011/horn-of-africa-drought-crisis-map/index.html

We have modified the code quite substantially since then, but until now had retained the use of layer onclick handlers to pop up infowindows.

I'm guessing your using a dynamic map service layer. If that's the case, then yes, it does require a server round trip to get actual feature geometry and feature attributes. The mechanism to do this is an identify or query task.


For the markers, I am just using a GraphicsLayer, connecting it to a map service,
and doing layer.add(graphic) calls based on filtered sets of them.

It does seem that there is a problem with the simple onclick handling for this graphic layer.  If I click in an area where there are maybe 10-15 markers under the cursor tip (and more nearby), it can take 2-3 seconds before the onclick handler gets called.  In less crowded areas it's instantaneous.  This surprised me because I presumed the (instantaneous) tooltips had to do the same work.

Thanks again for looking at this.

Rex Bradford
Direct Relief International
0 Kudos
derekswingley1
Frequent Contributor
For the markers, I am just using a GraphicsLayer, connecting it to a map service,
and doing layer.add(graphic) calls based on filtered sets of them.

How are you connecting a graphics layer to a map service?


It does seem that there is a problem with the simple onclick handling for this graphic layer.  If I click in an area where there are maybe 10-15 markers under the cursor tip (and more nearby), it can take 2-3 seconds before the onclick handler gets called.  In less crowded areas it's instantaneous.  This surprised me because I presumed the (instantaneous) tooltips had to do the same work.

Something does seem off about that...can you post your event handling code for your graphics layer?
0 Kudos
RexBradford
New Contributor II
How are you connecting a graphics layer to a map service?


The relevant code is:

    // Initialize the query task
    layerFistula.queryTask = new esri.tasks.QueryTask(userConfig.fistulaLayerURL);
   
    // Set up the initial query and execute it
    layerFistula.query = new esri.tasks.Query();
    layerFistula.query.returnGeometry = true;
    layerFistula.query.outFields = ["*"];
    layerFistula.executeQueryTask(false);

.....executeQuery() then builds up the "where" part of the query and ends up doing:

        layerFistula.query.where = where;
        layerFistula.queryTask.execute(layerFistula.query, layerFistula.showResults);

..... and then showResults(), which gets called when the query is finished, does this kind of stuff to create the markers (this is a subset of the code but gives you the idea....)

    layer.clear();
    map.infoWindow.hide();
    var il=resultFeatures.length;
    for (i = 0; i < il; i++) {
        var graphic = resultFeatures;
        var symbol = layerFistula.getSymbolForFacility(graphic.attributes);
        graphic.setSymbol(symbol);
        layer.add(graphic);
    }



Something does seem off about that...can you post your event handling code for your graphics layer?


All I am saying is that this simple code, run after the query has been completed, has a delay problem:

    dojo.connect(layer, "onClick", function(evt) {
        console.log("click!");
        layerUI.handleClick(evt);       
    });

.....it prints out the "click" on the console after a delay, and the delay is bigger the more markers there are nearby.  Note that the print is the first thing inside the onclick event handler.

Rex Bradford
Direct Relief International
0 Kudos
derekswingley1
Frequent Contributor
All of that looks like pretty standard, straight forward stuff. I'm not sure where the delay is being introduced. Any chance your app in on a public server?
0 Kudos
RexBradford
New Contributor II
All of that looks like pretty standard, straight forward stuff. I'm not sure where the delay is being introduced. Any chance your app in on a public server?


Unfortunately not currently, though not far off.  Perhaps using layer.add(graphic) is less efficient, lookup-wise, than whatever FeatureLayers do under the hood?  In this case, I am adding over 300 markers with this call, and the bad-performance case is when I'm hovering over about 20 of them at the same time.   Though again, tooltips are fine, just delay getting to onclick handler.

Rex
0 Kudos
derekswingley1
Frequent Contributor
Just brain storming here but are you adding your onClick handler to each graphic or is it on the actual graphicsLayer?
0 Kudos