Here it is, another post where I take some cool native UI and reproduce using only HTML5 technologies. The first one was the Facebook Login page. The result was a pixel perfect UI, just as nice as the native one. Now I’m taking the Path animated menu!
For those who don’t know Path, it’s a social network for connecting with family and close friends, available for iOS and Android. It has very interesting features, but the thing that really caught my attention was their “fan-out animated menu”. When you tap the menu, the options fan out, with a nice circular animation. It’s so cool that I had to take this UI and port it. I translated <divs> to Ext.Buttons, created the CSS3 animation and calculations, so everything works properly with Touch components.
This is the result below! You need to use a WebKit Browser in order to see it (Smartphone browsers, Google Chrome or Safari).
*Touch compatibility webkit only- Live Example: http://brunotavares.github.com/SenchaExamples/touch/native-to-web-path-menu/
- Source code: http://github.com/brunotavares/SenchaExamples/
Animation
Inside the path menu container I have one main button, and other small ones. They all are absolute positioned, and stacked together. So the main button actually covers the small ones, having a z-index: 2. When this button is tapped, either fanOut or fanIn methods are triggered. Those methods iterate over each item, animating them with methods fanOutItem or fanInItem.
The fanInItem is easy. We just have to take the items and translate to the origin, which is 0,0. The tricky method is fanOutItem. There is a couple of math involved for calculating the X,Y position of the item on top of the arch line. You can check all those methods below:
onPathBtnTap: function(btn) { var pressedCls = Ext.baseCSSPrefix + 'button-pressed'; btn.pressed = !btn.pressed; if (btn.pressed) { btn.addCls(pressedCls); this.fanOut(); } else { btn.removeCls(pressedCls); this.fanIn(); } }, fanOut: function() { this.getComponent(0).items.each(this.fanOutItem, this); }, fanIn: function() { this.getComponent(0).items.each(this.fanInItem, this); }, //@private fanOutItem: function(item, index, len) { var angle, rad, sin, cos, x, y, style, difCenter, arc = 90, distance= 150; //ignore main button if (index === 0) { return; } index--; len--; //calculate angle using items count if (len === 1) { angle = 0; } else { angle = (arc/(len-1)) * index; } //transform angle to rad rad = angle * Math.PI/180; //calculate cos and sin cos = Math.cos(rad); sin = Math.sin(rad); //find x,y using distance x = Math.ceil(distance * cos); y = Math.ceil(distance * sin * -1); style = { '-webkit-transition-delay': (30 * index) + 'ms', '-webkit-transform': 'translate3d('+x+'px, '+y+'px, 0)' }; if (!item.rendered) { item.style = style; } else { item.element.applyStyles(style); } }, //@private fanInItem: function(item, index, len) { //ignore main button if (index === 0) { return; } var style = { '-webkit-transition-delay': (30 * index) + 'ms', '-webkit-transform': 'translate3d(0px, 0px, 0)' }; if (!item.rendered) { item.style = style; } else { item.element.applyStyles(style); } }
Theming
I’m just using a couple gradients and box-shadows. Since I don’t want to change the HTML structure of the component itself, I had to use CSS pseudo elements :before and :after.
The :before was used for the outer gray and white box-shadows. They are not borders, but 2 box-shadows. The :after was used for the pressed state, putting a black mask on top of the button.
Wrapping Up
Currently everything is very hard coded, and my next task is make this more extensible, allowing other developers to take this animation and plug to any other containers. Also allow customizations, like change the arch degree and items distance to origin.
Hey, if you found this interesting don’t forget to tweet and share it with others :) I’m always looking for new cool UIs to reproduce with HTML5.
David Marsland liked this on Facebook.
Servidor es paitdiarro del melee, lo disfruto mucho mas que el braw. Lo que no quita que opine que la OST del brawl es la cosa mas bruta que ha salido en un videojuego y que los que juegan sin objetos en cualquiera de ellos son unos rancios
Great job Bruno! Smooth, pleasant to look at :)