Reputation: 785
I am trying to create a sort of plugin or event that css transitions (moves) elements via swipe on ipad. For this I am using so far the brillant working little code snippet of cocco:
(function(D){
var M=Math,abs=M.abs,max=M.max,
ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
f={
touchstart:function(e){
t=e.touches[0];
sx=t.pageX;
sy=t.pageY
},
touchmove:function(e){
m=1;
t=e.touches[0];
ex=t.pageX;
ey=t.pageY
},
touchend:function(e){
ce=D.createEvent("CustomEvent");
ce.initCustomEvent(m?(
max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
):'fc',true,true,e.target);
e.target.dispatchEvent(ce);
m=0
},
touchcancel:function(e){
m=0
}
}
for(l in f)D.addEventListener(l,f[l],false)
})(document);
For the transitions rico st.cruz’ plugin jquery-transit.js is implemented on my site (and jquery of course)
// usage (example)
$("body").on( 'swu', function() {
fullscreenSwipeUp = true;
$("#Fullscreen").transition( { y: '-100%' }, 900, 'easeInSine' )
} );
So far so good. Now my idea was to indicate the possible „swipe up“ with an additional touch move event that moves the element along while the finger tap is going on. And I succeeded in doing so adding the following js:
// js parts to integrate in a cooler way
var startY;
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
}, false );
window.addEventListener( 'touchmove', function(e) {
e.preventDefault();
// check if transition is going on and animations are ready
if ( !fullscreenSwipeUp ) { // find better solution f.e. to dispatch event on fullscreen transition?
var diffY = e.changedTouches[0].pageY - startY;
// fullscreen transition
if ( diffY <= 0 ) {
$("#Fullscreen").css( { y: diffY } );
} else {
// snap to clean starting value at bottom
$("#Fullscreen").css( { y: 0 } );
};
// do something else to indicate that swipe will be concluded when finger leaves
// min value based on variable th from custom swipe event
if ( diffY < -20 ) {
// indicate that swipe will be concluded
} else {
// indicate that swipe will not conclude
};
};
}, false );
// fullscreen fall back to bottom if swipe not concluded
window.addEventListener( 'touchend', function(e) {
e.preventDefault();
if ( !fullscreenSwipeUp ) {
// fall back to starting values / dequeue for smoother transition on second time
$("#Fullscreen").dequeue().transition( { y: 0 }, 150, 'easeInSine' );
};
}, false );
Now I see also that in this code various parts overlap each other as the double touch move event from the base custom event and my stuff. It would be so awesome if someone could offer me an idea of how to integrate the two codes. Or maybe something likes this exists? I couldn’t find the right thing.
Thanks for a helping hand!
PS I tried to create a fiddle, also, here: http://jsfiddle.net/Garavani/9zosg3bx/1/ but sadly I am too stupid to make it work with all the external scripts :-(
jquery-transit.js: http://ricostacruz.com/jquery.transit/
EDIT:
So I changed my code in the following way. I guess I was confused between the original swipe event (which incorporates the touch move event also) and what I wanted to do with the element. It works although probably still a mess. I had to set kind of flag to check if the swipe is executed to disable the touch move event temporarily. Is there a better way to do that? Thanks for your patience!
var startY;
var swipeY = false; // for condition if condition for swipe is fullfilled
var swiped = false; // for check if swipe has been executed
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
}, false );
window.addEventListener( 'touchmove', function(e) {
e.preventDefault();
// check if swipe already executed
if ( !swiped ) { // find better solution f.e. to dispatch event when swiped?
var diffY = e.changedTouches[0].pageY - startY;
// check for final swipe condition
if ( diffY < -30 ) {
swipeY = true;
// do something with an element to indicate swipe will be executed
} else {
swipeY = false;
// do something with an element to indicate swipe will NOT be executed
};
};
}, false );
window.addEventListener( 'touchend', function(e) {
e.preventDefault();
if ( swipeY ) {
swiped = true;
// trigger the swipe action
} else {
// let the element fall back to original state
};
}, false );
EDIT 2:
var startY;
var swipeY = false;
var swiped = false;
var wh = $(window).height();
// fullscreen move on touchmove
function fm(e) {
e.preventDefault();
// check if transition is going on and animations are ready
if ( !swiped && ready ) { // !swiped is necessary, also / why?
var diffY = e.changedTouches[0].pageY - startY;
var scaleY = diffY/wh;
// calculate transition intermediate values
var osh = 0.91 - ( 0.09 * scaleY );
var ofsc = 0.86 - ( 0.14 * scaleY );
// fullscreen transition
if ( diffY <= 0 ) {
tfs(osh,[1,-scaleY],ofsc,diffY,0) // an extra module that does the animation with the calculated values
} else {
// snap to clean starting values at bottom
tfs(0.91,[1,0],0.86,0,0)
};
// rotate arrow to indicate surpassing minimum touch move leading to swipe
if ( diffY < -30 ) {
swipeY = true;
$arrowDown.addClass('rotation');
} else {
swipeY = false;
$arrowDown.removeClass('rotation');
};
};
};
// fullscreen swipe
function fs(e) {
e.preventDefault();
window.removeEventListener( 'touchmove', fm, false );
if ( !swiped ) { // this is necessary, also / why?
if ( swipeY ) {
$arrowbottomField.trigger('touchstart'); // trigger the full swipe (also available as element direct touch (on touch swiped is set to true in touchstart event handler, also)
window.removeEventListener( 'touchend', fs, false );
} else {
// fall back of animation to starting values
tfs(0.91,[1,0],0.86,0,0);
};
};
};
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
window.addEventListener( 'touchmove', fm, false );
}, false );
window.addEventListener( 'touchend', fs, false );
Explanation (as good as I can) Thanks Cocco for your patience again. In the meantime I modified the code again. It works :-) I know it will be a mess in your eyes.
On my site (supposed to work also on ipad, but not only) there is a field where you can touch and a fullscreen is moving up covering the whole window (similar to www.chanel.com -> „more“). Additionally it is (on ipad) possible to swipe on the whole body to do the same thing.
Phases:
Phase 1) User taps and swipes (keeping the finger on) The fullscreen div follows his finger.
Pause 2) If a certain distance of the swipe is reached (still with the finger on) a little arrow also turns to indicate: if you leave now, swipe will be executed
Pause 3) still with finger on the distance becomes less than the one to complete the swipe, the arrow turns back
Phase 4) Leave with the finger the distance already covered decides if the fullscreen will move up completely or fall back down (if distance not sufficient)
For the little arrow to turn I could use a class toggle as you told me (way better than what I did! Thanks) but for the rest of the animation not because the values strongly depend on the window size. And the idea of my whole site is that the browser window can have any sizes or relations, all contents adapt themselves (containing horizontal AND vertical centerings at any time)
For mobile phones everything changes completely.
If you want to take a look: www.stefanseifert.com (if you want to see the effect (on ipad) you will have to skip the intro by touching the arrow in the right corner on the bottom of the trailer div)
I know that there is tons of other stuff that is note state of the art programming (to say this very carefully :-) but in a way it works. And I can not afford to hire a programmer for weeks to redo everything. ;-) It’s kind of learning by doing (for as you can guess I never programmed before in my life ;-) so I am very thankful for every bit of information and help to do little things better.
If someone will pass here I will get some down votes for sure :-) Thanks Cocco Merry Christmas!
Upvotes: 2
Views: 5323
Reputation: 16706
The code is actually made for low cpu devices , high performance .. leaving out complex calculations inside the touchmove. Anyway to animate your elements (between touchstart & touchend) a simple solution is to use css (not jquery or other resourceintensive plugins).
then just think logically... you can't determine in wich direction you swipe at the touchstart... you can do that at the touchend event after doing some math. OR while touchmove wich destroys the whole code, as mentioned above.
OPTION 1 (simple & high performance)
DEMO
Add some lines....
(function(D){
var M=Math,abs=M.abs,max=M.max,
ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
T, //<- THE TARGET
f={
touchstart:function(e){
t=e.touches[0];
sx=t.pageX;
sy=t.pageY;
T=e.target; T.classList.add('sw'); //<- ADD A CUSTOM CLASS FOR SWIPES
},
touchmove:function(e){
m=1;
t=e.touches[0];
ex=t.pageX;
ey=t.pageY
},
touchend:function(e){
ce=D.createEvent("CustomEvent");
ce.initCustomEvent(m?(
max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
):'fc',true,true,e.target);
e.target.dispatchEvent(ce);
m=0;
T.classList.remove('sw'); //<- REMOVE THE CLASS
},
touchcancel:function(e){
m=0
}
}
for(l in f)D.addEventListener(l,f[l],false)
})(document);
now define the css class
element.sw{
background-color:yellow;
}
use the proper (HW) animation for mobile devices on your element
element{
background-color:green;
-webkit-transition:background-color 200ms ease;
}
this is a simple and dirty solution , it works. just keep it simple.
the class will apply only on defined elements. ;)
OPTION 2
forget the code above...
Here is another "performant" way to do a "snap" animation using "bounce".
the code is a little more complex... and uses the mouse.. replace the mouse events with touch events.
and with more data points
http://jsfiddle.net/xgkbjwxb/1/
note: don't use jquery or complex js plugins in mobile devices.
Extra
As it's really problematic to work on pc without a touch interface i added some lines that force the mouse to simulate touches based on my function requisites.
EDIT
this code should do what you want...
http://jsfiddle.net/xgkbjwxb/3/
Upvotes: 3