From dbdf740d8e93f45d3bcddc17baa9ae76cb47ecff Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Fri, 25 Sep 2015 17:27:49 +0300 Subject: [PATCH 1/4] Added better swiping support for touch devices. --- js/impress.js | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/js/impress.js b/js/impress.js index 84659a2a2..154ae0fb6 100644 --- a/js/impress.js +++ b/js/impress.js @@ -179,7 +179,7 @@ // but some mobile devices need to be blacklisted, // because their CSS 3D support or hardware is not // good enough to run impress.js properly, sorry... - ( ua.search(/(iphone)|(ipod)|(android)/) === -1 ); + ( ua.search(/(iphone)|(ipod)/) === -1 ); if (!impressSupported) { // we can't be sure that `classList` is supported @@ -761,25 +761,38 @@ } }, false); - // touch handler to detect taps on the left and right side of the screen - // based on awesome work of @hakimel: https://github.com/hakimel/reveal.js - document.addEventListener("touchstart", function ( event ) { - if (event.touches.length === 1) { - var x = event.touches[0].clientX, - width = window.innerWidth * 0.3, - result = null; - - if ( x < width ) { - result = api.prev(); - } else if ( x > window.innerWidth - width ) { - result = api.next(); - } - - if (result) { - event.preventDefault(); - } + // Touch handler to detect swiping left and right based on window size. + // If the difference in X change is bigger than 1/20 of the screen width, + // we simply call an appropriate API function. + var lastX = 0; + var lastDiff = 0; + var threshold = window.innerWidth / 20; + var touchCount = 0; // To prevent multi-touch 'jumps' that mess everything up + + document.addEventListener('touchstart', function (event) { + console.log(event); + if (! touchCount++) { + // If touchCount is zero + lastX = event.touches[0].clientX; } - }, false); + }); + document.addEventListener('touchmove', function(event) { + var x = event.touches[0].clientX; + lastDiff = lastX - x; + lastX = x; + }); + document.addEventListener('touchend', function (event) { + if (lastDiff < -threshold) { + api.prev(); + } else if (lastDiff > threshold) { + api.next(); + } + + lastX = 0; + lastDiff = 0; + + touchCount--; + }); // rescale presentation when window is resized window.addEventListener("resize", throttle(function () { From 43724d118807b04b811d91f56899d64bb9075299 Mon Sep 17 00:00:00 2001 From: and3rson Date: Sat, 26 Sep 2015 21:20:47 +0300 Subject: [PATCH 2/4] Improved swipe effect. --- js/impress.js | 177 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 40 deletions(-) diff --git a/js/impress.js b/js/impress.js index 154ae0fb6..631325f18 100644 --- a/js/impress.js +++ b/js/impress.js @@ -84,7 +84,21 @@ var toNumber = function (numeric, fallback) { return isNaN(numeric) ? (fallback || 0) : Number(numeric); }; - + + var toNumberAdvanced = function (numeric) { + if (!(typeof numeric == 'string')) { + return toNumber(numeric); + } + var ratio = numeric.match(/^([\d\.]+)([wh])$/); + if (ratio == null) { + return toNumber(numeric); + } else { + var value = parseFloat(ratio[1]); + var multiplier = ratio[2] == 'w' ? window.innerWidth : window.innerHeight; + return value * multiplier; + } + }; + // `byId` returns element with given `id` - you probably have guessed that ;) var byId = function ( id ) { return document.getElementById(id); @@ -299,9 +313,9 @@ var data = el.dataset, step = { translate: { - x: toNumber(data.x), - y: toNumber(data.y), - z: toNumber(data.z) + x: toNumberAdvanced(data.x), + y: toNumberAdvanced(data.y), + z: toNumberAdvanced(data.z) }, rotate: { x: toNumber(data.rotateX), @@ -555,7 +569,11 @@ return goto(prev); }; - + + var interpolate = function(a, b, k) { + return a + (b - a) * k; + }; + // `next` API function goes to next step (in document order) var next = function () { var next = steps.indexOf( activeStep ) + 1; @@ -563,7 +581,119 @@ return goto(next); }; - + + // Touch handler to detect swiping left and right based on window size. + // If the difference in X change is bigger than 1/20 of the screen width, + // we simply call an appropriate API function. + var startX = 0; + var lastX = 0; + var lastDX = 0; + var threshold = window.innerWidth / 20; + + document.addEventListener('touchstart', function (event) { + startX = event.touches[0].clientX; + lastX = startX; + }); + document.addEventListener('touchmove', function (event) { + var x = event.touches[0].clientX; + var diff = x - startX; + + lastDX = lastX - x; + + lastX = x; + + // currentState + + var target; + if (diff < 0) { + var next = steps.indexOf(activeStep) + 1; + target = next < steps.length ? steps[next] : steps[0]; + } else if (diff > 0) { + var prev = steps.indexOf(activeStep) - 1; + target = prev >= 0 ? steps[prev] : steps[steps.length - 1]; + } else { + // No move + return; + } + + var targetStep = stepsData['impress-' + target.id]; + + var k = Math.abs(diff) / window.innerWidth; + + //console.log(currentState); + + //console.log(activeStep.id, '->', targetStep.el.id); + + + var zoomin = targetStep.scale >= currentState.scale; + + // if the same step is re-selected, force computing window scaling, + var targetScale = targetStep.scale * windowScale; + + var interpolatedStep = { + translate: { + x: interpolate(currentState.translate.x, -targetStep.translate.x, k), + y: interpolate(currentState.translate.y, -targetStep.translate.y, k), + z: interpolate(currentState.translate.z, -targetStep.translate.z, k) + }, + rotate: { + x: interpolate(currentState.rotate.x, -targetStep.rotate.x, k), + y: interpolate(currentState.rotate.y, -targetStep.rotate.y, k), + z: interpolate(currentState.rotate.z, -targetStep.rotate.z, k) + }, + scale: interpolate(currentState.scale, targetScale) + }; + + css(root, { + // to keep the perspective look similar for different scales + // we need to 'scale' the perspective, too + transform: perspective(config.perspective / interpolatedStep.scale) + scale(interpolatedStep.scale), + transitionDuration: "0ms", + transitionDelay: "0ms" + }); + + css(canvas, { + transform: rotate(interpolatedStep.rotate, true) + translate(interpolatedStep.translate), + transitionDuration: "0ms", + transitionDelay: "0ms" + }); + }); + document.addEventListener('touchend', function (event) { + var totalDiff = lastX - startX; + + if (Math.abs(totalDiff) > window.innerWidth / 2) { + if (totalDiff > window.innerWidth / 2) { + prev(); + } else if (totalDiff < -window.innerWidth / 2) { + next(); + } + } else if (Math.abs(lastDX) > threshold) { + if (lastDX < -threshold) { + prev(); + } else if (lastDX > threshold) { + next(); + } + } else { + // No movement - move to the same slide + + css(root, { + // to keep the perspective look similar for different scales + // we need to 'scale' the perspective, too + transform: perspective(config.perspective / currentState.scale) + scale(currentState.scale), + transitionDuration: config.transitionDuration + "ms", + transitionDelay: "0ms" + }); + + css(canvas, { + transform: rotate(currentState.rotate, true) + translate(currentState.translate), + //transitionDuration: duration + "ms", + //transitionDelay: (zoomin ? 0 : delay) + "ms" + transitionDuration: config.transitionDuration + "ms", + transitionDelay: "0ms" + }); + } + }); + // Adding some useful classes to step elements. // // All the steps that have not been shown yet are given `future` class. @@ -760,46 +890,13 @@ event.preventDefault(); } }, false); - - // Touch handler to detect swiping left and right based on window size. - // If the difference in X change is bigger than 1/20 of the screen width, - // we simply call an appropriate API function. - var lastX = 0; - var lastDiff = 0; - var threshold = window.innerWidth / 20; - var touchCount = 0; // To prevent multi-touch 'jumps' that mess everything up - document.addEventListener('touchstart', function (event) { - console.log(event); - if (! touchCount++) { - // If touchCount is zero - lastX = event.touches[0].clientX; - } - }); - document.addEventListener('touchmove', function(event) { - var x = event.touches[0].clientX; - lastDiff = lastX - x; - lastX = x; - }); - document.addEventListener('touchend', function (event) { - if (lastDiff < -threshold) { - api.prev(); - } else if (lastDiff > threshold) { - api.next(); - } - - lastX = 0; - lastDiff = 0; - - touchCount--; - }); - // rescale presentation when window is resized window.addEventListener("resize", throttle(function () { // force going to active step again, to trigger rescaling api.goto( document.querySelector(".step.active"), 500 ); }, 250), false); - + }, false); })(document, window); From 184565cc7bc4e8118a0c8df3660f543665c25703 Mon Sep 17 00:00:00 2001 From: and3rson Date: Sat, 26 Sep 2015 21:36:54 +0300 Subject: [PATCH 3/4] Removed disabling mobile support. --- js/impress.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/js/impress.js b/js/impress.js index 631325f18..1fb84c4c1 100644 --- a/js/impress.js +++ b/js/impress.js @@ -188,12 +188,7 @@ // and `classList` and `dataset` APIs ( body.classList ) && - ( body.dataset ) && - - // but some mobile devices need to be blacklisted, - // because their CSS 3D support or hardware is not - // good enough to run impress.js properly, sorry... - ( ua.search(/(iphone)|(ipod)/) === -1 ); + ( body.dataset ); if (!impressSupported) { // we can't be sure that `classList` is supported From 09b6bce2125054b8245df33340783afe8fede575 Mon Sep 17 00:00:00 2001 From: and3rson Date: Sun, 27 Sep 2015 11:34:25 +0300 Subject: [PATCH 4/4] Added cancellation of current swipe + decreased threshold. --- js/impress.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/impress.js b/js/impress.js index 1fb84c4c1..d499b8d12 100644 --- a/js/impress.js +++ b/js/impress.js @@ -656,10 +656,10 @@ document.addEventListener('touchend', function (event) { var totalDiff = lastX - startX; - if (Math.abs(totalDiff) > window.innerWidth / 2) { - if (totalDiff > window.innerWidth / 2) { + if (Math.abs(totalDiff) > window.innerWidth / 5 && (totalDiff * lastDX) <= 0) { + if (totalDiff > window.innerWidth / 5 && lastDX <= 0) { prev(); - } else if (totalDiff < -window.innerWidth / 2) { + } else if (totalDiff < -window.innerWidth / 5 && lastDX >= 0) { next(); } } else if (Math.abs(lastDX) > threshold) {