Touch screen not good with Carousel

Questions related to the Responsive Web Design tools of WYSIWYG Web Builder.
Forum rules
PLEASE READ THE FORUM RULES BEFORE YOU POST:
viewtopic.php?f=12&t=1901

MUST READ:
http://www.wysiwygwebbuilder.com/respon ... esign.html
Please read this first before posting any questions! Also check out the example project to get an idea how the RWD concept works.

Responsive Web Design FAQ:
http://wysiwygwebbuilder.com/forum/view ... 10&t=63817
Post Reply
Beth
 
 
Posts: 54
Joined: Mon Jan 15, 2018 10:55 pm

Touch screen not good with Carousel

Post by Beth » Thu Oct 24, 2019 7:08 pm

Maybe it's just me or my phone, but it seems that it is not possible to scroll up and down when there is a carousel on the page and you want to move the page. It's as if the carousel blocks the screen's ability to maneuver, which makes the page unusable - or at least very frustrating. Works great on a desktop but no good on a phone.

Is there a fix for this or is it just me or should I think of a different way all together?

See this example: https://oldbow.com/used-bows-slideshow.htm and try to move vertically when the carousel is covering the entire screen.

Thanks in advance.

User avatar
Pablo
 
Posts: 21508
Joined: Tue Mar 28, 2006 12:00 pm
Location: Europe
Contact:

Re: Touch screen not good with Carousel

Post by Pablo » Thu Oct 24, 2019 8:32 pm

The reason for this is because the carousel monitors touch events for scrolling through the slides.
For touch screens I recommend to use 'flexible' mode of the carousel, then it will work in both desktop and mobile mode.

Beth
 
 
Posts: 54
Joined: Mon Jan 15, 2018 10:55 pm

Re: Touch screen not good with Carousel

Post by Beth » Thu Oct 24, 2019 11:04 pm

Thank you Pablo.

The carousel is set to Width = Flexable / Height = Fixed. There is a single graphic on each panel. If I were to make the graphic into a background image for each panel I have the same result.

I have an HTML script to make the carousel swipeable, which works fine, but same problem with or without script:
<script>
/*! Hammer.JS - v1.0.6dev - 2013-09-12
* http://eightmedia.github.com/hammer.js
*
* Copyright (c) 2013 Jorik Tangelder <j.tangelder@gmail.com>;
* Licensed under the MIT license */
(function(t, e) {
"use strict";

function n() {
if (!r.READY) {
r.event.determineEventTypes();
for (var t in r.gestures) r.gestures.hasOwnProperty(t) && r.detection.register(r.gestures[t]);
r.event.onTouch(r.DOCUMENT, r.EVENT_MOVE, r.detection.detect), r.event.onTouch(r.DOCUMENT, r.EVENT_END, r.detection.detect), r.READY = !0
}
}
var r = function(t, e) {
return new r.Instance(t, e || {})
};
r.defaults = {
stop_browser_behavior: {
userSelect: "none",
touchAction: "none",
touchCallout: "none",
contentZooming: "none",
userDrag: "none",
tapHighlightColor: "rgba(0,0,0,0)"
}
}, r.HAS_POINTEREVENTS = t.navigator.pointerEnabled || t.navigator.msPointerEnabled, r.HAS_TOUCHEVENTS = "ontouchstart" in t, r.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android|silk/i, r.NO_MOUSEEVENTS = r.HAS_TOUCHEVENTS && t.navigator.userAgent.match(r.MOBILE_REGEX), r.EVENT_TYPES = {}, r.DIRECTION_DOWN = "down", r.DIRECTION_LEFT = "left", r.DIRECTION_UP = "up", r.DIRECTION_RIGHT = "right", r.POINTER_MOUSE = "mouse", r.POINTER_TOUCH = "touch", r.POINTER_PEN = "pen", r.EVENT_START = "start", r.EVENT_MOVE = "move", r.EVENT_END = "end", r.DOCUMENT = t.document, r.plugins = {}, r.READY = !1, r.Instance = function(t, e) {
var i = this;
return n(), this.element = t, this.enabled = !0, this.options = r.utils.extend(r.utils.extend({}, r.defaults), e || {}), this.options.stop_browser_behavior && r.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior), r.event.onTouch(t, r.EVENT_START, function(t) {
i.enabled && r.detection.startDetect(i, t)
}), this
}, r.Instance.prototype = {
on: function(t, e) {
for (var n = t.split(" "), r = 0; n.length > r; r++) this.element.addEventListener(n[r], e, !1);
return this
},
off: function(t, e) {
for (var n = t.split(" "), r = 0; n.length > r; r++) this.element.removeEventListener(n[r], e, !1);
return this
},
trigger: function(t, e) {
e || (e = {});
var n = r.DOCUMENT.createEvent("Event");
n.initEvent(t, !0, !0), n.gesture = e;
var i = this.element;
return r.utils.hasParent(e.target, i) && (i = e.target), i.dispatchEvent(n), this
},
enable: function(t) {
return this.enabled = t, this
}
};
var i = null,
o = !1,
s = !1;
r.event = {
bindDom: function(t, e, n) {
for (var r = e.split(" "), i = 0; r.length > i; i++) t.addEventListener(r, n, !1)
},
onTouch: function(t, e, n) {
var a = this;
this.bindDom(t, r.EVENT_TYPES[e], function(c) {
var u = c.type.toLowerCase();
if (!u.match(/mouse/) || !s) {
u.match(/touch/) || u.match(/pointerdown/) || u.match(/mouse/) && 1 === c.which ? o = !0 : u.match(/mouse/) && 1 !== c.which && (o = !1), u.match(/touch|pointer/) && (s = !0);
var h = 0;
o && (r.HAS_POINTEREVENTS && e != r.EVENT_END ? h = r.PointerEvent.updatePointer(e, c) : u.match(/touch/) ? h = c.touches.length : s || (h = u.match(/up/) ? 0 : 1), h > 0 && e == r.EVENT_END ? e = r.EVENT_MOVE : h || (e = r.EVENT_END), (h || null === i) && (i = c), n.call(r.detection, a.collectEventData(t, e, a.getTouchList(i, e), c)), r.HAS_POINTEREVENTS && e == r.EVENT_END && (h = r.PointerEvent.updatePointer(e, c))), h || (i = null, o = !1, s = !1, r.PointerEvent.reset())
}
})
},
determineEventTypes: function() {
var t;
t = r.HAS_POINTEREVENTS ? r.PointerEvent.getEvents() : r.NO_MOUSEEVENTS ? ["touchstart", "touchmove", "touchend touchcancel"] : ["touchstart mousedown", "touchmove mousemove", "touchend touchcancel mouseup"], r.EVENT_TYPES[r.EVENT_START] = t[0], r.EVENT_TYPES[r.EVENT_MOVE] = t[1], r.EVENT_TYPES[r.EVENT_END] = t[2]
},
getTouchList: function(t) {
return r.HAS_POINTEREVENTS ? r.PointerEvent.getTouchList() : t.touches ? t.touches : (t.indentifier = 1, [t])
},
collectEventData: function(t, e, n, i) {
var o = r.POINTER_TOUCH;
return (i.type.match(/mouse/) || r.PointerEvent.matchType(r.POINTER_MOUSE, i)) && (o = r.POINTER_MOUSE), {
center: r.utils.getCenter(n),
timeStamp: (new Date).getTime(),
target: i.target,
touches: n,
eventType: e,
pointerType: o,
srcEvent: i,
preventDefault: function() {
this.srcEvent.preventManipulation && this.srcEvent.preventManipulation(), this.srcEvent.preventDefault && this.srcEvent.preventDefault()
},
stopPropagation: function() {
this.srcEvent.stopPropagation()
},
stopDetect: function() {
return r.detection.stopDetect()
}
}
}
}, r.PointerEvent = {
pointers: {},
getTouchList: function() {
var t = this,
e = [];
return Object.keys(t.pointers).sort().forEach(function(n) {
e.push(t.pointers[n])
}), e
},
updatePointer: function(t, e) {
return t == r.EVENT_END ? this.pointers = {} : (e.identifier = e.pointerId, this.pointers[e.pointerId] = e), Object.keys(this.pointers).length
},
matchType: function(t, e) {
if (!e.pointerType) return !1;
var n = {};
return n[r.POINTER_MOUSE] = e.pointerType == e.MSPOINTER_TYPE_MOUSE || e.pointerType == r.POINTER_MOUSE, n[r.POINTER_TOUCH] = e.pointerType == e.MSPOINTER_TYPE_TOUCH || e.pointerType == r.POINTER_TOUCH, n[r.POINTER_PEN] = e.pointerType == e.MSPOINTER_TYPE_PEN || e.pointerType == r.POINTER_PEN, n[t]
},
getEvents: function() {
return ["pointerdown MSPointerDown", "pointermove MSPointerMove", "pointerup pointercancel MSPointerUp MSPointerCancel"]
},
reset: function() {
this.pointers = {}
}
}, r.utils = {
extend: function(t, n, r) {
for (var i in n) t !== e && r || (t = n);
return t
},
hasParent: function(t, e) {
for (; t;) {
if (t == e) return !0;
t = t.parentNode
}
return !1
},
getCenter: function(t) {
for (var e = [], n = [], r = 0, i = t.length; i > r; r++) e.push(t[r].pageX), n.push(t[r].pageY);
return {
pageX: (Math.min.apply(Math, e) + Math.max.apply(Math, e)) / 2,
pageY: (Math.min.apply(Math, n) + Math.max.apply(Math, n)) / 2
}
},
getVelocity: function(t, e, n) {
return {
x: Math.abs(e / t) || 0,
y: Math.abs(n / t) || 0
}
},
getAngle: function(t, e) {
var n = e.pageY - t.pageY,
r = e.pageX - t.pageX;
return 180 * Math.atan2(n, r) / Math.PI
},
getDirection: function(t, e) {
var n = Math.abs(t.pageX - e.pageX),
i = Math.abs(t.pageY - e.pageY);
return n >= i ? t.pageX - e.pageX > 0 ? r.DIRECTION_LEFT : r.DIRECTION_RIGHT : t.pageY - e.pageY > 0 ? r.DIRECTION_UP : r.DIRECTION_DOWN
},
getDistance: function(t, e) {
var n = e.pageX - t.pageX,
r = e.pageY - t.pageY;
return Math.sqrt(n * n + r * r)
},
getScale: function(t, e) {
return t.length >= 2 && e.length >= 2 ? this.getDistance(e[0], e[1]) / this.getDistance(t[0], t[1]) : 1
},
getRotation: function(t, e) {
return t.length >= 2 && e.length >= 2 ? this.getAngle(e[1], e[0]) - this.getAngle(t[1], t[0]) : 0
},
isVertical: function(t) {
return t == r.DIRECTION_UP || t == r.DIRECTION_DOWN
},
stopDefaultBrowserBehavior: function(t, e) {
var n, r = ["webkit", "khtml", "moz", "Moz", "ms", "o", ""];
if (e && t.style) {
for (var i = 0; r.length > i; i++)
for (var o in e) e.hasOwnProperty(o) && (n = o, r && (n = r + n.substring(0, 1).toUpperCase() + n.substring(1)), t.style[n] = e[o]);
"none" == e.userSelect && (t.onselectstart = function() {
return !1
}), "none" == e.userDrag && (t.ondragstart = function() {
return !1
})
}
}
}, r.detection = {
gestures: [],
current: null,
previous: null,
stopped: !1,
startDetect: function(t, e) {
this.current || (this.stopped = !1, this.current = {
inst: t,
startEvent: r.utils.extend({}, e),
lastEvent: !1,
name: ""
}, this.detect(e))
},
detect: function(t) {
if (this.current && !this.stopped) {
t = this.extendEventData(t);
for (var e = this.current.inst.options, n = 0, i = this.gestures.length; i > n; n++) {
var o = this.gestures[n];
if (!this.stopped && e[o.name] !== !1 && o.handler.call(o, t, this.current.inst) === !1) {
this.stopDetect();
break
}
}
return this.current && (this.current.lastEvent = t), t.eventType == r.EVENT_END && !t.touches.length - 1 && this.stopDetect(), t
}
},
stopDetect: function() {
this.previous = r.utils.extend({}, this.current), this.current = null, this.stopped = !0
},
extendEventData: function(t) {
var e = this.current.startEvent;
if (e && (t.touches.length != e.touches.length || t.touches === e.touches)) {
e.touches = [];
for (var n = 0, i = t.touches.length; i > n; n++) e.touches.push(r.utils.extend({}, t.touches[n]))
}
var o = t.timeStamp - e.timeStamp,
s = t.center.pageX - e.center.pageX,
a = t.center.pageY - e.center.pageY,
c = r.utils.getVelocity(o, s, a);
return r.utils.extend(t, {
deltaTime: o,
deltaX: s,
deltaY: a,
velocityX: c.x,
velocityY: c.y,
distance: r.utils.getDistance(e.center, t.center),
angle: r.utils.getAngle(e.center, t.center),
interimAngle: this.current.lastEvent && r.utils.getAngle(this.current.lastEvent.center, t.center),
direction: r.utils.getDirection(e.center, t.center),
interimDirection: this.current.lastEvent && r.utils.getDirection(this.current.lastEvent.center, t.center),
scale: r.utils.getScale(e.touches, t.touches),
rotation: r.utils.getRotation(e.touches, t.touches),
startEvent: e
}), t
},
register: function(t) {
var n = t.defaults || {};
return n[t.name] === e && (n[t.name] = !0), r.utils.extend(r.defaults, n, !0), t.index = t.index || 1e3, this.gestures.push(t), this.gestures.sort(function(t, e) {
return t.index < e.index ? -1 : t.index > e.index ? 1 : 0
}), this.gestures
}
}, r.gestures = r.gestures || {}, r.gestures.Hold = {
name: "hold",
index: 10,
defaults: {
hold_timeout: 500,
hold_threshold: 1
},
timer: null,
handler: function(t, e) {
switch (t.eventType) {
case r.EVENT_START:
clearTimeout(this.timer), r.detection.current.name = this.name, this.timer = setTimeout(function() {
"hold" == r.detection.current.name && e.trigger("hold", t)
}, e.options.hold_timeout);
break;
case r.EVENT_MOVE:
t.distance > e.options.hold_threshold && clearTimeout(this.timer);
break;
case r.EVENT_END:
clearTimeout(this.timer)
}
}
}, r.gestures.Tap = {
name: "tap",
index: 100,
defaults: {
tap_max_touchtime: 250,
tap_max_distance: 10,
tap_always: !0,
doubletap_distance: 20,
doubletap_interval: 300
},
handler: function(t, e) {
if (t.eventType == r.EVENT_END && "touchcancel" != t.srcEvent.type) {
var n = r.detection.previous,
i = !1;
if (t.deltaTime > e.options.tap_max_touchtime || t.distance > e.options.tap_max_distance) return;
n && "tap" == n.name && t.timeStamp - n.lastEvent.timeStamp < e.options.doubletap_interval && t.distance < e.options.doubletap_distance && (e.trigger("doubletap", t), i = !0), (!i || e.options.tap_always) && (r.detection.current.name = "tap", e.trigger(r.detection.current.name, t))
}
}
}, r.gestures.Swipe = {
name: "swipe",
index: 40,
defaults: {
swipe_max_touches: 1,
swipe_velocity: .7
},
handler: function(t, e) {
if (t.eventType == r.EVENT_END) {
if (e.options.swipe_max_touches > 0 && t.touches.length > e.options.swipe_max_touches) return;
(t.velocityX > e.options.swipe_velocity || t.velocityY > e.options.swipe_velocity) && (e.trigger(this.name, t), e.trigger(this.name + t.direction, t))
}
}
}, r.gestures.Drag = {
name: "drag",
index: 50,
defaults: {
drag_min_distance: 10,
correct_for_drag_min_distance: !0,
drag_max_touches: 1,
drag_block_horizontal: !1,
drag_block_vertical: !1,
drag_lock_to_axis: !1,
drag_lock_min_distance: 25
},
triggered: !1,
handler: function(t, n) {
if (r.detection.current.name != this.name && this.triggered) return n.trigger(this.name + "end", t), this.triggered = !1, e;
if (!(n.options.drag_max_touches > 0 && t.touches.length > n.options.drag_max_touches)) switch (t.eventType) {
case r.EVENT_START:
this.triggered = !1;
break;
case r.EVENT_MOVE:
if (t.distance < n.options.drag_min_distance && r.detection.current.name != this.name) return;
if (r.detection.current.name != this.name && (r.detection.current.name = this.name, n.options.correct_for_drag_min_distance)) {
var i = Math.abs(n.options.drag_min_distance / t.distance);
r.detection.current.startEvent.center.pageX += t.deltaX * i, r.detection.current.startEvent.center.pageY += t.deltaY * i, t = r.detection.extendEventData(t)
}(r.detection.current.lastEvent.drag_locked_to_axis || n.options.drag_lock_to_axis && n.options.drag_lock_min_distance <= t.distance) && (t.drag_locked_to_axis = !0);
var o = r.detection.current.lastEvent.direction;
t.drag_locked_to_axis && o !== t.direction && (t.direction = r.utils.isVertical(o) ? 0 > t.deltaY ? r.DIRECTION_UP : r.DIRECTION_DOWN : 0 > t.deltaX ? r.DIRECTION_LEFT : r.DIRECTION_RIGHT), this.triggered || (n.trigger(this.name + "start", t), this.triggered = !0), n.trigger(this.name, t), n.trigger(this.name + t.direction, t), (n.options.drag_block_vertical && r.utils.isVertical(t.direction) || n.options.drag_block_horizontal && !r.utils.isVertical(t.direction)) && t.preventDefault();
break;
case r.EVENT_END:
this.triggered && n.trigger(this.name + "end", t), this.triggered = !1
}
}
}, r.gestures.Transform = {
name: "transform",
index: 45,
defaults: {
transform_min_scale: .01,
transform_min_rotation: 1,
transform_always_block: !1
},
triggered: !1,
handler: function(t, n) {
if (r.detection.current.name != this.name && this.triggered) return n.trigger(this.name + "end", t), this.triggered = !1, e;
if (!(2 > t.touches.length)) switch (n.options.transform_always_block && t.preventDefault(), t.eventType) {
case r.EVENT_START:
this.triggered = !1;
break;
case r.EVENT_MOVE:
var i = Math.abs(1 - t.scale),
o = Math.abs(t.rotation);
if (n.options.transform_min_scale > i && n.options.transform_min_rotation > o) return;
r.detection.current.name = this.name, this.triggered || (n.trigger(this.name + "start", t), this.triggered = !0), n.trigger(this.name, t), o > n.options.transform_min_rotation && n.trigger("rotate", t), i > n.options.transform_min_scale && (n.trigger("pinch", t), n.trigger("pinch" + (1 > t.scale ? "in" : "out"), t));
break;
case r.EVENT_END:
this.triggered && n.trigger(this.name + "end", t), this.triggered = !1
}
}
}, r.gestures.Touch = {
name: "touch",
index: -1 / 0,
defaults: {
prevent_default: !1,
prevent_mouseevents: !1
},
handler: function(t, n) {
return n.options.prevent_mouseevents && t.pointerType == r.POINTER_MOUSE ? (t.stopDetect(), e) : (n.options.prevent_default && t.preventDefault(), t.eventType == r.EVENT_START && n.trigger(this.name, t), e)
}
}, r.gestures.Release = {
name: "release",
index: 1 / 0,
handler: function(t, e) {
t.eventType == r.EVENT_END && e.trigger(this.name, t)
}
}, "function" == typeof define && "object" == typeof define.amd && define.amd ? define(function() {
return r
}) : "object" == typeof module && "object" == typeof module.exports ? module.exports = r : t.Hammer = r
})(this),
function(t) {
"use strict";
var e = function(e, n) {
return n === t ? e : (e.event.bindDom = function(e, r, i) {
n(e).on(r, function(e) {
var n = e.originalEvent || e;
n.pageX === t && (n.pageX = e.pageX, n.pageY = e.pageY), n.target || (n.target = e.target), n.which === t && (n.which = n.button), n.preventDefault || (n.preventDefault = e.preventDefault), n.stopPropagation || (n.stopPropagation = e.stopPropagation), i.call(this, n)
})
}, e.Instance.prototype.on = function(t, e) {
return n(this.element).on(t, e)
}, e.Instance.prototype.off = function(t, e) {
return n(this.element).off(t, e)
}, e.Instance.prototype.trigger = function(t, e) {
var r = n(this.element);
return r.has(e.target).length && (r = n(e.target)), r.trigger({
type: t,
gesture: e
})
}, n.fn.hammer = function(t) {
return this.each(function() {
var r = n(this),
i = r.data("hammer");
i ? i && t && e.utils.extend(i.options, t) : r.data("hammer", new e(this, t || {}))
})
}, e)
};
"function" == typeof define && "object" == typeof define.amd && define.amd ? define("hammer-jquery", ["hammer", "jquery"], e) : e(window.Hammer, window.jQuery || window.Zepto)
}();
$(document).ready(function()
{
$('.carousel').each(function ()
{
var $carousel = $(this);
var hammertime = new Hammer(this,
{
recognizers: [
[Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL }]
]
});
hammertime.on('swipeleft', function ()
{
$carousel.bootstrapcarousel('next');
});
hammertime.on('swiperight', function ()
{
$carousel.bootstrapcarousel('prev');
});
});
});
</script>

----------------------------------------
Maybe I'll try a Lightbox gallery? It's not what I want but it has to be useful. Does the OWL carousel work better?

Beth

User avatar
Pablo
 
Posts: 21508
Joined: Tue Mar 28, 2006 12:00 pm
Location: Europe
Contact:

Re: Touch screen not good with Carousel

Post by Pablo » Fri Oct 25, 2019 6:33 am

The built-in carousel uses Bootstrap.

The behavior is discussed here:
https://github.com/twbs/bootstrap/issues/27531

Beth
 
 
Posts: 54
Joined: Mon Jan 15, 2018 10:55 pm

Re: Touch screen not good with Carousel

Post by Beth » Fri Oct 25, 2019 7:42 pm

Thank you Pablo.

That's good to know and maybe I missed it in the documentation. I have spent many hours trying to make it work but now I know why it doesn't. This should be a FAQ or something.

I've gone with a plain-vanilla Slideshow (not swipeable) but at least it is usable. Alas...

Post Reply