Ads

Sunday 29 June 2014

Creating Jelly Navigation Menu for Touch Devices

Download   Demo


First Step: Changing The Section Shape


Our first aim is to change the menu section shape by manipulating the curves. Every object is made up of anchor points. These points are connected with each other by curves. So each point has “In” and “Out” handles to define the location and direction of specific curves. Folks who work with vector editors should feel comfortable with this step.


All we need to do is to change the handleOut position of the top-left andbottom-right points. To achieve this, I wrote simple so-called “toppie” and “bottie” functions:


toppie:(amount)->
@base.segments[1].handleOut.y = amount
@base.segments[1].handleOut.x = (@wh/2)

bottie:(amount)->
@base.segments[3].handleOut.y = amount
@base.segments[3].handleOut.x = - @wh/2

# @wh/2 is section center.
# @base variable holds section's rectangle path.

It’s important to set the handle’s X position to exactly the middle of the section, so that the curve will turn out to be symmetrical.


Second Step: Calculating The Scrolling Speed


So the next thing that needs to be done is to calculate the scrolling speed and direction, and then pass this data to the bottie and toppie functions. We can listen to the container’s scrolling event and determine the current scrolling position (in my case the “container” is a #wrapper element whereas it is a window object in the pen examples).


# get current scroll value
window.PaperSections.next = window.PaperSections.$container.scrollTop()

# and calculate the difference with previous scroll position
window.PaperSections.scrollSpeed = (window.PaperSections.next - window.PaperSections.prev)

# to make it all work, all we have left to do is to save current scroll position to prev variable
window.PaperSections.prev = window.PaperSections.next

This is repeated for every scrolling event. In this code snippet,window.PaperSections is just a global variable. I also made a few minor additions in my implementation:


  • A silly coefficient to increase scroll speed by multiplying it by 1.2 (just played around with it),

  • I sliced the scroll speed result by its maximum so that it is not larger thansectionHeight/2,

  • I also added a direction coefficient (it could be 1 or -1, you can change it in dat.gui on the top right of the page). This way you can control the reaction direction of sections.

Here is the final code:


if window.PaperSections.i % 4 is 0
direction = if window.PaperSections.invertScroll then -1 else 1
window.PaperSections.next = window.PaperSections.$container.scrollTop()
window.PaperSections.scrollSpeed = direction*window.PaperSections.slice 1.2*(window.PaperSections.next - window.PaperSections.prev), window.PaperSections.data.sectionheight/2
window.PaperSections.prev = window.PaperSections.next
window.PaperSections.i++

In this example, if window.PaperSections.i % 4 is 0 helps us react on every fourth scroll event — similar to a filter. That function lives inwindow.PaperSections.scrollControl.


That’s it! We’re almost done! It couldn’t be any easier, right? Try out the scrolling here.


See Demo #2


Step Three: Make It Jelly!


In this final step, we need to animate the toppie and bottie functions to 0with TweenJS’ elastic easing everytime the scrolling stops.


3.1 DETERMINE WHEN SCROLLING STOPS


To do this, let’s add the setTimeout function to ourwindow.PaperSections.scrollControl function (or scroll) with 50ms delay. Each time when the scrolling event fires up, the Timeout is cleared except for the last one, i.e. once scrolling stops, the code in our timeout will execute.


clearTimeout window.PaperSections.timeOut
window.PaperSections.timeOut = setTimeout ->
window.PaperSections.$container.trigger 'stopScroll'
window.PaperSections.i = 0
window.PaperSections.prev = window.PaperSections.$container.scrollTop()
, 50

The main focus here is the window.PaperSections.$container.trigger stopScrollevent. We can subscribe to it and launch the animation appropriately. The other two lines of code are simply being used to reset helper variables for laterscrollSpeed calculations.


See Demo #3


3.2 ANIMATE POINT’S HANDLEOUT TO “0”


Next, we’ll write the translatePointY function to bring our jelly animation to life. This function will take the object as a parameter with the following key-value sets:



// point to move (our handleOut point)
point: @base.segments[1].handleOut,

// destination point
to: 0,

// duration of animation
duration: duration

The function body is made up of the following:


translatePointY:(o)->
# create new tween(from point position) to (options.to position, with duration)
mTW = new TWEEN.Tween(new Point(o.point)).to(new Point(o.to), o.duration)

# set easing to Elastic Out
mTW.easing TWEEN.Easing.Elastic.Out

# on each update set point's Y to current animation point
mTW.onUpdate ->
o.point.y = @y

# finally start the tween
mTW.start()

The TWEEN.update() function also has to be added to every frame of the PaperJS animation loop:


onFrame = ->
TWEEN.update()

Also, we need to stop all animations on scrolling. I added the following line to the scroll listener function:


TWEEN.removeAll()

Finally, we need to subscribe to the stopScroll event and launch the animations by calling our translatePointY function:


window.PaperSections.$container.on 'stopScroll', =>
# calculate animation duration
duration = window.PaperSections.slice(Math.abs(window.PaperSections.scrollSpeed*25), 1400) or 3000

# launch animation for top left point
@translatePointY(
point: @base.segments[1].handleOut
to: 0
duration: duration
).then =>
# clear scroll speed variable after animation has finished
# without it section will jump a little when new scroll event fires
window.PaperSections.scrollSpeed = 0

# launch animation for bottom right point
@translatePointY
point: @base.segments[3].handleOut
to: 0
duration: duration

In Conclusion


Last but not least, a class for the sections has to be added. Of course, you can make as many instances of it as you like; you just need to define initial Y offset and colors. Also, you will need to make sure that the section in your layout has the same height as the section in canvas. Then we can just apply translated3dto both on the scroll event and animations. This will cause HTML sections to move properly, just like the canvas sections, and hence produce a realistic animation.



Creating Jelly Navigation Menu for Touch Devices

No comments:

Post a Comment