9

I have a question. Is there a possibility to bind a double click Mouse Event to a node?
In the documentation, there is only 'click'.

Thanks for your help!

Lostizzet
  • 171
  • 1
  • 3

6 Answers6

12

You can add a custom doubleTap event for Cytoscape like this:

var cy = $('#cy').cytoscape('get');
var tappedBefore;
var tappedTimeout;
cy.on('tap', function(event) {
  var tappedNow = event.cyTarget;
  if (tappedTimeout && tappedBefore) {
    clearTimeout(tappedTimeout);
  }
  if(tappedBefore === tappedNow) {
    tappedNow.trigger('doubleTap');
    tappedBefore = null;
  } else {
    tappedTimeout = setTimeout(function(){ tappedBefore = null; }, 300);
    tappedBefore = tappedNow;
  }
});

Then, you can subscribe for the new event. For example, if you need to detect double tab on nodes, do:

cy.on('doubleTap', 'node', function(event) { /* ... */ });

Nevertheless, I understant @maxkfranz point of view that this is not mobile-friendly solution.

fracz
  • 20,536
  • 18
  • 103
  • 149
  • 1
    this worked for me after I did changed tappedNow.trigger('doubleTap'); to this.trigger('doubleTap'); – Eric Santos Mar 20 '15 at 20:41
  • 1
    Yes, it's pretty easy to add your own custom events/gestures on top of the library. I still think doubletap/doubleclick isn't very good UI in most cases, so I don't think it should be included in the library by default. Maybe you would consider packing your code in an extension so it's reusable. Extension scaffolding is automatic: http://js.cytoscape.org/#extensions/autoscaffolding – maxkfranz Jan 22 '16 at 16:26
  • I find this solution not work well on IE11, and the solution @scebotari66 posted work well for me also on IE11. – Does Aug 23 '19 at 10:53
  • I do not get a event.cyTarget . In my event I just get event.cy . is that the same as target? – Oliver Watkins Feb 24 '20 at 16:46
  • 1
    ok I found out I have event.target, and it works, instead of event.cyTarget – Oliver Watkins Feb 24 '20 at 16:54
3

One of the core requirements of cy.js is that it should work equally well and as-consistently-as-possible across devices. Double click is a carry over from PC days: It often results in poor UI, and it is completely foreign to touch-based devices. Therefore, we do not support it currently. -M

maxkfranz
  • 11,896
  • 1
  • 27
  • 36
  • 1
    i think about 99% of people using cy would be using it on a PC anyway. – Oliver Watkins Feb 25 '20 at 10:52
  • 1
    It depends on the app, and it depends on the use case. Even on desktop computers, users rarely try to double click --- especially on the web. There's nothing stopping you from using double clicks in your apps on top of built-in 'click' events. The library, however, discourages you from doing so by not having a direct 'doubleclick' event. – maxkfranz Mar 11 '20 at 14:31
2

There is also a way to achieve this without setTimeout. The event has a timeStamp property with the values of UNIX time stamp when the event got triggered. So, here is the approach:

var doubleClickDelayMs = 350;
var previousTapStamp;

cy.on('tap', function(e) {
    var currentTapStamp = e.timeStamp;
    var msFromLastTap = currentTapStamp - previousTapStamp;

    if (msFromLastTap < doubleClickDelayMs) {
        e.target.trigger('doubleTap', e);
    }
    previousTapStamp = currentTapStamp;
});


cy.on('doubleTap', function(event, originalTapEvent) {
    ...
});

Here is a working fiddle: https://jsfiddle.net/scebotari66/84x7hxd0/4/

scebotari66
  • 3,395
  • 2
  • 27
  • 34
0

thanks @fracz for the solution. In my case I needed the tap position. If metadata from the original tap event are needed, don't forget passing and replacing the event, as the doubletap event doesn't contain all metadata.

var tappedBefore;
var tappedTimeout;

cy.on('tap', function(event) {
  var tappedNow = event.target;
  if (tappedTimeout && tappedBefore) {
    clearTimeout(tappedTimeout);
  }
  if(tappedBefore === tappedNow) {
    tappedNow.trigger('doubleTap', event);
    tappedBefore = null;
    originalTapEvent = null;
  } else {
    tappedTimeout = setTimeout(function(){ tappedBefore = null; }, 300);
    tappedBefore = tappedNow;
  }
});

and to use it:

cy.on('doubleTap', function (event, originalTapEvent) {
    event = originalTapEvent;
...

Besides, did someone do experiments with a combination of tapstart (index finger, use this event location) + tap(middle finger, location irrelevant only as selection confirmation) as an alternative? Would that work?

til
  • 832
  • 11
  • 27
0

This is not a strict double tap but works like it. It relies on node.selected()

When user taps/click once on a node it gets a state selected. When user clicks again and the node is selected from before it works as a double click.

There is no need to track another state and use timeouts with this solution.

cy.on('tap', 'node', function(evt){
  let node = evt.target;
  console.log('tapped ' + node.id());
  if (node.selected()) {
    console.log('selected ' + node.id());
  }
});

console log will then be

tapped <nodeId>
tapped <nodeId>
selected <nodeId>
hrvoj3e
  • 2,512
  • 1
  • 23
  • 22
0

See fixpoint/cytoscape-dblclick (MIT License) for a 3rd-party solution that is ready to use.

Bora M. Alper
  • 3,538
  • 1
  • 24
  • 35