md2
Version:
Angular2 based Material Design components, directives and services are Accordion, Autocomplete, Chips(Tags), Collapse, Colorpicker, Data Table, Datepicker, Dialog(Modal), Menu, Multiselect, Select, Tabs, Tags(Chips), Toast and Tooltip.
169 lines • 8.49 kB
JavaScript
import { RippleRef, RippleState } from './ripple-ref';
/** Fade-in duration for the ripples. Can be modified with the speedFactor option. */
export var RIPPLE_FADE_IN_DURATION = 450;
/** Fade-out duration for the ripples in milliseconds. This can't be modified by the speedFactor. */
export var RIPPLE_FADE_OUT_DURATION = 400;
/**
* Helper service that performs DOM manipulations. Not intended to be used outside this module.
* The constructor takes a reference to the ripple directive's host element and a map of DOM
* event handlers to be installed on the element that triggers ripple animations.
* This will eventually become a custom renderer once Angular support exists.
* @docs-private
*/
var RippleRenderer = (function () {
function RippleRenderer(elementRef, _ngZone, _ruler, platform) {
this._ngZone = _ngZone;
this._ruler = _ruler;
/** Whether the mouse is currently down or not. */
this._isMousedown = false;
/** Events to be registered on the trigger element. */
this._triggerEvents = new Map();
/** Set of currently active ripple references. */
this._activeRipples = new Set();
/** Ripple config for all ripples created by events. */
this.rippleConfig = {};
/** Whether mouse ripples should be created or not. */
this.rippleDisabled = false;
// Only do anything if we're on the browser.
if (platform.isBrowser) {
this._containerElement = elementRef.nativeElement;
// Specify events which need to be registered on the trigger.
this._triggerEvents.set('mousedown', this.onMousedown.bind(this));
this._triggerEvents.set('mouseup', this.onMouseup.bind(this));
this._triggerEvents.set('mouseleave', this.onMouseLeave.bind(this));
// By default use the host element as trigger element.
this.setTriggerElement(this._containerElement);
}
}
/** Fades in a ripple at the given coordinates. */
RippleRenderer.prototype.fadeInRipple = function (pageX, pageY, config) {
var _this = this;
if (config === void 0) { config = {}; }
var containerRect = this._containerElement.getBoundingClientRect();
if (config.centered) {
pageX = containerRect.left + containerRect.width / 2;
pageY = containerRect.top + containerRect.height / 2;
}
else {
// Subtract scroll values from the coordinates because calculations below
// are always relative to the viewport rectangle.
var scrollPosition = this._ruler.getViewportScrollPosition();
pageX -= scrollPosition.left;
pageY -= scrollPosition.top;
}
var radius = config.radius || distanceToFurthestCorner(pageX, pageY, containerRect);
var duration = RIPPLE_FADE_IN_DURATION * (1 / (config.speedFactor || 1));
var offsetX = pageX - containerRect.left;
var offsetY = pageY - containerRect.top;
var ripple = document.createElement('div');
ripple.classList.add('mat-ripple-element');
ripple.style.left = offsetX - radius + "px";
ripple.style.top = offsetY - radius + "px";
ripple.style.height = radius * 2 + "px";
ripple.style.width = radius * 2 + "px";
// If the color is not set, the default CSS color will be used.
ripple.style.backgroundColor = config.color;
ripple.style.transitionDuration = duration + "ms";
this._containerElement.appendChild(ripple);
// By default the browser does not recalculate the styles of dynamically created
// ripple elements. This is critical because then the `scale` would not animate properly.
enforceStyleRecalculation(ripple);
ripple.style.transform = 'scale(1)';
// Exposed reference to the ripple that will be returned.
var rippleRef = new RippleRef(this, ripple, config);
rippleRef.state = RippleState.FADING_IN;
// Add the ripple reference to the list of all active ripples.
this._activeRipples.add(rippleRef);
// Wait for the ripple element to be completely faded in.
// Once it's faded in, the ripple can be hidden immediately if the mouse is released.
this.runTimeoutOutsideZone(function () {
rippleRef.state = RippleState.VISIBLE;
if (!config.persistent && !_this._isMousedown) {
rippleRef.fadeOut();
}
}, duration);
return rippleRef;
};
/** Fades out a ripple reference. */
RippleRenderer.prototype.fadeOutRipple = function (rippleRef) {
// For ripples that are not active anymore, don't re-un the fade-out animation.
if (!this._activeRipples.delete(rippleRef)) {
return;
}
var rippleEl = rippleRef.element;
rippleEl.style.transitionDuration = RIPPLE_FADE_OUT_DURATION + "ms";
rippleEl.style.opacity = '0';
rippleRef.state = RippleState.FADING_OUT;
// Once the ripple faded out, the ripple can be safely removed from the DOM.
this.runTimeoutOutsideZone(function () {
rippleRef.state = RippleState.HIDDEN;
rippleEl.parentNode.removeChild(rippleEl);
}, RIPPLE_FADE_OUT_DURATION);
};
/** Fades out all currently active ripples. */
RippleRenderer.prototype.fadeOutAll = function () {
this._activeRipples.forEach(function (ripple) { return ripple.fadeOut(); });
};
/** Sets the trigger element and registers the mouse events. */
RippleRenderer.prototype.setTriggerElement = function (element) {
var _this = this;
// Remove all previously register event listeners from the trigger element.
if (this._triggerElement) {
this._triggerEvents.forEach(function (fn, type) { return _this._triggerElement.removeEventListener(type, fn); });
}
if (element) {
// If the element is not null, register all event listeners on the trigger element.
this._ngZone.runOutsideAngular(function () {
_this._triggerEvents.forEach(function (fn, type) { return element.addEventListener(type, fn); });
});
}
this._triggerElement = element;
};
/** Listener being called on mousedown event. */
RippleRenderer.prototype.onMousedown = function (event) {
if (!this.rippleDisabled) {
this._isMousedown = true;
this.fadeInRipple(event.pageX, event.pageY, this.rippleConfig);
}
};
/** Listener being called on mouseup event. */
RippleRenderer.prototype.onMouseup = function () {
this._isMousedown = false;
// Fade-out all ripples that are completely visible and not persistent.
this._activeRipples.forEach(function (ripple) {
if (!ripple.config.persistent && ripple.state === RippleState.VISIBLE) {
ripple.fadeOut();
}
});
};
/** Listener being called on mouseleave event. */
RippleRenderer.prototype.onMouseLeave = function () {
if (this._isMousedown) {
this.onMouseup();
}
};
/** Runs a timeout outside of the Angular zone to avoid triggering the change detection. */
RippleRenderer.prototype.runTimeoutOutsideZone = function (fn, delay) {
if (delay === void 0) { delay = 0; }
this._ngZone.runOutsideAngular(function () { return setTimeout(fn, delay); });
};
return RippleRenderer;
}());
export { RippleRenderer };
/** Enforces a style recalculation of a DOM element by computing its styles. */
// TODO(devversion): Move into global utility function.
function enforceStyleRecalculation(element) {
// Enforce a style recalculation by calling `getComputedStyle` and accessing any property.
// Calling `getPropertyValue` is important to let optimizers know that this is not a noop.
// See: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
window.getComputedStyle(element).getPropertyValue('opacity');
}
/**
* Returns the distance from the point (x, y) to the furthest corner of a rectangle.
*/
function distanceToFurthestCorner(x, y, rect) {
var distX = Math.max(Math.abs(x - rect.left), Math.abs(x - rect.right));
var distY = Math.max(Math.abs(y - rect.top), Math.abs(y - rect.bottom));
return Math.sqrt(distX * distX + distY * distY);
}
//# sourceMappingURL=ripple-renderer.js.map