Mouse Hover Event

Hi,
I have loaded some geojson files and obtained entities associated with those datasouces. I am trying to implement a mouse hover effect so that when I move my mouse over, say, a state of the U.S. I can manipulate the particular entity. I have browsed the documentations, samples, and posts. And I was not able to find a suitable event handler for this inquery.

So there is not mouse hover event on Cesium.js, and we may have to implement such using MOUSE_MOVE?

Hiya,

Hmm, it’s a bit to and fro, but essentially hook into the Cesium render cycle;

viewer.scene.preRender.addEventListener((info) => { ... }

Also hook into the mouse position (like you thought);

let currentMousePosition = null;
let myMouseHandler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
myMouseHandler.setInputAction((movement) => {
          currentMousePosition = movement.endPosition;
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

Then in the renderer event you need to pick for where the mouse is pointing;

let anything = null;
if ( currentMousePosition ) {
   anything = viewer.scene.pick(currentMousePosition);
   if ( anything ) {
      // react
   }
}

The picker gives you an array of things; it could be entities (vector objects), or 3DTilesets (models, point-clouds), but not ImageLayers. Loop through the items, do some type checking on what you find, and do things accordingly.

Caching of picked things (including loop delays, change detection, etc.) and hover states is a different matter, and can get quite hairy, but for simple stuff just rely on the real-time loop as above. It also gets increasingly complicated with picking things if you have transparent items and / or terrain / globe, and picking on point-clouds consistently is a lot of fun! (There are different pickers and sample methods based on transparency of globe, terrain and objects, and a few settings like depthTestPicking, but I suspect the forums have more references to these when you get there).

Hope any of that was useful.

Cheers,

Alex

1 Like

Thanks so much for this. I have tried this method on entities but the whole scene becomes very laggy. Is this because of the large amount of data the scene has to handle at a time?

It depends on how complex your various data is in the scene. I personally don’t check the mouse in complete real-time, but a measure somewhere between 3 to 1 times per second (depending on FPS). You might even be able to get away with 1 per second, it depends on what you’re trying to do. You also don’t have to pick in the scene unless the mouse moves, I usually define some distance that feels right (say, 4 pixels away from last pick position).

There’s also different ways of iterating through your found objects (for example, inject a property into your entities, ie. ‘__my_entity’ or even typed versions of it), as well as inject in objects you want to ignore (check the docs). You can do more complex things, too, like don’t pick while displaying a hover unless the mouse move more than X/Y distance from current mouse position like explained earlier.

Next up is whether you pick on transparent or not surfaces, if you have a terrain model anywhere, and the precission needed for the pick (scene.pick() is simple, but you could sample the terrain or model with Promises as well).

It all comes back to; what are you trying to achieve specifically, and then try to optimize for that.

Cheers,

Alex

1 Like

I’m going to piggyback on this discussion and see if I can fetch a bit more from you @Alexander_Johannesen. I’m trying to accomplish a similar feat within my Cesium based application - hovering on a entity and displaying a dialog window that encapsulates data regarding the picked entity. However, implementing this seems to indeed cause a great deal of latency. I have incorporated some animations into my application and thus when you move the mouse, those animations becoming frozen/choppy until mouse movement subsides.

You mentioned loop delays - is there some sort of debounce or delay built in to the ScreenSpaceEventHandler that we can leverage? If so, would you care to elaborate on how this could be achieved?

1 Like

Hi there,

Well, no, Cesium is a fairly raw API for dealing with the 3D scene, so anything else is in your own domain.

For this particular use case, it makes a difference where you hook your real-time loop. There are mainly two loops of interest here; the render cycle, and the mouse movements.

In the render cycle basically keep track of mouse X and Y positions, plus the state of the hover window. First, if the mouse doesn’t move more than [some_value] pixel since the last picked position, I do nothing. A typical example is that if the mouse moves more than 3 pixels away fromt he old position, I can do a pick at the new position. If the hover is already showing, I don’t do a pick, but simply have a timer that counts down until I want the hover to close, but only if a) the mouse has moved more than [some_value], and b) if mouse has moved and I pick, the pick is different to the current pick. You can also add in things like "only check the mouse positions every time in the render cycle, depending on how many FPS you’re getting.

As to animations, that’s a different kettle of fish, and will depend on your frameworks and animation techniques (pure CSS? Animations in HTML/CSS, or within Cesium? And what kind of animations are they?). The render cycle normally shouldn’t interfere here, but it might be worth looking into if Cesium uses the GPU for most things.

Let me know a few more details like that, and I’ll try to help the best I can.

Cheers,

Alex

1 Like

Hey Alex,

I forgot to respond back with a solution I came up with! Sorry about that - thanks for the information and being quick to reply! I have animations attached to some of my billboards that have a pulsating effect. I did this using Cesium’s CallbackProperty and because of that, when I actively check if the mouse is hovering over one of those billboards; without any delay attached to that check, the animations freeze until I stop moving the mouse.

To get around this, I wrapped a debounce function call around the movement object like so:

billboardEventHandler.setInputAction(debounce(movement => {

   let pickedObject = this.$root.viewer.scene.pick(movement.endPosition);

   if (pickedObject && pickedObject.id == "UniqueIdentifier") {
      // HANDLE DESIRED TASK(S) HERE
   }           
}, 250), ScreenSpaceEventType.MOUSE_MOVE);

No more freezing :slight_smile:

2 Likes