If you have went through Calculus, now could be the time you finally understand limits.

Let’s go over, one by one, what each of the notation above is telling us about sigmoid.

2.1. The first notation tells that as you increase the value of x, which is the parameter you’re passing to sigmoid. The results (return value) of sigmoid approaches almost 1. No matter how big the value of x, the return value will never exceed 1. Or, Limit as x approaches infinity of the function sigmoid is 1. Infinity here, just means a really really large number.

2.2. The second notation, not so different from the first, tells us the return value of sigmoid approaches 0 as you take the input parameter (x) to 0.

2.3. You figure this out yourself.

How is this limiting nature of sigmoid helpful for us? Welp, TODO number 3 said “Limit the amount of rotation (no toppling)”.

So There!

There are many more useful uses you can extract out of this curve, but for our intents and purposes we have milked it just enough.

Next, we’ll quickly go ahead and declare the sigmoid function at the top of our .js file.

// Sigmoid function

var sigmoid = function(x) {

return (x / (1 + Math.abs(x)));

};

And that’s it! Now we can finally get to dynamically rotating the card.

Rotating the card

The first thing we’ll do is create a new variable, rotation .

var rotation = 0;

var update = function() {...

....

Next, inside the update function, we’ll add two new lines of code like so,

var update = function() {

xVelocity = (MousePosition.x - CardPosition.x);



CardPosition.x = MousePosition.x;

CardPosition.y = MousePosition.y;



rotation = sigmoid(xVelocity);



// Update the position of card

card.style.top = CardPosition.y + 'px';

// Subtract (Width of card / 2 = 125) to centre cursor on top

card.style.left = (CardPosition.x - 125) + 'px';



card.style.transform = `rotate(${rotation}deg)`;



requestAnimationFrame(update);

};

The first line in bold calculates and assigns value to the rotation variable. The next one, takes that value and applies it as a CSS transform style to the card.

If you run the code you’ll notice a very, very subtle version of the animation we’re after.

You’re right, it’s as good as invisible. We can amplify this subtle effect by multiplying, let’s say 10 to rotation.

rotation = sigmoid(xVelocity) * 10;

Very jittery, but somewhat there. Let’s take the * 10 out and do something else.

rotation = rotation + sigmoid(xVelocity);

What we’re doing here is trying to remove the jitter by additively applying the the result of sigmoid to rotation.

Here is what the animation looks like now.

This is smooth and everything but still, not there at all. Let’s tweak the code a little more.

When the dragging of card stops we want the card to return to it’s original rotation value of 0, like we described in our TODOs.

Doing that is very straightforward. This is the technique used for basic emulation of friction in game programming. You successively multiply the value you want to damp by a number between 0 and 1.

Here’s how we’ll do it.

rotation = rotation * 0.9 + sigmoid(xVelocity);

The way this works is, when dragging stops, xVelocity becomes 0. Therefore the latter half of the code above, after +, becomes 0, as sigmoid(0) = 0 .

Then effectively our line of code becomes,

rotation = rotation * 0.9;

And remember the update function is still being repeatedly called over and over via requestAnimationFrame . Now on each subsequent call of update the value of rotation starts decreasing by 10%. Let’s say initially the value of rotation is 30, therefore,

// call 1

rotation = 30 * 0.9; // 27 // call 2

rotation = 27 * 0.9; // 24.3 // call 3

rotation = 24.3 * 0.9; // 21.87

....

on repeated calls, the value of rotation keeps decreasing until it hits a 0.

Which. By the way. It’ll never do. It’ll get extremely close to 0, but never exactly 0, can you figure why? This is an interesting paradox called the Zeno’s paradox. You can read more about it if you wish to ;-).

Since it’ll never hit 0, it’s our job to observe when the value gets super close to 0 so we can shut it out by giving it a value of 0 explicitly like so.

if (Math.abs(rotation) < 0.01) rotation = 0;

This is a very small detail and you’d be just fine not including the above line of code. But just for the sake of completeness and correction I’ll leave it there.

And now, we’re done with everything and look how natural dragging the card around feels. Cool! isn’t it?

Feel free to play around with the values that are being multiplied to rotation and sigmoid’s result. They adjust the damping duration and sensitivity of rotation respectively.

rotation = rotation * 0.9 + (sigmoid(xVelocity) * 2);

My motivation behind exploring this was to make dragging cards in Trello feel more natural. I won’t consider this anything more than just an experiment. It would be a pleasure to see how you approach this. I have packaged all the code we wrote above into a Google Chrome extension that injects the animation script into trello.com. It’s available on GitHub. Feel free to collaborate, install or just play around.