almende / vis

⚠️ This project is not maintained anymore! Please go to https://github.com/visjs
7.85k stars 1.48k forks source link

Polymer and visjs timeline : click (selection) doesn't work #3051

Open rom1504 opened 7 years ago

rom1504 commented 7 years ago

I'm trying to put visjs timeline in a web component using polymer

I've managed to get it to work but there is one problem : the click on item doesn't work. Only the long click is detected.

I think polymer or the shadow dom concept is probably conflicting with visjs handling of clicks.

Here is a demo of that : http://plnkr.co/edit/6OmfKqAl6UKzKbLQViei?p=preview You can long click on items to select them but not simple click on them.

The update event is also not emitted (double click on item). I guess it works with the same functionnalities.

Is there something I can do in visjs to make this work ? Is this a visjs bug ?

yotamberk commented 7 years ago

Try the version in the develop branch. I've fixed the click and double click functionality there

rom1504 commented 7 years ago

I'm getting that error with the develop branch:

Uncaught TypeError: Cannot read property 'getIds' of null
    at ItemSet.groupFromTarget (ItemSet.js:2224)
    at Timeline.getEventProperties (Timeline.js:542)
    at HTMLDivElement.Timeline.dom.root.onmousemove (Timeline.js:143)

(I'm not using groups)

rom1504 commented 7 years ago

I fixed that bug in #3061 About my problem, doing:

timeline.on("click", (e) => {
          timeline.setSelection(e.item);
        });

fixes it. I'm not sure whether that's something to fix in visjs.

PhilAndrew commented 7 years ago

I want to use this timeline as a webcomponent, can you suggest how I can do that?

rom1504 commented 7 years ago

I've been using it there https://github.com/rom1504/camomile-polymer-client/blob/master/camomile-segmentation.html It works using the last release (vis 4.20.0).

You can probably use that as an example.

PhilAndrew commented 7 years ago

I see your example is a good place to start http://plnkr.co/edit/6OmfKqAl6UKzKbLQViei?p=preview

MeTaNoV commented 6 years ago

Indeed working in 'develop' but only when using the trick of @rom1504 , waiting impatiently for full working released version integrating those fixes!

MeTaNoV commented 6 years ago

@yotamberk , thanks for reopening this issue.

I create a repo with a simple encapsulation of a build of Vis from the develop branch. You can find it here: https://github.com/MeTaNoV/vis-element

You need to have the polymer cli installed on your machine (https://github.com/Polymer/polymer-cli) (And also bower). Then, when cloning my repo, run a first time bower install, then simply replace vis.min.js and vis.min.css at the root with the new test version. And run the demo polymer serve -o. There is currently 2 timelines which shows that the timeline.on() method is working with the "click" event, that can eventually call "setSelection" on the clicked item. But this simple scenario is not enough when considering for example multiselect.

Tell me if I can help any further. For example, if you can orient me in your codebase, I can try to figure out what's going wrong!

MeTaNoV commented 6 years ago

I was able to investigate a bit the issue. The problem happens in _onSelectItem() from ItemSet.js where the following line:

  var item = this.itemFromTarget(event);

return undefined because it seems that event.target point to a wrong element, whereas event.firstTarget is holding the proper value. As a temporary workaround, I switched the code to the firstTarget but would like to understand how the shadowDom or any other mechanism is leading to the change of the target value.

connollyst commented 6 years ago

Hi all,

Any update on this ticket? I tried rom1504's solution of manually wiring up a click listener to timeline.setSelection, which worked for selecting items. However, when I have clickToUse enabled, no interaction is possible - surely the same issue.

I'm using 4.21.0, is there a fix in the pipeline? If not, any recommendation on how to fix all click listeners, not just item selection?

Cheers, Sean

mpilone commented 5 years ago

I started to look into this because I'm having the same issue when trying to use the Timeline in a Polymer component. Unfortunately I'm not a JS expert so I'm moving pretty slowly but I did find that the Activator.prototype.activate function is called on click, the overlay is disabled, but then the Activator.prototype.deactivate function is immediately called.

It looks like the Activator attempts to ignore click events that were on the overlay using the _hasParent() function but, in my case, the container is not a parent of event.target. The event.originalTarget is the div.vis-overlay but the target is my root Polymer element/view.

My guess is that there is some kind of "event retargeting" happening due to shadow DOM but I have to learn a lot more before I know how to fix it. If others are still looking into this maybe we can find a solution. I'm assuming item selection is a related case but I haven't looked at it yet.

mpilone commented 5 years ago

I found two changes that appear to make things work correctly. As suspected, both issues are related to shadow DOM and checking the parent of a node.

The first fix for general selection support is in HammerJs. The file vis/node_modules/hammerjs/src/input.js needs to be modified at line 190 to read:

    // find the correct target
    var target = manager.element;
    // if (hasParent(input.srcEvent.target, target)) {
    //     target = input.srcEvent.target;
    // }
    // MIKE FIX
    var eventTarget = input.srcEvent.composedPath().length > 0 ? 
        input.srcEvent.composedPath()[0] : input.srcEvent.target;
    if (hasParent(eventTarget, target)) {
        target = eventTarget;
    }
    input.target = target;

This fixes an issue where window mouseup/pointerup events are targeting the root web component node due to event retargeting so the hasParent check will fail and the incorrect target will be used.

The second fix for activating the Timeline when using clickToUse is in VisJs. The file lib/shared/Activator.js needs to be modified at line 44 to read:

// attach a click event to the window, in order to deactivate when clicking outside the timeline
  if (document && document.body) {
    this.onClick = function (event) {

        // MIKE FIX
        if (event.composedPath().indexOf(container) === -1) {
            me.deactivate();
        }
      // if (!_hasParent(event.target, container)) {
      //   me.deactivate();
      // }
    };
    document.body.addEventListener('click', this.onClick);

Again, this is an issue with a window listener that is trying to determine if the target node is a child of the container but the target will be retargeted to the web component root and therefore not match.

I believe my fixes will only work with "open" shadow DOM and not "closed" so I'm not sure if there is a better solution. I also get double select event callbacks but I haven't looked into that yet and I don't know if that is "normal" behavior for the timeline.

Unfortunately HammerJs doesn't appear to be actively developed so I doubt it will be updated for web components and shadow DOM support. I'm also not sure about the state of VisJs development but it probably needs to a review to look for any window level listeners that are trying to recursively check event parent/child relationships because shadow DOM makes that a little tricky. Given the state of HammerJs, another pointer/gesture solution may be needed as well.