In the previous article We learned how to animate the non-interactive part of this animation From Lukas Kus using GSAP Timeline. Now in order to completely replicate what was done on the dibbble it would be cool to simulate the user dragging on what we did previously to reveal an image, and that's exactly what we're doing today.
Again, here's the end result.
Setting up the background image
We'll need to carefully set up the background image behind the main circle, this will depend heavily on how you first positioned your SVG on the canvas. On the example above it's done by wrapping everything on the same div
and absolutely positioning it using thetop
and left
css properties. You can see it on line 58 of the css tab.
I used Lorem Picsum to fetch a different image of the height I wanted everytime to get a nicer result as well.
The draggable interaction
In order to make the image move and then fade away after reaching certain threshold I'll be using a GSAP Draggable
which simplifies the process of making any DOM element Draggable.
First of all, let's arrange our SVG in a way we could move all elements we want to be movable at the same time, as currently the Draggable
plugin does not support moving non-nested elements at the same time natively.
To do so, I added a <g>
to surround the fill part of the main circle and the small orange dot that remains. See HTML line 7.
After that we need to create the actual function that makes the element Draggable. It's done on line 84, let's go over the main parts of it.
const dg = Draggable.create("#movable", {
type: "x, y",
edgeResistance: "0.8",
bounds: ".inner-circle",
inertia: true
})[0];
The Draggable.create
function targets everything inside the tag with id #movable
.
The type
parameter defines the axis we want to move on, in our case we want to freely move around so we use both x,y
.
edgeResistance
is a value between 0 and 1 that defines how much does the image can go outside the boundaries and the 'strength' the boundaries apply to bring the main item back.
bounds
is the query of an element that should contain the element we provided when creating the draggable. It's important that the element is bigger than the draggable, and that it contains it at least visually so we can actually see our animation. In this case is the inner circle we draw with the animation.
inertia
gives a sense of smoothness to our draggable when manipulating it with the dom.
const el = dg.addEventListener("drag", (e) => {
if (shouldOpen(dg) && isActive) {
closingTl.play();
isActive = false;
}
});
To make the background image appear after we pass a certain treshold we should track whether the draggable element moved the way we wanted, so we listen whenever the element is dragged and check if the position is inside the boundarieswe difine within shouldOpen
.
function shouldOpen(dg) {
const threshold = 25;
const isOutOfXBoundaries =
dg.x < dg.minX - threshold || dg.x > dg.maxX + threshold;
const isOutOfYBoundaries =
dg.y < dg.minY - threshold || dg.y > dg.maxY + threshold;
return isOutOfXBoundaries || isOutOfYBoundaries;
}
The shouldOpen function simply receives a draggable event and checks if it's within a range i arbitrarily designed, not too much to see here.
If the image is outside the range we defined then we trigger a new animation that fades out the SVG and brings up the image itself. And we're done!
The point where it all connects it's on line 9 where we define
const tl = new TimelineMax({ repeat: 0, onComplete: addDraggable });
We're using the addDragable function only after the animation completes, since we don't want the user to be able to move the animation while it's still playing.
It may look like a lot of code and orchestration at firts, but just think of how much more complex it would have been using plain css animations and js. Also, by tweaking some values you could make the animation play backwards, or replay it on demand as I've done on the code example.
If you liked this post, make sure to leave a like and follow me on DEV.TO and twitter as @stiv_ml
Top comments (0)