This commit is contained in:
Max Lynch
2015-07-19 20:52:58 -05:00
parent b515a46d30
commit 602e9d872f
3 changed files with 177 additions and 2 deletions

View File

@ -27,12 +27,15 @@ $button-fab-size: 56px;
button,
[button] {
position: relative;
display: inline-flex;
flex-shrink: 0;
flex-flow: row nowrap;
align-items: center;
justify-content: center;
will-change: transform;
margin: $button-margin;
line-height: 1;

View File

@ -20,7 +20,7 @@ $ripple-animation-curve: cubic-bezier(0, 0, 0.2, 1) !default;
width: 50px;
overflow: hidden;
&.is-animating {
&.md-ripple-animating {
transition: transform 0.3s $ripple-animation-curve;
width: 0.3s $ripple-animation-curve;
height: 0.3s $ripple-animation-curve;

View File

@ -1,3 +1,9 @@
/**
* Portions lovingly adapted from Material Design Lite
* Copyright Google, 2015, Licensed under the Apache 2 license.
* https://github.com/google/material-design-lite
*/
import {Directive, ElementRef} from 'angular2/angular2';
@Directive({
@ -9,9 +15,175 @@ import {Directive, ElementRef} from 'angular2/angular2';
export class MaterialRipple {
constructor(elementRef: ElementRef) {
this.elementRef = elementRef;
this.element = this.elementRef.nativeElement;
console.log('Ripple', elementRef);
var rippleContainer = document.createElement('span');
rippleContainer.classList.add('md-ripple-container');
this.rippleElement = document.createElement('span');
this.rippleElement.classList.add('md-ripple');
rippleContainer.appendChild(this.rippleElement);
this.recentering = false;//this.element.classList.contains(this.CssClasses_.RIPPLE_CENTER);
this.INITIAL_SCALE = 'scale(0.0001, 0.0001)';
this.INITIAL_SIZE = '1px';
this.INITIAL_OPACITY = '0.4';
this.FINAL_OPACITY = '0';
this.FINAL_SCALE = '';
//this.boundRippleBlurHandler = this.blurHandler.bind(this);
//this.rippleElement_.addEventListener('mouseup', this.boundRippleBlurHandler);
this.elementRef.nativeElement.appendChild(rippleContainer);
this._initRipple();
}
elementClicked(event) {
_initRipple() {
this.frameCount = 0;
this.rippleSize = 0;
this.x = 0;
this.y = 0;
// Touch start produces a compat mouse down event, which would cause a
// second ripples. To avoid that, we use this property to ignore the first
// mouse down after a touch start.
this.ignoringMouseDown = false;
this.boundDownHandler = this.downHandler.bind(this);
this.element.addEventListener('mousedown', this.boundDownHandler);
this.element.addEventListener('touchstart', this.boundDownHandler);
this.boundUpHandler = this.upHandler.bind(this);
this.element.addEventListener('mouseup', this.boundUpHandler);
this.element.addEventListener('mouseleave', this.boundUpHandler);
this.element.addEventListener('touchend', this.boundUpHandler);
this.element.addEventListener('blur', this.boundUpHandler);
}
/**
* Handle mouse / finger down on element.
* @param {Event} event The event that fired.
* @private
*/
downHandler(event) {
'use strict';
if (!this.rippleElement.style.width && !this.rippleElement.style.height) {
var rect = this.element.getBoundingClientRect();
this.boundHeight = rect.height;
this.boundWidth = rect.width;
this.rippleSize = Math.sqrt(rect.width * rect.width + rect.height * rect.height) * 2 + 2;
this.rippleElement.style.width = this.rippleSize + 'px';
this.rippleElement.style.height = this.rippleSize + 'px';
}
this.rippleElement.classList.add('is-visible');
if (event.type === 'mousedown' && this.ignoringMouseDown) {
this.ignoringMouseDown = false;
} else {
if (event.type === 'touchstart') {
this.ignoringMouseDown = true;
}
var frameCount = this.getFrameCount();
if (frameCount > 0) {
return;
}
this.setFrameCount(1);
var bound = event.currentTarget.getBoundingClientRect();
var x;
var y;
// Check if we are handling a keyboard click.
if (event.clientX === 0 && event.clientY === 0) {
x = Math.round(bound.width / 2);
y = Math.round(bound.height / 2);
} else {
var clientX = event.clientX ? event.clientX : event.touches[0].clientX;
var clientY = event.clientY ? event.clientY : event.touches[0].clientY;
x = Math.round(clientX - bound.left);
y = Math.round(clientY - bound.top);
}
this.setRippleXY(x, y);
this.setRippleStyles(true);
window.requestAnimationFrame(this.animFrameHandler.bind(this));
}
}
/**
* Handle mouse / finger up on element.
* @param {Event} event The event that fired.
* @private
*/
upHandler(event) {
'use strict';
// Don't fire for the artificial "mouseup" generated by a double-click.
if (event && event.detail !== 2) {
this.rippleElement.classList.remove('is-visible');
}
}
getFrameCount() {
return this.frameCount;
}
setFrameCount(fC) {
this.frameCount = fC;
}
getRippleElement() {
return this.rippleElement;
}
setRippleXY(newX, newY) {
this.x = newX;
this.y = newY;
}
setRippleStyles(start) {
if (this.rippleElement !== null) {
var transformString;
var scale;
var size;
var offset = 'translate(' + this.x + 'px, ' + this.y + 'px)';
if (start) {
scale = this.INITIAL_SCALE;
size = this.INITIAL_SIZE;
} else {
scale = this.FINAL_SCALE;
size = this.rippleSize + 'px';
if (this.recentering) {
offset = 'translate(' + this.boundWidth / 2 + 'px, ' + this.boundHeight / 2 + 'px)';
}
}
transformString = 'translate(-50%, -50%) ' + offset + scale;
this.rippleElement.style.webkitTransform = transformString;
this.rippleElement.style.msTransform = transformString;
this.rippleElement.style.transform = transformString;
if (start) {
this.rippleElement.classList.remove('md-ripple-animating');
} else {
this.rippleElement.classList.add('md-ripple-animating');
}
}
}
animFrameHandler() {
if (this.frameCount-- > 0) {
window.requestAnimationFrame(this.animFrameHandler.bind(this));
} else {
this.setRippleStyles(false);
}
}
elementClicked(event) {}
}