Looking for effective way to detect mouse over graphics

2699
8
10-16-2015 07:07 AM
HuyHo
by
Occasional Contributor

In our application, we would like to change the mouse cursor whenever the user hover the mouse over a graphic.  We've came up with a way to do it using the GraphicsLayer.HitTestAsync() method whenever the mouse move.  But I am not sure if this is the best way to do it because as I move my mouse over the map, my CPU spikes to 10-15%.  I think this is too costly in terms of performance for such a simple feature.

    private async void MapView_MouseMove(object sender, MouseEventArgs e)
    {
        Graphic graphic = await HitTestAsync(_mapView, e.GetPosition(_mapView));
        UpdateHoveringGraphic(graphic);
    }

The UpdateHoveringGraphic() function will then determine if the graphic has changed to generate a MouseEnter and MouseLeave event.

We have several GraphicsLayer, so this adds up.  Does anyone have any suggestions to accomplish this feature in a less resource intensive way?

Thanks.

0 Kudos
8 Replies
JoshuaTharp
New Contributor II

Did you ever find a solution to this problem?

0 Kudos
HuyHo
by
Occasional Contributor

No -- we haven't. Sorry.

0 Kudos
BjørnarSundsbø1
Occasional Contributor II

Still no success?

0 Kudos
BjørnarSundsbø1
Occasional Contributor II

I'm attempting the same with poor performance. We have multiple layers to hit test, and attempt the following code. Trying to tweak the query for hitLayers doesn't get any real difference in the result, and alone takes about 60ms. The hit testing of 22 layers in this case takes nearly 400ms. I do the hit testing on click, to select graphics, and I have long ago abandoned doing it on mouse move due to poor performance. Any help would be welcome.

var hitLayers = mapView.Map.Layers.EnumerateLeaves()
.Where(m => m.IsVisible)
.OfType<GraphicsLayer>()
.Where(m => m.Graphics != null && m.Graphics.Count > 0)
.OrderBy(m => m.Graphics.Count)
.ToList();
var list = new List<Graphic>();
foreach (var layer in hitLayers)
{
var items = await layer.HitTestAsync(mapView, screenPoint, maxHits).ContinueWith(t => t.Result);
list.AddRange(items);
if (list.Count > maxHits)
{
return list.Take(maxHits);
}
}
return list.Take(maxHits);

0 Kudos
AnttiKajanus1
Regular Contributor II

Have you tried to see if using the functions that will do identify to all operational layers in one go and compared how that does affect the performance? Do you have performance problems both in Debug and Release modes?

GeoView.IdentifyLayersAsync Method (Point, Double, Boolean, Int64, CancellationToken)

0 Kudos
BjørnarSundsbø1
Occasional Contributor II

So far we are still on the 10.2.7 release due to the limitations in v100, so IdentifyLayersAsync is not available. There seems to be some performance boost in release mode, but still not fast enough to consider mouse over, even if making sure the cursor has stopped. Since most of the code is executed in the Esri Runtime, why should release mode have such an impact? I know the optimizer is enabled, but the heavy work is still performed in optimized assemblies.

0 Kudos
TylerHarris2
New Contributor

I just created a zero's matrix of size screenWidth x screenHeight. If there's a button at that pixel I filled that matrix entry with the button's index location in an array of its fellow buttons. Checking the mouse screen xy against this matrix will let you tell if you're hovering and what button you're over... This is probably not the greatest idea but I never found any better solutions.

0 Kudos
YaronAvraham
New Contributor III

Hi, 

I've had same problem with the performance, so i've added a thread timer to the mouse move event.

 private readonly TimeSpan _timerTimeSpan = TimeSpan.FromMilliseconds(300);

 Timer  _tooltipTimer = new Timer(timerElapsed, null, Timeout.Infinite, Timeout.Infinite);

private void MapViewOnMouseMove(object sender, MouseEventArgs e)
{
_mouseEvent = e;
_tooltipTimer.Change(_timerTimeSpan, Timeout.InfiniteTimeSpan);
}

private void timerElapsed(object state)
{

........

}

saving the last mouse coordinates and trigger the timer again on every mouse move with 300ms.

0 Kudos