UNPKG

@tsparticles/interaction-external-bounce

Version:

tsParticles bounce external interaction

123 lines (122 loc) 4.95 kB
import { Circle, Rectangle, Vector, calculateBounds, circleBounce, circleBounceDataFromParticle, double, getRangeValue, half, minRadius, minVelocity, safeDocument, squareExp, } from "@tsparticles/engine"; import { DivType, divModeExecute } from "@tsparticles/plugin-interactivity"; const halfPI = Math.PI * half, toleranceFactor = 10; function processBounce(container, position, radius, area, enabledCb) { const query = container.particles.grid.query(area, enabledCb); for (const particle of query) { if (area instanceof Circle) { circleBounce(circleBounceDataFromParticle(particle), { position, radius, mass: radius ** squareExp * halfPI, velocity: Vector.origin, factor: Vector.origin, }); } else if (area instanceof Rectangle) { rectBounce(particle, calculateBounds(position, radius)); } } } function singleSelectorBounce(container, selector, div, bounceCb) { const query = safeDocument().querySelectorAll(selector); if (!query.length) { return; } query.forEach(item => { const elem = item, pxRatio = container.retina.pixelRatio, pos = { x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio, y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio, }, radius = elem.offsetWidth * half * pxRatio, tolerance = toleranceFactor * pxRatio, area = div.type === DivType.circle ? new Circle(pos.x, pos.y, radius + tolerance) : new Rectangle(elem.offsetLeft * pxRatio - tolerance, elem.offsetTop * pxRatio - tolerance, elem.offsetWidth * pxRatio + tolerance * double, elem.offsetHeight * pxRatio + tolerance * double); bounceCb(pos, radius, area); }); } export function divBounce(container, divs, bounceMode, enabledCb) { divModeExecute(bounceMode, divs, (selector, div) => { singleSelectorBounce(container, selector, div, (pos, radius, area) => { processBounce(container, pos, radius, area, enabledCb); }); }); } export function mouseBounce(container, interactivityData, enabledCb) { const pxRatio = container.retina.pixelRatio, tolerance = toleranceFactor * pxRatio, mousePos = interactivityData.mouse.position, radius = container.retina.bounceModeDistance; if (!radius || radius < minRadius || !mousePos) { return; } processBounce(container, mousePos, radius, new Circle(mousePos.x, mousePos.y, radius + tolerance), enabledCb); } function rectSideBounce(data) { const res = { bounced: false }, { pSide, pOtherSide, rectSide, rectOtherSide, velocity, factor } = data; if (pOtherSide.min < rectOtherSide.min || pOtherSide.min > rectOtherSide.max || pOtherSide.max < rectOtherSide.min || pOtherSide.max > rectOtherSide.max) { return res; } if ((pSide.max >= rectSide.min && pSide.max <= (rectSide.max + rectSide.min) * half && velocity > minVelocity) || (pSide.min <= rectSide.max && pSide.min > (rectSide.max + rectSide.min) * half && velocity < minVelocity)) { res.velocity = velocity * -factor; res.bounced = true; } return res; } export function rectBounce(particle, divBounds) { const pPos = particle.getPosition(), size = particle.getRadius(), bounds = calculateBounds(pPos, size), bounceOptions = particle.options.bounce, resH = rectSideBounce({ pSide: { min: bounds.left, max: bounds.right, }, pOtherSide: { min: bounds.top, max: bounds.bottom, }, rectSide: { min: divBounds.left, max: divBounds.right, }, rectOtherSide: { min: divBounds.top, max: divBounds.bottom, }, velocity: particle.velocity.x, factor: getRangeValue(bounceOptions.horizontal.value), }); if (resH.bounced) { if (resH.velocity !== undefined) { particle.velocity.x = resH.velocity; } if (resH.position !== undefined) { particle.position.x = resH.position; } } const resV = rectSideBounce({ pSide: { min: bounds.top, max: bounds.bottom, }, pOtherSide: { min: bounds.left, max: bounds.right, }, rectSide: { min: divBounds.top, max: divBounds.bottom, }, rectOtherSide: { min: divBounds.left, max: divBounds.right, }, velocity: particle.velocity.y, factor: getRangeValue(bounceOptions.vertical.value), }); if (resV.bounced) { if (resV.velocity !== undefined) { particle.velocity.y = resV.velocity; } if (resV.position !== undefined) { particle.position.y = resV.position; } } }