Skip to content
This repository has been archived by the owner on Jul 29, 2019. It is now read-only.

Improve the click/doubleClick event with options how these should be fired. #203

Open
dponch opened this issue Jul 9, 2014 · 33 comments
Open

Comments

@dponch
Copy link

dponch commented Jul 9, 2014

Hi,

I want to use the events click and doubleclick on a network graph, but I realized that the event doubleclick triggers the event click, so when I doubleclick 2 functions are called.
Is there a way to avoid this?

Thanks

@AlexDM0
Copy link
Contributor

AlexDM0 commented Jul 9, 2014

Hi Dponch,

You could create a timeout function in your onclick function with a timeout you decide. If you have not received a doubleclick by then, interpret it as a click.

var doubleClick = false;

function onclick() {
  setTimeout(function () {
    if (doubleClick == false) {
      doOnClick();
    }
    else {doubleClick = false;}
},400);
}

function doOnClick() {
  ...
  do stuff
}

function onDoubleClick() {
  doubleClick = true;
  ...
  do stuff
}

Regards,

Alex

@AlexDM0 AlexDM0 added the Graph label Jul 9, 2014
@dponch
Copy link
Author

dponch commented Jul 9, 2014

Hi,

That's a good idea, thanks for your help.
But it didn't work out. I'm seeing that when I doubleclick it makes:

  1. Call to click event. This can be avoid with your solution
  2. Call to doubleclick event
  3. Call to click event again. So finally, it does the click stuff.

I'm using Firefox30. Could it be a problem?

@AlexDM0
Copy link
Contributor

AlexDM0 commented Jul 9, 2014

Hi Dponch,

You're right! I forgot about the second click hehe :). This should work:

network.on('click', onClick);
network.on('doubleClick', onDoubleClick);

var doubleClickTime = 0;
var threshold = 200;

function onClick() {
    var t0 = new Date();
    if (t0 - doubleClickTime > threshold) {
        setTimeout(function () {
            if (t0 - doubleClickTime > threshold) {
                doOnClick();
            }
        },threshold);
    }
}

function doOnClick() {
    console.log("execute onClick function");
}

function onDoubleClick() {
    doubleClickTime = new Date();
    console.log("execute onDoubleClick function");
}

Let me know if this works!

@dponch
Copy link
Author

dponch commented Jul 10, 2014

It works perfectly! Many thanks!!!

@dponch dponch closed this as completed Jul 10, 2014
@AlexDM0
Copy link
Contributor

AlexDM0 commented Jul 10, 2014

You're welcome. We have not put this in vis because it would delay the click event. If a user doesnt use the double click that would be annoying :).

@dsl101
Copy link

dsl101 commented Sep 16, 2014

Alex,

Sorry to reopen an old ticket, but I came here looking for a solution to the multiple event issue. I completely understand why you wouldn't want the code above which delays the click() event, but would it be possible for vis to suppress the second spurious click() event? At the moment, if you double-click on the network, the user code gets:

click()
doubleClick()
click()

Is there a case for ever getting the second click() event? Just the first two would seem to be 'normal' behaviour in, e.g. vb.net, etc. At the moment, I've had to put a variation of your code in to prevent that happening:

network.on('click', onClick);
network.on('doubleClick', onDoubleClick);

var doubleClickTime = 0;
var threshold = 200;

function onClick() {
    var t0 = new Date();
    if (t0 - doubleClickTime > threshold) {
        doOnClick();
    }
}

function doOnClick() {
    console.log("execute onClick function");
}

function onDoubleClick() {
    doubleClickTime = new Date();
    console.log("execute onDoubleClick function");
}

This reduces a double-click on the network to these events:

click()
doubleClick()

which is actually exactly what I want. People who don't want the first click() event when the user double-clicks can the use very similar user-side code to wait and see if there's a double-click event following within their own timeout.

The only side-effect of this would be that a double-click can't be followed by a single-click within the threshold time - but again, that's pretty normal I think.

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 16, 2014

Hi Dave,

That's perfectly fine. This code was just a suggestion or idea. To answer your question, no I don't think it's up to us to determine if people want a click after a double click. Since the solution is very easy, I'd prefer to leave that up to the devs using vis.

Regards,

Alex

@josdejong
Copy link
Contributor

It makes sense to me to just have the click-doubleclick events, instead of click-doubleclick-click. The second click is "eaten" or replaced by a doubleclick when within the threshold.

I can't come up with a use case where you would want click-doubleclick-click. I think this behavior is unwanted in practice.

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 17, 2014

Double click can color a node and then click again somewhere else to deselect?

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 17, 2014

Nevermind, misread the issue.

@josdejong
Copy link
Contributor

I think there are three use cases:

  1. I just use click. Click should react immediately.
  2. I use both click and doubleclick, and it is fine to have both fired on the same user event. Click can then react immediately.
  3. I use both click and doubleclick, and these two involve actions which should not happen on the same user event, I want either click or doubleclick fired but not both. For example on singleclick I create something, on doubleclick I delete something. This means a single click needs to wait for the threshold before it knows it was not the first click of a doubleclick.

I think 1. and 2. are important. We could realize the third option as well, that requires the developer to set an option to specify this behavior.

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 17, 2014

The first item, only using click, makes it unacceptable for vis to eat a click for the doubleClick event. Since the events are always fired, regardless of listeners, what do you suggest? Options to pass to network on init?

If the default settings are anything other then it is now it could give unexpected behaviour. Also the doubleClick threshold (time to wait) could be customised. I'm not sure if I'd want to have people use the code as stated above or add more options.

What do you think?

@josdejong
Copy link
Contributor

The first item, only using click, makes it unacceptable for vis to eat a click for the doubleClick event.

Why? Seen from a user perspective, the user either does a single click (resulting in a click event) or a double click (which should result in one click and one doubleclick event). In case of a double click, the second click is fired as a doubleclick event instead of a second click event.

So I think we can keep current behavior, except for the second click event not being fired anymore when doubleclicking. Then we have situations 1. and 2. right?

Option 3 is an extra, that would require configuration via the options.

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 17, 2014

If you're only using clicks, and you are clicking twice fast I find it strange that you'd have to listen to the doubleClick event instead of just the click event because you might lose a click. Now vis gives you exactly what happens. There ARE two clicks and they were fast enough that it could be called a double click. I would argue this gives the most reliable result. We could add event options to streamline this if needed.

@josdejong
Copy link
Contributor

yeah, that's true. We could introduce an option for this with three different modes.

@dsl101
Copy link

dsl101 commented Sep 17, 2014

I'm torn between Alex's last comment (what you get is exactly what is happening), and the vast experience of developing on, e.g. Win32 where that isn't what you get. I'm not saying Win32 is right here, just that I was confused by the event stream being 'different'.

I think a 'doubleClickMode' option would be ideal - I'll leave it to someone else to argue what the default should be :). Then I can code on the user side exactly as I do in other apps, and get the same events I would normally expect. Here's my suggestion:

When the user just 'clicks', you should always get a click() event. When the user 'double-clicks', you should get 1 of 4 things:

  1. doubleClickMode: false - you just get the 2 click() events, very close together. Maybe this isn't strictly necessary - you just wouldn't subscribe to the doubleClick() event...
  2. doubleClickMode: {mode: 'only', threshold: 200} - you just get 1 doubleClick() event, with the side-effect that all click() events will be delayed by threshold milliseconds, to allow for the detection of a double-click
  3. doubleClickMode: {mode: 'normal', threshold: 200} - you get a click() event immediately, and then a doubleClick() event if the user clicks again within threshold milliseconds (2 events in total)
  4. doubleClickMode: {mode: 'all', threshold: 200} - you get a click() event immediately, and then a second click() event and a doubleClick() event if the user clicks again within threshold milliseconds (3 events in total)

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 17, 2014

Hi Dave,

I would argue that 1 and 4 are the same. That leaves:

eventOptions : {
  doubleClickThreshold : 200,  // default 200?
  doubleClick: true,  // true will hide the second click, false: will not fire a doubleClick event at all.
  ... maybe future event options?
}

Hows that? If the user chooses to use the double click he'll have to work with the initial click anyway. I'm opposed to delaying ALL clicks, seems nasty.

Regards

@dsl101
Copy link

dsl101 commented Sep 17, 2014

Agree 1 isn't necessary as 1 == 4 if you don't subscribe to the doubleclick event.

Not sure what doubleClick: false above would give - isn't that the same again as just not subscribing to the double-click event?

I'd strongly argue for including case 2. though, with a warning in the docs that it will delay clicks. If that's the behaviour you want, your user-side click handler will end up being delayed anyway, and this way it makes the user-side code much cleaner and easier to understand. IMO, we shouldn't be putting that level of click handling stuff in the application - it would be much nicer if the library did it for us. Understand this makes vis messier inside though. How about this version?

eventOptions : {
    doubleClickThreshold : 200,  // default 200? Read from OS (yuck)?
    hideSingleClicks: 2  // default 1 (convention) or 0 (backwards compatibility for vis)
        // Hide 0, 1 or 2 of the associated single clicks when a double click is detected
        // 0 - user sees 'click', 'doubleClick', 'click' - no delay to click events
        // 1 - user sees 'click', 'doubleClick' - no delay to click events
        // 2 - user sees 'doubleClick' - all click events delayed

    // ... maybe future event options?
}

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 17, 2014

I would argue that doubleClick: false in my example completely removes the double click functionality from the network. If true, we can delay all clicks and hide the second one. The user would essentially be "toggling" the double click functionality on or off.

@AlexDM0 AlexDM0 reopened this Sep 17, 2014
@dsl101
Copy link

dsl101 commented Sep 17, 2014

I'm still a little unclear what the difference is between turning doubleClick off, and simply not subscribing to the doubleClick event. But anyway, would doubleClick: false then send click() or click(), click() to the user? And if you set doubleClick(): true, you then have no option to get all the events, which is the current behaviour. Doesn't that risk breaking old code?

@AlexDM0
Copy link
Contributor

AlexDM0 commented Sep 17, 2014

if false, the user would get click - click, if true, the user would get click doubleclick. As for breaking old code, yes that is possible.. we could still emit the doubleclick so if false the user would get click - doubleclick - click as it is now.

@dsl101
Copy link

dsl101 commented Sep 17, 2014

I think that's basically cases 0 and 1 in my list. Case 2 is the 'new' one, where click = click() and double-click = doubleClick(), which might be good for new apps, and would save the user having to put the wait code in.

In your last scenario, supposing I wanted a user's 'click' to do something, but a user's 'double-click' to do nothing. I'd have to subscribe to the doubleClick() event, just to surpress the previous click() event that I got first on the first press of the mouse! Seems like it makes the library quite awkward from a developers point of view...

@AlexDM0
Copy link
Contributor

AlexDM0 commented Jan 9, 2015

Hi,

Over the last year a lot of feature requests have been made. We have just introduced our new website which has a list of the requested features. We have placed this request on that list.

The list can be found here:
http://visjs.org/featureRequests.html

An explaination of the new system can be found here:
http://visjs.org/blog.html#New\ website\ for\ vis.js!

I would like to stress that this does not mean we abandon this request. Discussion here will continue if needed on this feature but we will close it to keep our Github issue page more of a bug-todo list.

Future feature requests will still be made here and then added to the website by us.

Regards,

Alex

@mojoaxel mojoaxel changed the title Click and DoubleClick event Improve the click/doubleClick event with options how these should be fired. Oct 24, 2016
@mojoaxel
Copy link
Member

Reopening as Feature-Request issue (see #2114).
Everybody: Please feel free to implement this!

@supriyasureshg
Copy link

supriyasureshg commented Jul 10, 2017

Onclick of buttons how to show the particular segments of node.In vis js.
If any knows please help me out.

@wimrijnders
Copy link
Contributor

@supriyasureshg You commented here so I'll remove the label Inactive.
However, I don't really understand your comment, would you mind making it more clear?

@saliez
Copy link

saliez commented Jan 16, 2018

It is certainly very nice and ergonomic to be able to distinguish different actions using the same left mouse button.
Since the double click is a problem, an alternative could be to detect the time between the button down and the release.

  • If released after a short delay do action "A" intended as a single click. People will probably not feel a delay.
  • If released after a longer delay do action "B" intended as a double click. Takes of course a little more time like a double click do.
  • If moving outside the original location of the selected element before the end of the delay do action "C", i.e. a "drag and drop".

@MykhailoMykhaliuk
Copy link

I'd recommend to use Rx.js

@rohit2503
Copy link

I have following work to do :

  1. Click on graph.
  2. Pull the x axes data on which click was made.
  3. Using this x -axis value make ajax call.

I have written a function and map it to the clickCallBack of Dygraph. Things are working fine but soon you double click on graph will again call the function and I lost default feature of reset zoom. I know there should be something to differentiate the single click vs double click. The solution above told will not work for me since I need to fetch x axis value and click on container which holds graph will not fetch me point on which click was made.

I have even tried interactionModel but facing same problem. Please let me know your suggestion.
@dponch @AlexDM0

Thanks,
Rohit Jaiswal

@MykhailoMykhaliuk
Copy link

MykhailoMykhaliuk commented May 29, 2018

const source = Rx.Observable.fromEvent(container, 'click')
  .map(({ offsetX  }) => offsetX)
  .throttleTime(300)
  .subscribe(offsetX => {
    console.log(offsetX);
    // make ajax call here
  });

@rohit2503
Copy link

@MishaMykhalyukCogniance will it work for container which holds dygraph based graph. I have not used Rx before.

@MykhailoMykhaliuk
Copy link

MykhailoMykhaliuk commented May 29, 2018

@rohit2503 It should work. I've checked it on official site:
image

@rohit2503
Copy link

rohit2503 commented May 29, 2018

Sorry I tried but it's not working. I have used this RX js https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.0/rxjs.umd.js in my code. When I am typing in browser console Rx it is giving error Rx not found.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants