tsparticles
Version:
Easily create highly customizable particle animations and use them as animated backgrounds for your website. Ready to use components available also for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.
275 lines (274 loc) • 12.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Bubbler = void 0;
const Utils_1 = require("../../Utils");
const Enums_1 = require("../../Enums");
function calculateBubbleValue(particleValue, modeValue, optionsValue, ratio) {
if (modeValue > optionsValue) {
const size = particleValue + (modeValue - optionsValue) * ratio;
return Utils_1.NumberUtils.clamp(size, particleValue, modeValue);
}
else if (modeValue < optionsValue) {
const size = particleValue - (optionsValue - modeValue) * ratio;
return Utils_1.NumberUtils.clamp(size, modeValue, particleValue);
}
}
class Bubbler {
constructor(container) {
this.container = container;
}
isEnabled() {
const container = this.container;
const options = container.actualOptions;
const mouse = container.interactivity.mouse;
const events = options.interactivity.events;
const divs = events.onDiv;
const divBubble = Utils_1.Utils.isDivModeEnabled(Enums_1.DivMode.bubble, divs);
if (!(divBubble || (events.onHover.enable && mouse.position) || (events.onClick.enable && mouse.clickPosition))) {
return false;
}
const hoverMode = events.onHover.mode;
const clickMode = events.onClick.mode;
return (Utils_1.Utils.isInArray(Enums_1.HoverMode.bubble, hoverMode) || Utils_1.Utils.isInArray(Enums_1.ClickMode.bubble, clickMode) || divBubble);
}
reset(particle, force) {
if (!particle.bubble.inRange || force) {
delete particle.bubble.div;
delete particle.bubble.opacity;
delete particle.bubble.radius;
delete particle.bubble.color;
}
}
interact() {
const options = this.container.actualOptions;
const events = options.interactivity.events;
const onHover = events.onHover;
const onClick = events.onClick;
const hoverEnabled = onHover.enable;
const hoverMode = onHover.mode;
const clickEnabled = onClick.enable;
const clickMode = onClick.mode;
const divs = events.onDiv;
if (hoverEnabled && Utils_1.Utils.isInArray(Enums_1.HoverMode.bubble, hoverMode)) {
this.hoverBubble();
}
else if (clickEnabled && Utils_1.Utils.isInArray(Enums_1.ClickMode.bubble, clickMode)) {
this.clickBubble();
}
else {
Utils_1.Utils.divModeExecute(Enums_1.DivMode.bubble, divs, (selector, div) => this.singleSelectorHover(selector, div));
}
}
singleSelectorHover(selector, div) {
const container = this.container;
const selectors = document.querySelectorAll(selector);
if (!selectors.length) {
return;
}
selectors.forEach((item) => {
const elem = item;
const pxRatio = container.retina.pixelRatio;
const pos = {
x: (elem.offsetLeft + elem.offsetWidth / 2) * pxRatio,
y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
};
const repulseRadius = (elem.offsetWidth / 2) * pxRatio;
const area = div.type === Enums_1.DivType.circle
? new Utils_1.Circle(pos.x, pos.y, repulseRadius)
: new Utils_1.Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio);
const query = container.particles.quadTree.query(area);
for (const particle of query) {
if (!area.contains(particle.getPosition())) {
continue;
}
particle.bubble.inRange = true;
const divs = container.actualOptions.interactivity.modes.bubble.divs;
const divBubble = Utils_1.Utils.divMode(divs, elem);
if (!particle.bubble.div || particle.bubble.div !== elem) {
this.reset(particle, true);
particle.bubble.div = elem;
}
this.hoverBubbleSize(particle, 1, divBubble);
this.hoverBubbleOpacity(particle, 1, divBubble);
this.hoverBubbleColor(particle, divBubble);
}
});
}
process(particle, distMouse, timeSpent, data) {
const container = this.container;
const bubbleParam = data.bubbleObj.optValue;
if (bubbleParam === undefined) {
return;
}
const options = container.actualOptions;
const bubbleDuration = options.interactivity.modes.bubble.duration;
const bubbleDistance = container.retina.bubbleModeDistance;
const particlesParam = data.particlesObj.optValue;
const pObjBubble = data.bubbleObj.value;
const pObj = data.particlesObj.value || 0;
const type = data.type;
if (bubbleParam !== particlesParam) {
if (!container.bubble.durationEnd) {
if (distMouse <= bubbleDistance) {
const obj = pObjBubble !== null && pObjBubble !== void 0 ? pObjBubble : pObj;
if (obj !== bubbleParam) {
const value = pObj - (timeSpent * (pObj - bubbleParam)) / bubbleDuration;
if (type === Enums_1.ProcessBubbleType.size) {
particle.bubble.radius = value;
}
if (type === Enums_1.ProcessBubbleType.opacity) {
particle.bubble.opacity = value;
}
}
}
else {
if (type === Enums_1.ProcessBubbleType.size) {
delete particle.bubble.radius;
}
if (type === Enums_1.ProcessBubbleType.opacity) {
delete particle.bubble.opacity;
}
}
}
else if (pObjBubble) {
if (type === Enums_1.ProcessBubbleType.size) {
delete particle.bubble.radius;
}
if (type === Enums_1.ProcessBubbleType.opacity) {
delete particle.bubble.opacity;
}
}
}
}
clickBubble() {
const container = this.container;
const options = container.actualOptions;
const mouseClickPos = container.interactivity.mouse.clickPosition;
if (mouseClickPos === undefined) {
return;
}
const distance = container.retina.bubbleModeDistance;
const query = container.particles.quadTree.queryCircle(mouseClickPos, distance);
for (const particle of query) {
if (!container.bubble.clicking) {
continue;
}
particle.bubble.inRange = !container.bubble.durationEnd;
const pos = particle.getPosition();
const distMouse = Utils_1.NumberUtils.getDistance(pos, mouseClickPos);
const timeSpent = (new Date().getTime() - (container.interactivity.mouse.clickTime || 0)) / 1000;
if (timeSpent > options.interactivity.modes.bubble.duration) {
container.bubble.durationEnd = true;
}
if (timeSpent > options.interactivity.modes.bubble.duration * 2) {
container.bubble.clicking = false;
container.bubble.durationEnd = false;
}
const sizeData = {
bubbleObj: {
optValue: container.retina.bubbleModeSize,
value: particle.bubble.radius,
},
particlesObj: {
optValue: Utils_1.NumberUtils.getRangeMax(particle.options.size.value) * container.retina.pixelRatio,
value: particle.size.value,
},
type: Enums_1.ProcessBubbleType.size,
};
this.process(particle, distMouse, timeSpent, sizeData);
const opacityData = {
bubbleObj: {
optValue: options.interactivity.modes.bubble.opacity,
value: particle.bubble.opacity,
},
particlesObj: {
optValue: Utils_1.NumberUtils.getRangeMax(particle.options.opacity.value),
value: particle.opacity.value,
},
type: Enums_1.ProcessBubbleType.opacity,
};
this.process(particle, distMouse, timeSpent, opacityData);
if (!container.bubble.durationEnd) {
if (distMouse <= container.retina.bubbleModeDistance) {
this.hoverBubbleColor(particle);
}
else {
delete particle.bubble.color;
}
}
else {
delete particle.bubble.color;
}
}
}
hoverBubble() {
const container = this.container;
const mousePos = container.interactivity.mouse.position;
if (mousePos === undefined) {
return;
}
const distance = container.retina.bubbleModeDistance;
const query = container.particles.quadTree.queryCircle(mousePos, distance);
for (const particle of query) {
particle.bubble.inRange = true;
const pos = particle.getPosition();
const pointDistance = Utils_1.NumberUtils.getDistance(pos, mousePos);
const ratio = 1 - pointDistance / distance;
if (pointDistance <= distance) {
if (ratio >= 0 && container.interactivity.status === Utils_1.Constants.mouseMoveEvent) {
this.hoverBubbleSize(particle, ratio);
this.hoverBubbleOpacity(particle, ratio);
this.hoverBubbleColor(particle);
}
}
else {
this.reset(particle);
}
if (container.interactivity.status === Utils_1.Constants.mouseLeaveEvent) {
this.reset(particle);
}
}
}
hoverBubbleSize(particle, ratio, divBubble) {
const container = this.container;
const modeSize = (divBubble === null || divBubble === void 0 ? void 0 : divBubble.size)
? divBubble.size * container.retina.pixelRatio
: container.retina.bubbleModeSize;
if (modeSize === undefined) {
return;
}
const optSize = Utils_1.NumberUtils.getRangeMax(particle.options.size.value) * container.retina.pixelRatio;
const pSize = particle.size.value;
const size = calculateBubbleValue(pSize, modeSize, optSize, ratio);
if (size !== undefined) {
particle.bubble.radius = size;
}
}
hoverBubbleOpacity(particle, ratio, divBubble) {
var _a;
const options = this.container.actualOptions;
const modeOpacity = (_a = divBubble === null || divBubble === void 0 ? void 0 : divBubble.opacity) !== null && _a !== void 0 ? _a : options.interactivity.modes.bubble.opacity;
if (modeOpacity === undefined) {
return;
}
const optOpacity = particle.options.opacity.value;
const pOpacity = particle.opacity.value;
const opacity = calculateBubbleValue(pOpacity, modeOpacity, Utils_1.NumberUtils.getRangeMax(optOpacity), ratio);
if (opacity !== undefined) {
particle.bubble.opacity = opacity;
}
}
hoverBubbleColor(particle, divBubble) {
var _a;
const options = this.container.actualOptions;
if (particle.bubble.color === undefined) {
const modeColor = (_a = divBubble === null || divBubble === void 0 ? void 0 : divBubble.color) !== null && _a !== void 0 ? _a : options.interactivity.modes.bubble.color;
if (modeColor === undefined) {
return;
}
const bubbleColor = modeColor instanceof Array ? Utils_1.Utils.itemFromArray(modeColor) : modeColor;
particle.bubble.color = Utils_1.ColorUtils.colorToHsl(bubbleColor);
}
}
}
exports.Bubbler = Bubbler;