src/animations/Ripples.js
/**
* @file Ripples.js
* @author Liqueur de Toile <contact@liqueurdetoile.com>
* @licence AGPL-3.0 {@link https://github.com/liqueurdetoile/beloader-animations/blob/master/LICENSE}
*/
const anime = window.anime;
const Q = window.elementify.Q;
import AbstractAnimation from 'core/AbstractAnimation';
/**
* Ripples is a fully customizable effect that
* generates... ripples.
* It can be used as highlighter for click or items.
* It can also be used as loader whith loop active.
*
* @version 1.0.0
* @since 1.0.0
* @author Liqueur de Toile <contact@liqueurdetoile.com>
* @extends {AbstractAnimation}
*/
export default class Ripples extends AbstractAnimation {
/**
* Creates an instance of Ripples
* @version 1.0.0
* @since 1.0.0
* @author Liqueur de Toile <contact@liqueurdetoile.com>
* @param {Object} [options={}] Options for animation
* @param {boolean} [options.loop=false] Wether if animation should loop
* @param {number} [options.duration=3000] Duration of one ripple animation (ms)
* @param {number} [options.offset=1000] Offset between two ripples animations (ms)
* @param {string} [options.width='100px'] Width for the container (any allowed css value)
* @param {string} [options.height='100px'] Height for the container (any allowed css value)
* @param {number} [options.scale=30] Scale factor
* @param {string} [options.easing] Easing formula (any allowed easing by animejs)
* @param {Object} [options.ripples] Ripples Options
* @param {number} [options.ripples.count=3] Number of ripples
* @param {string} [options.ripples.width='3px'] Initial innerWidth of a ripple (any allowed css value)
* @param {string} [options.ripples.height='3px'] Initial innerWidth of a ripple (any allowed css value)
* @param {string} [options.ripples.borderColor='#09c'] Border color of ripples (any allowed css value)
* @param {string} [options.ripples.borderStyle='solid'] Border style of ripples (any allowed css value)
* @param {string} [options.ripples.borderWidth='1px'] Initial border width (any allowed css value)
* @param {string} [options.ripples.background=''] Background property of a ripple (any allowed css value)
* @param {Object} [options.ripples.opacity] Specific options for opacity animation
* @param {number} [options.ripples.opacity.start=1] Initial opacity value
* @param {number} [options.ripples.opacity.end=0] Final opacity value
* @param {number} [options.ripples.opacity.duration=this.options.duration] Opacity animation duration
* @param {number} [options.ripples.opacity.easing=this.options.easing] Opacity animation easing
*/
constructor(options = {}) {
super(options);
/**
* Active ripple index
* @type {Number}
* @since 1.0.0
*/
this.activeRipple = 0;
this.options.define('loop', false);
this.options.define('duration', 3000);
this.options.define('offset', 1000);
this.options.define('width', '100px');
this.options.define('height', '100px');
this.options.define('scale', 30);
this.options.define('easing', 'easeInSine');
this.options.define('ripples.count', 3);
this.options.define('ripples.width', '3px');
this.options.define('ripples.height', '3px');
this.options.define('ripples.borderColor', '#09c');
this.options.define('ripples.borderStyle', 'solid');
this.options.define('ripples.borderWidth', '1px');
this.options.define('ripples.background', 'none');
this.options.define('ripples.borderRadius', '50%');
this.options.define('ripples.opacity.start', 1);
this.options.define('ripples.opacity.end', 0);
this.options.define('ripples.opacity.duration', this.options.pull('duration'));
this.options.define('ripples.opacity.easing', this.options.pull('easing'));
}
/**
* HTML block for container
* @type {HTMLElement}
*/
get block() {
/* istanbul ignore else */
if (!this._block) {
this._block = Q('+div', {
id: this.id,
class: 'ripple',
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: this.options.pull('width'),
height: this.options.pull('height')
}
});
}
return this._block;
}
/**
* Generates a ripple animation given the options
* @return {Object} Animation that can be added to timeline
*/
_ripple() {
var ripple = Q('+div', {
style: {
position: 'absolute',
width: this.options.pull('ripples.width'),
height: this.options.pull('ripples.height'),
borderRadius: this.options.pull('ripples.borderRadius'),
background: this.options.pull('ripples.background'),
borderStyle: this.options.pull('ripples.borderStyle'),
borderWidth: this.options.pull('ripples.borderWidth'),
borderColor: this.options.pull('ripples.borderColor')
}
});
var animation = {
targets: ripple.node,
scale: {
value: this.options.pull('scale'),
duration: this.options.pull('duration'),
easing: this.options.pull('easing')
},
opacity: {
value: [
this.options.pull('ripples.opacity.start'),
this.options.pull('ripples.opacity.end')
],
duration: this.options.pull('ripples.opacity.duration'),
easing: this.options.pull('ripples.opacity.easing')
},
loop: this.options.pull('loop'),
offset: this.activeRipple * this.options.pull('offset'),
begin: function () {
this._block.append(ripple);
}.bind(this),
complete: () => ripple.remove()
};
this.activeRipple++;
if (this.activeRipple === this.options.pull('ripples.count')) {
this.activeRipple = 0;
}
return animation;
}
/**
* Launch the animation
* @return {this} Chainable
*/
start() {
/**
* Timeline object
* @type {Timeline}
*/
this.animation = anime.timeline({
loop: this.options.pull('loop')
});
for (let i = 0; i < this.options.pull('ripples.count'); i++) {
this.animation.add(this._ripple());
}
return this;
}
}