How to get translation offset while transitioning - javascript

I have a container that is quite similar to an image slider, and designed for horizontal touch/mouse drag to move between slides. For aesthetics, an easing function is applied so that it glides into place centered on each slide when released. The method of movement is "transform: translateX()".
The problem I'm currently having is that, if the user releases, then touches and and moves it again while it's already in motion, it will jump to the slide at the end of it's transition. So for example: if you are in slide 1, move it and release while it's in the zone for slide 2, and then try to move again while it' still in motion, it will jump to slide 2 immediately, and then move from there to wherever I move my finger.
What I'm essentially looking for is a way to get the intermediate transition distance while the translation animation is running. Is there any way to measure where an element actually is in the middle of transition? If not, what are some solutions for this situation?
EDIT:
I found out the root cause to my issue, although it doesn't change the focus of the question. To give a broader explanation of what was going on, I'll include it here.
The default transition duration time was set to 300ms. When a user drags on the content by mouse or by touch, this was set to 0ms so that it wouldn't lag behind the user's movements. When released, it would be set back to 300ms. If it was grabbed again while it was in motion, it would take the position it was transitioning to and snap there when the duration was set to 0ms. This was better than then alternative of allowing it to continue to flow there while dragging again, as the content would slide under the drag point.

Per the comments on the question post, I assume this means the answer to my first question is: no, you cannot get the intermediate values directly during translation.
As to the second question, the comments mention the option of preventing activity until the animation completes. While this would work, I felt it would also diminish the UX, and so I decided to try something a little different. My solution seems to work quite well as a workaround, and so I decided to answer my own question and post it here for others. I also edited the question with a little more detail.
What I ended up doing was using a timer to predict the position of the intermediate value, so that if interrupted, it would appear to seamlessly stop mid-transition in the correct place.
Doing this required a little math, and the precise formula is dependent on what sort of easing is employed. "Linear" easing is the easiest to predict, but the others are quite doable with a little bit of trigonometry. I used "ease-out", so I'll include my solution for that one in pseudo-code below:
startX + (finishX - startX) * sin((now - startTime) / transitionDuration * PI / 2)
startX is the position the slider was at when released (beginning of transition).
finishX is the position the slider is moving towards (end of transition).
now is the current time in milliseconds.
startTime is the time the slider was at when released (beginning of transition).
transitionDuration is the amount of time the transition takes to complete in milliseconds.
In summary, the above allows you to predict the position of an element during transition. While specifically written for "ease-out", it should be trivial to adapt it to other basic curves.

Related

Translate3d adds extra space at the end of document

I made a smooth scroll on the page using transform translate3d.
But there is a problem. Translate3d adds extra space at the end of the document.
You can see it here: https://codepen.io/anon/pen/WEpLGE
I think that the problem is somewhere here:
if(Math.round(currentY) !== Math.round(destY)){
var newY = Math.round(currentY + ((destY - currentY) * 0.1));
container.css({
transform: 'translate3d(0, -' + newY + 'px, 0)'
});
}
You can see that at the end of the image container, there is an empty space.
How can I solve the problem?
Using transform does not cause the surrounding elements to reflow. Essentially this means the browser isn't rerendering the size of the containing element even though you're moving it with translate3d. The images are staying in their original spot when it comes to influencing the size of the parent container, or where text gets flowed around them but the user sees it moved by the translate.
In short, it's not adding space. That space is the space which the translated element would be taking up if it wasn't moved.
This article explains it in the third paragraph of the "Transform" section.
I'm not exactly sure what you're trying to achieve with the translate. It looks to me like it's some sort of parallax effect? I'd remove the if statement where the transform is added, and see if you're fine with that. You might try position: absolute also. I can explain why it's happening, but without more detail as to what you're trying to achieve it's going to be hard to help with a solution.
Edit:
After looking at the code, it looks like you're going for a smooth scroll effect where the images lag behind the scroll then drift into place. Kind of like scrolling on a cellphone where it drifts to its final position.
This is technically 2 questions in one, "Why is there extra space" and "how do I get this smooth scroll". I recommend you add another question, or edit this one to be more specific to one or the other. But I'll give you a hint as to how I would fix it.
My recommendation would be to change the code, not to add an incrementing offset (which is why you end up with the space at the end). But detect a scroll, add a class which shifts everything up with a css transition then when the scrolling stops remove that class so everything shifts back down.
This would leave everything in its original place on the screen when they stop scrolling instead of leaving it offset as it is now.
If you confirm this I'll give you some example code, not going to take the time on an assumption though.

Measure swipe distance

This question has been probably asked many times but I can't actually find the answer nor here nor on Google. Probably I'm searching it with wrong words, so I decided to ask here on StackOverflow.
I'm using Hammer.js to handle the mobile gestures on the current website and what I'd like to do now is moving the divs horizontally as much as the thumb moves (like the Facebook's app gallery, for example).
I thought I can achieve it getting the coordinates X,Y of the point where the swipe event is recognized and then animate the move between the current viewport and the next "overflow hidden" div. What I'm missing is: which is the event listener that would listen at every thumb move so that I can calculate the distance in pixel between the current point and the starting point, automatically updating the value for the animate function?
the event you are looking for is touchmove

Creating scrolling images with prototype and script.aculo.us

I am trying to animate images of clouds on my website to slowly move through my header, as on http://toriseye.quodis.com/ using prototype and script.aculo.us. I can't get the effect right as it is too fast, appears to rise towards the end, isn't smooth and it won't repeat after the first run. For some reason I can't post the jsfiddle.net link in the question box, so see my comment below :)
Firstly use transition: Effect.Transitions.linear as that will make it smooth
plus you are running the interval at 1 second (1000 milliseconds) but telling the Move Effect to last for 5 seconds - this will confuse the heck out of the javascript
Then you need to reset the position of the element you are moving - use the afterFinish callback to do so
I'm not sure the exact reason it is rising - but if you use the relative mode and just use an x parameter it does not rise
take a look at my edits to your fiddle
http://jsfiddle.net/nukt2/4/
I'm assuming your goal is multiple clouds - I would look at the Parallel Effects option so they are all running on the same timer
http://madrobby.github.io/scriptaculous/effect-parallel/

Pause and Resuming a JQuery.animated object

I'm having trouble in trying to pause and resume a JQuery.animated object, it pauses fine but once it resumes animation it resets the animation from its current position so it ends up moving past the spot where it was meant to stop.
Heres a jsFiddle: jsFiddle to help explain it better.
Thanks for you help.
Is this what you were trying to achieve?
I was just using the suggestions from #DarthJDG, also added the element's height so it doesn't go below the window border.
http://jsfiddle.net/HemUe/2/
The problem is that you're using relative animation targets. As far as I can tell, the plugin only takes the time elapsed into account when restarting the animation, the properties remain the same.
So if you start a linear animation for 5 seconds to move an element +100px and pause the animation after 2 seconds, it has already moved 40px. When the animation resumes, it will start an animation to move +100px for 3 seconds, and the element ends up moving 140px in total.
The solution is to use absolute values when calling $box.animate(), converting relative values to absolute there and then if necessary. Instead of moving "+="+windowHeight, set it to $box.position().top + windowHeight.
You might want to report this bug/limitation to the plugin's developer, but as the plugin's version is only 0.1, he might be well aware.

jQuery smooth mouse tracking

I have my object tracking the mouse using the onmousemove event. But I would like to make it smooth. I'm sure this can't be difficult in jQuery but I'm not finding any really good resources.
One idea I had was to simply use the animate function and calculating the offsets that I want to move to. Then if the mouse moves again before the animation is complete, I would use the stop function to stop the animation. I would recalculate my destination and away I go again. This seems a little hack-ish and I also imagine that it will be a little jerky. I'm sure there has to be a better way. Any Ideas?
EDIT
Sorry I didn't make my problem very clear. I have the object tracking the mouse in real time, so that it moves exactly the same as my mouse. The problem is that I want it to be smooth and lag behind with acceleration effects like Andy Lin mentioned below. I'm just a little lost how to actually implement this.
I am afraid, that there is no better way, than animate. If you add a smoothing function, then you would simply do the same thing that animate does. Be sure, not to queue your animations or they will look weird. I got nice results with this:
var obj = $('<div style="width:50px;height:50px;background:red;position:absolute"></div>');
obj.appendTo(document.body);
$(document).bind('mousemove',function(ev){
obj.animate({top:ev.pageY,left:ev.pageX},{queue:false,duration:200,easing:'linear'})});
when you are using onmousemove, you do not need to have the object change its behavior with every invocation.
e.g. you can add a timer to say that within period of time, the object will not response to mousemove and will follow its original path, and upon timeout or mouse move stop, move according to the destination.
also, you can simulate an acceleration and slow down effect with animation settings.

Categories

Resources