11import { ElementRef , NgZone } from '@angular/core' ;
22import { ViewportRuler } from '../overlay/position/viewport-ruler' ;
3+ import { RippleRef } from './ripple-ref' ;
34
45/** Fade-in duration for the ripples. Can be modified with the speedFactor option. */
56export const RIPPLE_FADE_IN_DURATION = 450 ;
67
78/** Fade-out duration for the ripples in milliseconds. This can't be modified by the speedFactor. */
89export const RIPPLE_FADE_OUT_DURATION = 400 ;
910
10- /**
11- * Returns the distance from the point (x, y) to the furthest corner of a rectangle.
12- */
13- const distanceToFurthestCorner = ( x : number , y : number , rect : ClientRect ) => {
14- const distX = Math . max ( Math . abs ( x - rect . left ) , Math . abs ( x - rect . right ) ) ;
15- const distY = Math . max ( Math . abs ( y - rect . top ) , Math . abs ( y - rect . bottom ) ) ;
16- return Math . sqrt ( distX * distX + distY * distY ) ;
17- } ;
18-
1911export type RippleConfig = {
2012 color ?: string ;
2113 centered ?: boolean ;
2214 radius ?: number ;
2315 speedFactor ?: number ;
16+ persistent ?: boolean ;
2417} ;
2518
2619/**
@@ -41,12 +34,12 @@ export class RippleRenderer {
4134 /** Whether the mouse is currently down or not. */
4235 private _isMousedown : boolean = false ;
4336
44- /** Currently active ripples that will be closed on mouseup. */
45- private _activeRipples : HTMLElement [ ] = [ ] ;
46-
4737 /** Events to be registered on the trigger element. */
4838 private _triggerEvents = new Map < string , any > ( ) ;
4939
40+ /** Currently active ripples. */
41+ activeRipples : RippleRef [ ] = [ ] ;
42+
5043 /** Ripple config for all ripples created by events. */
5144 rippleConfig : RippleConfig = { } ;
5245
@@ -66,7 +59,7 @@ export class RippleRenderer {
6659 }
6760
6861 /** Fades in a ripple at the given coordinates. */
69- fadeInRipple ( pageX : number , pageY : number , config : RippleConfig = { } ) {
62+ fadeInRipple ( pageX : number , pageY : number , config : RippleConfig = { } ) : RippleRef {
7063 let containerRect = this . _containerElement . getBoundingClientRect ( ) ;
7164
7265 if ( config . centered ) {
@@ -101,15 +94,24 @@ export class RippleRenderer {
10194
10295 // By default the browser does not recalculate the styles of dynamically created
10396 // ripple elements. This is critical because then the `scale` would not animate properly.
104- this . _enforceStyleRecalculation ( ripple ) ;
97+ enforceStyleRecalculation ( ripple ) ;
10598
10699 ripple . style . transform = 'scale(1)' ;
107100
108- // Wait for the ripple to be faded in. Once it's faded in, the ripple can be hidden immediately
109- // if the mouse is released.
101+ // Exposed reference to the ripple that will be returned.
102+ let rippleRef = new RippleRef ( this , ripple , config ) ;
103+
104+ // Wait for the ripple element to be completely faded in.
105+ // Once it's faded in, the ripple can be hidden immediately if the mouse is released.
110106 this . runTimeoutOutsideZone ( ( ) => {
111- this . _isMousedown ? this . _activeRipples . push ( ripple ) : this . fadeOutRipple ( ripple ) ;
107+ if ( config . persistent || this . _isMousedown ) {
108+ this . activeRipples . push ( rippleRef ) ;
109+ } else {
110+ rippleRef . fadeOut ( ) ;
111+ }
112112 } , duration ) ;
113+
114+ return rippleRef ;
113115 }
114116
115117 /** Fades out a ripple element. */
@@ -151,8 +153,11 @@ export class RippleRenderer {
151153 /** Listener being called on mouseup event. */
152154 private onMouseup ( ) {
153155 this . _isMousedown = false ;
154- this . _activeRipples . forEach ( ripple => this . fadeOutRipple ( ripple ) ) ;
155- this . _activeRipples = [ ] ;
156+
157+ // On mouseup, fade-out all ripples that are active and not persistent.
158+ this . activeRipples
159+ . filter ( ripple => ! ripple . config . persistent )
160+ . forEach ( ripple => ripple . fadeOut ( ) ) ;
156161 }
157162
158163 /** Listener being called on mouseleave event. */
@@ -167,13 +172,22 @@ export class RippleRenderer {
167172 this . _ngZone . runOutsideAngular ( ( ) => setTimeout ( fn , delay ) ) ;
168173 }
169174
170- /** Enforces a style recalculation of a DOM element by computing its styles. */
171- // TODO(devversion): Move into global utility function.
172- private _enforceStyleRecalculation ( element : HTMLElement ) {
173- // Enforce a style recalculation by calling `getComputedStyle` and accessing any property.
174- // Calling `getPropertyValue` is important to let optimizers know that this is not a noop.
175- // See: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
176- window . getComputedStyle ( element ) . getPropertyValue ( 'opacity' ) ;
177- }
175+ }
178176
177+ /** Enforces a style recalculation of a DOM element by computing its styles. */
178+ // TODO(devversion): Move into global utility function.
179+ function enforceStyleRecalculation ( element : HTMLElement ) {
180+ // Enforce a style recalculation by calling `getComputedStyle` and accessing any property.
181+ // Calling `getPropertyValue` is important to let optimizers know that this is not a noop.
182+ // See: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
183+ window . getComputedStyle ( element ) . getPropertyValue ( 'opacity' ) ;
184+ }
185+
186+ /**
187+ * Returns the distance from the point (x, y) to the furthest corner of a rectangle.
188+ */
189+ function distanceToFurthestCorner ( x : number , y : number , rect : ClientRect ) {
190+ const distX = Math . max ( Math . abs ( x - rect . left ) , Math . abs ( x - rect . right ) ) ;
191+ const distY = Math . max ( Math . abs ( y - rect . top ) , Math . abs ( y - rect . bottom ) ) ;
192+ return Math . sqrt ( distX * distX + distY * distY ) ;
179193}
0 commit comments