Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement google paper button effects

Google’s paper / material design http://www.google.com/design/spec/material-design/introduction.html is a really clean look that I think is going to see a lot of use. Polymer has a bunch of “paper-elements” ready to go and the web community is already playing with different ways to implement it. For this question I’m specifically looking at the button click effect.

It has a ripple of activation color that radiates from your click. Here is polymer’s example: http://www.polymer-project.org/components/paper-elements/demo.html#paper-button , here is a css jquery example: http://thecodeplayer.com/walkthrough/ripple-click-effect-google-material-design

My question is how to go about implementing it?

Taking a look at the polymer example When you mousedown it radiates a background color shift maybe instead of the colored opacity ripple in the other example. It holds when it reaches it’s limit and then on mouseup it quickly fades out.

Since I could easily see the code behind the second example I tried implementing it in a similar fashion as it had but with the exception of using touch events instead of click since I wanted it to hold the effect if all i did was touch but not release.

I tried scaling, transitioning the position setting the opacity but getting the placement and the effect of radiating outwards from the point of touch was beyond me or at least from the time I’ve invested so far. In truth I’m just under experienced in the animation department in general.

Any thoughts on how to implement it?

like image 410
aintnorest Avatar asked Jul 25 '14 00:07

aintnorest


1 Answers

I also wanted this effect, but I've not seen any implementations either. I decided to go with a CSS radial gradient in the button's background-image. I'm centering the ripple (the gradient's circle) at the touch/mouse point. I extended the Surface module in order to hook into the render cycle.

There are two Transitionables, one for the diameter of the gradient and one for gradient opacity. Both of these are reset after the interaction. When the user clicks on a button, the Surface stores the X and Y offset and then transitions the gradient diameter to its max value. When the user releases the button, it transitions the gradient opacity to 0.

The render cycle is constantly setting the background-image to a radial gradient with the circle at the X and Y offset, and getting the opacity and gradient diameter from the two Transitionables.

I can't tell you whether I've implemented the ripple button effect using best practices, but I like the result.

var Surface = require('famous/core/Surface');
var Timer = require('famous/utilities/Timer');
var Transitionable = require('famous/transitions/Transitionable');

// Extend the button surface to tap into .render()
// Probably should include touch events
function ButtonSurface() {
    Surface.apply(this, arguments);

    this.gradientOpacity = new Transitionable(0.1);
    this.gradientSize = new Transitionable(0);
    this.offsetX = 0;
    this.offsetY = 0;

    this.on('mousedown', function (data) {
        this.offsetX = (data.offsetX || data.layerX) + 'px';
        this.offsetY = (data.offsetY || data.layerY) + 'px';

        this.gradientOpacity.set(0.1);
        this.gradientSize.set(0);
        this.gradientSize.set(100, {
            duration: 300,
            curve: 'easeOut'
        });
    }.bind(this));

    this.on('mouseup', function () {
        this.gradientOpacity.set(0, {
            duration: 300,
            curve: 'easeOut'
        });
    });

    this.on('mouseleave', function () {
        this.gradientOpacity.set(0, {
            duration: 300,
            curve: 'easeOut'
        });
    });
}

ButtonSurface.prototype = Object.create(Surface.prototype);
ButtonSurface.prototype.constructor = ButtonSurface;

ButtonSurface.prototype.render = function () {
    var gradientOpacity = this.gradientOpacity.get();
    var gradientSize = this.gradientSize.get();
    var fadeSize = gradientSize * 0.75;

    this.setProperties({
        backgroundImage: 'radial-gradient(circle at ' + this.offsetX + ' ' + this.offsetY + ', rgba(0,0,0,' + gradientOpacity + '), rgba(0,0,0,' + gradientOpacity + ') ' + gradientSize + 'px, rgba(255,255,255,' + gradientOpacity + ') ' + gradientSize + 'px)'
    });

    // return what Surface expects
    return this.id;
};

You can check out my fiddle here.

like image 116
Clay Smith Avatar answered Sep 28 '22 09:09

Clay Smith