zingchart / zingtouch

A JavaScript touch gesture detection library for the modern web
https://zingchart.github.io/zingtouch/
MIT License
2.12k stars 135 forks source link

Gesture Area Access #19

Closed 1ubuntuuser closed 6 years ago

1ubuntuuser commented 7 years ago

Is it possible for gesture actions to be detected through embedded div elements? I have some div elements inside a parent div. I set the parent div to be the gesture region and area. This disabled the onclick event of the child div elements. Is there a way to keep the functionality of div elements within a gesture region without interrupting the gestures? Previously, I had been using the js listener bellow to accomplish my desired result.

ParentDiv.addEventListener('touchstart' handleTouchStart, false);

I am impressed with the library and would hate to stop using it because of this issue! Any help would be appreciated.

mike-schultz commented 7 years ago

Hey @danielwilson654 can you put together a demo of the issue you are having up on jsfiddle or codepen?

1ubuntuuser commented 7 years ago

Hey @mike-schultz, Here is an example on codepen http://codepen.io/danielwilson654/pen/oZBGqG

I used the pinch/extend gestures in the example.

I would like to know if it is possible to use the "Click Me!" div for gesture purposes while maintaining the ability to click the div.

I am able to make the "Click Me!" div clickable while inside the gesture area, but then gestures are interrupted by that div.

mike-schultz commented 7 years ago

Hey @danielwilson654 , thanks for the demo. The previous logic disallowed any gestures not originating from the same point, and didn't account for nested elements. I modified the code a bit and it should be a bit more flexible on this branch: https://github.com/zingchart/zingtouch/tree/fix-19

Let me know how it goes...

1ubuntuuser commented 7 years ago

Thank you, Mike! I'll give the fix a shot.

1ubuntuuser commented 7 years ago

Hi Mike,

v1.0.5 didn't seem to do it unfortunately. I Updated the Codepen test to use v1.0.5. Gestures work over the top of the button div but unfortunately the dive does not respond to clicks where the button div overlaps the gesture area.

I was able to work around this issue partially by setting the Region's PreventDefaults property to false and then stopping propagation at the document level. This workaround causes response issues in some applications so it's not a real fix. Uncomment Line 30 to activate the work around.

Thanks for putting in the time to address this issue.

1ubuntuuser commented 7 years ago

Any progress on this one?

mike-schultz commented 7 years ago

Hey @danielwilson654 , I took a look at this and can see some issues with zooming + native events. Native zoom and scrolling gestures are problematic on mobile devices, so setting preventDefault on regions is preferred to help with that.

Instead of using native onclick events, are you able to use the library's 'tap' event? It tracks browser clicks as well as mobile taps. It seems like it works in your specific use case.

1ubuntuuser commented 7 years ago

Hey @mike-schultz, Thanks for looking into this. My company uses Xojo Web to build web apps. The Xojo web app has pre-built html/JS controls. I was hoping not to touch every web control.

I am trying to use ZingTouch as the back-end for a drag and drop control that you can easily program with check boxes and object assignments. The ZingtTouch library works as advertised but web apps are often more complicated then simple web pages so perhaps that's why I am running into problems.

If I understand what you are saying correctly, I will have to use ZingTouch for all the user control interactions?

mike-schultz commented 7 years ago

@danielwilson654

Hey Daniel, more or less, using zingtouch and native events get tricky since we are trying to suppress browser gestures as much as we can.

I was able to figure out a way to get native events working while still maintaining functionality, but it only seems to work when at least one of the inputs is on the target. Hopefully this might give you a bit of insight:

  1. Set your Region's preventDefault to false (3rd parameter). By default, ZingTouch will force preventDefault on all events for that area. By setting this to false, we are allowing all browser gestures (zooming, scrolling) and native events to be called. The click event should be working at this point.

e.g. new ZingTouch.Region(parent, false, false );

  1. Call preventDefault manually at the end of each of your pinch/expand events. This will prevent browser gestures from occurring. This won't effect click events since they are disjoint and cannot happen at the same time as a pinch/expand.

e.g.

region.bind(el, 'pinch', e => {

  //Your code here
  // e.detail.events contains an array of special ZingTouch events.
  e.detail.events.forEach(event => {
    // Within each of those special ZingTouch events, the originalEvent the browser emitted is stored.
    event.originalEvent.preventDefault();
  });
});

http://codepen.io/mike-schultz/pen/RVGeLW

1ubuntuuser commented 7 years ago

Thanks Mike, I'm testing this now. It appears the fix only works for the updated Iphone OS. I'll let you know how I go.

1ubuntuuser commented 7 years ago

Okay, Got it working! Thanks for pointing me down the right track.

I had to make the following changes.

1. 'e.detail.events.forEach(event => {' caused error on some mobile browsers.

I replaced it with the following code.

 for (var i = 0, len = e.detail.events.length; i < len; i++) {
e.detail.events[i].originalEvent.preventDefault();
}

2. 'Element.getBoundingClientRect()' doesn't work on some mobile browsers and causes the DOM to repaint everything.

I substituted it with a new function I added to the module. I'm not sure if it's any faster but it works on older browsers. I'm not very experienced with building JS libraries so I have no idea how to compile it into the zingtouch.min.js

/**
       * Gets the x,y position of a target. Alternative to Element.getBoundingClientRect. Source: https://gist.github.com/caryfuk/3b7bb50831421f1873aa. Modified By DocBlaster.
       * @param {Element} target
       * @return {Object}
       */

       getTargetPosition: function getTargetPosition(elm) {
          var xPos = 0, yPos = 0, elmW = 0, elmH = 0;
          elmW = elm.clientWidth
           elmH = elm.clientHeight
          while(elm) {
            xPos += (elm.offsetLeft - elm.scrollLeft + elm.clientLeft);
            yPos += (elm.offsetTop - elm.scrollTop + elm.clientTop);
            elm = elm.offsetParent;
          }

          return { x: xPos, y: yPos, left: xPos, top: yPos, width: elmW, height: elmH };
        },

3. Expand/Pinch gestures where ignored 10% of the time.

It would seem even after replacing the 'Element.getBoundingClientRect()' sometimes (but not usually) the isInside function fails to retrieve information from the DOM. The function errors and therefor returns false. I added the following try catch to at least suppress the bug.

/**
       * Determines if the x,y position of the input is within then target.
       * @param {Number} x -clientX
       * @param {Number} y -clientY
       * @param {Element} target
       * @return {Boolean}
       */
      isInside: function isInside(x, y, target) {
             try {
                  var result
              var rect = exports.default.getTargetPosition(target); 
              //console.log(rect);
                  result = x > rect.left && x < rect.left + rect.width && y > rect.top && y < rect.top + rect.height;
                  //console.log(result);
                  return result;
              }
              catch(err) {
                  return true //Bypassed because the function fails from time to time on older browsers.
              } 

      },

Thanks again for your support with these issues.

mike-schultz commented 7 years ago

Glad it worked out! Curious, what browsers are you running into that getBoundingClientRect forces a repaint?

1ubuntuuser commented 7 years ago

So they say... https://gist.github.com/paulirish/5d52fb081b3570c81e3a.

But i also noticed that clientHeight also causes layout thrashing as they call it. The performance wasn't really my main concern. Cross browser support is a large concern to me.

1ubuntuuser commented 6 years ago

I see you have closed this and a new release is available. Will I need to re-edit the new releases as per above?

mike-schultz commented 6 years ago

Hey @danielwilson654, I'm trying to close out old issues and old pull requests this week. If you'd like lets revisit this as a pull request so the fixes you found can be added in?