How to implement google paper button effects

Paper / Material Design http://www.google.com/design/spec/material-design/introduction.html is a really clean look that I think will be very helpful. The polymer has a bunch of “paper elements” ready to go, and the web community is already playing in a variety of ways to implement it. For this question, Im specifically considers the effect of clicking a button.

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

My question is: how to implement this?

Take a look at the polymer example. When you're in mousedown, it emits a background color shift, perhaps instead of the ripple color opacity in another example. He holds on when he reaches his limit, and then quickly disappears on the mouse.

Since I could easily see the code of the second example, I tried to implement it the same way it did, but with the exception of using touch events instead of clicking, because I wanted it to hold the effect if all I did was touch but not release .

I tried scaling by moving the position that sets the opacity, but getting the placement and the radiation effect from the point of contact was higher than me, or at least from the moment I invested so far. In truth, I'm only experienced in the animation department in general.

Any thoughts on how to implement it?

+4
3

, . CSS . ( ) /. Surface, .

: . reset . , Surface X Y, . , 0.

X Y .

, , .

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;
};

.

+4

Clay Awesome work love your version , , .

define(function(require, exports, module) {

var Engine          = require('famous/core/Engine');
var Surface          = require('famous/core/Surface');
var Modifier         = require('famous/core/Modifier');
var StateModifier = require('famous/modifiers/StateModifier');
var Transform        = require('famous/core/Transform');
var View             = require('famous/core/View');
var Transitionable = require('famous/transitions/Transitionable');
var ImageSurface     = require("famous/surfaces/ImageSurface");
var OptionsManager = require('famous/core/OptionsManager');
var ContainerSurface = require("famous/surfaces/ContainerSurface");
var EventHandler = require('famous/core/EventHandler');
var RenderNode  = require('famous/core/RenderNode');
var Draggable   = require('famous/modifiers/Draggable');
var Easing      = require('famous/transitions/Easing');

function PaperButton(options) {
    View.apply(this, arguments);

    this.options = Object.create(PaperButton.DEFAULT_OPTIONS);
    this.optionsManager = new OptionsManager(this.options);
    if (options) this.optionsManager.patch(options);

    this.rootModifier = new StateModifier({
        size:this.options.size
    });

    this.mainNode = this.add(this.rootModifier);

    this._eventOutput = new EventHandler();
    EventHandler.setOutputHandler(this, this._eventOutput);

    _createControls.call(this);
    this.refresh();
};

PaperButton.prototype = Object.create(View.prototype);
PaperButton.prototype.constructor = PaperButton;

PaperButton.prototype.refresh = function() {
    var _inactiveBackground = 'grey';
    var _activeBackground = this.options.backgroundColor + '0.8)';
    this.surfaceSync.setProperties({boxShadow:_makeBoxShadow(this.options.enabled ? _droppedShadow : _noShadow)});
    this.surfaceSync.setProperties({background:_setBackground(this.options.enabled ? _activeBackground: _inactiveBackground)});
};

PaperButton.prototype.getEnabled = function() {
    return this.options.enabled;
};

PaperButton.prototype.setEnabled = function(enabled) {
    if(enabled == this.options.enabled) { return; }
    this.options.enabled = enabled;
    this.refresh();
};

PaperButton.DEFAULT_OPTIONS = {
    size:[269,50],//size of the button
    content:'Button',//button text
    backgroundColor:'rgba(68, 135, 250,',//rgba values only, cliped after the third values comma
    color:'white',//text color
    fontSize:'21px',
    enabled: true,
};

var _width = window.innerWidth; 
var _height = window.innerHeight;

var _noShadow = [0,0,0,0,0];
var _droppedShadow = [0,2,8,0,0.8];
var _liftedShadow = [0,5,15,0,0.8];
var _compareShadows = function(left, right) {
    var i = left.length;
    while(i>0) {
        if(left[i]!=right[i--]){ 
            return false;
        }
    }
    return true;
};

var _boxShadow = ['', 'px ', '', 'px ', '', 'px ', '', 'px rgba(0,0,0,', '', ')'];
var _makeBoxShadow = function(data) {
    _boxShadow[0] = data[0];
    _boxShadow[2] = data[1];
    _boxShadow[4] = data[2];
    _boxShadow[6] = data[3];
    _boxShadow[8] = data[4];
    return _boxShadow.join('');
};
var _setBackground = function(data) {
    return data;
};

var _animateShadow = function(initial, target, transition, comparer, callback) {
    var _initial = initial;
    var _target = target;
    var _transition = transition;
    var _current = initial;
    var _transitionable = new Transitionable(_current);
    var _handler;
    var _prerender = function(goal) {
        return function() {
            _current = _transitionable.get();
            callback(_current);
            if (comparer(_current, goal)) {
            //if (_current == _target || _current == _initial) {
                Engine.removeListener('prerender', _handler);
            }
        };
    };
    return {
        play: function() {
            // 
            //if(!this.options.enabled) { return; }
            _transitionable.halt();
            _transitionable.set(_target, _transition);
            _handler = _prerender(_target);
            Engine.on('prerender', _handler);
        },
        rewind: function() {
            //
            //if(!this.options.enabled) { return; }
            _transitionable.halt();
            _transitionable.set(_initial, _transition);
            _handler = _prerender(_initial);
            Engine.on('prerender', _handler);
        },
    }
}

function _createControls() {
    var self = this;

    var _container = new ContainerSurface({
        size:self.options.size,
        properties:{
            overflow:'hidden'
        }
    });
    this.mainNode.add(_container);

    var clicked = new Surface({
        size:[200,200],
        properties:{
            background:'blue',
            borderRadius:'200px',
            display:'none'
        }
    });
    clicked.mod = new StateModifier({
        origin:[0.5,0.5]
    });
    _container.add(clicked.mod).add(clicked);

    this.surfaceSync = new Surface({
        size:self.options.size,
        content:self.options.content,
        properties:{
            lineHeight:self.options.size[1] + 'px',
            textAlign:'center',
            fontWeight:'600',
            background:self.options.backgroundColor + '0.8)',
            color:self.options.color,
            fontSize:self.options.fontSize,
        }
    });
    this.mainNode.add(this.surfaceSync);
    this.surfaceSync.on('touchstart', touchEffect);
    this.surfaceSync.on('touchend', endTouchEffect);
    clicked.mod.setTransform(
            Transform.scale(-1, -1, -1),
            { duration : 0, curve: Easing.outBack }
        );


    var animator = _animateShadow(_droppedShadow, _liftedShadow, { duration : 500, curve: Easing.outBack }, _compareShadows, function(data) {
        if(!this.options.enabled) { return; }
        this.surfaceSync.setProperties({boxShadow:_makeBoxShadow(data)});
    }.bind(this));


    function touchEffect(e){
        var temp = e.target.getBoundingClientRect();
        var size = this.getSize();

        var offsetY = e.changedTouches[0].pageY - (temp.bottom - (size[1] / 2));
        var offsetX = e.changedTouches[0].pageX - (temp.right - (size[0] / 2));

        clicked.setProperties({left:offsetX+'px',top: offsetY+'px',display:'block'});

        var shadowTransitionable = new Transitionable([0,2,8,-1,0.65]);
        clicked.mod.setTransform(
            Transform.scale(2, 2, 2),
            { duration : 350, curve: Easing.outBack }
        );
        animator.play();
    };
    function endTouchEffect(){
        clicked.mod.setTransform(
            Transform.scale(-1, -1, -1),
            { duration : 300, curve: Easing.outBack }
        );
        clicked.setProperties({display:'none'});
        animator.rewind();
    };

};
module.exports = PaperButton;
});
+1

Clay Smith .

ButtonSuface Phonegap/Cordova. .

define(function(require, exports, module) {
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);
    this.gradientSize = new Transitionable(0);
    this.offsetX = 0;
    this.offsetY = 0;

    this.on('touchstart', function (data) {
        this.offsetX = (data.targetTouches[0].clientX - this._element.getBoundingClientRect().left) + 'px';
        this.offsetY = (data.targetTouches[0].clientY - this._element.getBoundingClientRect().top) + 'px';

        this.gradientOpacity.set(0.2);
        this.gradientSize.set(0);
        this.gradientSize.set(100, {
            duration: 250,
            curve: 'easeOut'
        });
    });

    this.on('touchend', function (data) {
        this.gradientOpacity.set(0, {
            duration: 250,
            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;
};

module.exports= ButtonSurface;
});
0

All Articles