UNPKG

8.12 kBJavaScriptView Raw
1import { collisionVelocity, getDistances, getRandom, getValue } from "./NumberUtils";
2import { Vector } from "../Core/Utils/Vector";
3function rectSideBounce(pSide, pOtherSide, rectSide, rectOtherSide, velocity, factor) {
4 const res = { bounced: false };
5 if (pOtherSide.min < rectOtherSide.min ||
6 pOtherSide.min > rectOtherSide.max ||
7 pOtherSide.max < rectOtherSide.min ||
8 pOtherSide.max > rectOtherSide.max) {
9 return res;
10 }
11 if ((pSide.max >= rectSide.min && pSide.max <= (rectSide.max + rectSide.min) / 2 && velocity > 0) ||
12 (pSide.min <= rectSide.max && pSide.min > (rectSide.max + rectSide.min) / 2 && velocity < 0)) {
13 res.velocity = velocity * -factor;
14 res.bounced = true;
15 }
16 return res;
17}
18function checkSelector(element, selectors) {
19 const res = executeOnSingleOrMultiple(selectors, (selector) => {
20 return element.matches(selector);
21 });
22 return res instanceof Array ? res.some((t) => t) : res;
23}
24export function isSsr() {
25 return typeof window === "undefined" || !window || typeof window.document === "undefined" || !window.document;
26}
27export function hasMatchMedia() {
28 return !isSsr() && typeof matchMedia !== "undefined";
29}
30export function safeMatchMedia(query) {
31 if (!hasMatchMedia()) {
32 return;
33 }
34 return matchMedia(query);
35}
36export function animate() {
37 return isSsr()
38 ? (callback) => setTimeout(callback)
39 : (callback) => (requestAnimationFrame || setTimeout)(callback);
40}
41export function cancelAnimation() {
42 return isSsr()
43 ? (handle) => clearTimeout(handle)
44 : (handle) => (cancelAnimationFrame || clearTimeout)(handle);
45}
46export function isInArray(value, array) {
47 return value === array || (array instanceof Array && array.indexOf(value) > -1);
48}
49export async function loadFont(font, weight) {
50 try {
51 await document.fonts.load(`${weight !== null && weight !== void 0 ? weight : "400"} 36px '${font !== null && font !== void 0 ? font : "Verdana"}'`);
52 }
53 catch (_a) {
54 }
55}
56export function arrayRandomIndex(array) {
57 return Math.floor(getRandom() * array.length);
58}
59export function itemFromArray(array, index, useIndex = true) {
60 return array[index !== undefined && useIndex ? index % array.length : arrayRandomIndex(array)];
61}
62export function isPointInside(point, size, offset, radius, direction) {
63 return areBoundsInside(calculateBounds(point, radius !== null && radius !== void 0 ? radius : 0), size, offset, direction);
64}
65export function areBoundsInside(bounds, size, offset, direction) {
66 let inside = true;
67 if (!direction || direction === "bottom") {
68 inside = bounds.top < size.height + offset.x;
69 }
70 if (inside && (!direction || direction === "left")) {
71 inside = bounds.right > offset.x;
72 }
73 if (inside && (!direction || direction === "right")) {
74 inside = bounds.left < size.width + offset.y;
75 }
76 if (inside && (!direction || direction === "top")) {
77 inside = bounds.bottom > offset.y;
78 }
79 return inside;
80}
81export function calculateBounds(point, radius) {
82 return {
83 bottom: point.y + radius,
84 left: point.x - radius,
85 right: point.x + radius,
86 top: point.y - radius,
87 };
88}
89export function deepExtend(destination, ...sources) {
90 for (const source of sources) {
91 if (source === undefined || source === null) {
92 continue;
93 }
94 if (typeof source !== "object") {
95 destination = source;
96 continue;
97 }
98 const sourceIsArray = Array.isArray(source);
99 if (sourceIsArray && (typeof destination !== "object" || !destination || !Array.isArray(destination))) {
100 destination = [];
101 }
102 else if (!sourceIsArray && (typeof destination !== "object" || !destination || Array.isArray(destination))) {
103 destination = {};
104 }
105 for (const key in source) {
106 if (key === "__proto__") {
107 continue;
108 }
109 const sourceDict = source, value = sourceDict[key], isObject = typeof value === "object", destDict = destination;
110 destDict[key] =
111 isObject && Array.isArray(value)
112 ? value.map((v) => deepExtend(destDict[key], v))
113 : deepExtend(destDict[key], value);
114 }
115 }
116 return destination;
117}
118export function isDivModeEnabled(mode, divs) {
119 return !!findItemFromSingleOrMultiple(divs, (t) => t.enable && isInArray(mode, t.mode));
120}
121export function divModeExecute(mode, divs, callback) {
122 executeOnSingleOrMultiple(divs, (div) => {
123 const divMode = div.mode, divEnabled = div.enable;
124 if (divEnabled && isInArray(mode, divMode)) {
125 singleDivModeExecute(div, callback);
126 }
127 });
128}
129export function singleDivModeExecute(div, callback) {
130 const selectors = div.selectors;
131 executeOnSingleOrMultiple(selectors, (selector) => {
132 callback(selector, div);
133 });
134}
135export function divMode(divs, element) {
136 if (!element || !divs) {
137 return;
138 }
139 return findItemFromSingleOrMultiple(divs, (div) => {
140 return checkSelector(element, div.selectors);
141 });
142}
143export function circleBounceDataFromParticle(p) {
144 return {
145 position: p.getPosition(),
146 radius: p.getRadius(),
147 mass: p.getMass(),
148 velocity: p.velocity,
149 factor: Vector.create(getValue(p.options.bounce.horizontal), getValue(p.options.bounce.vertical)),
150 };
151}
152export function circleBounce(p1, p2) {
153 const { x: xVelocityDiff, y: yVelocityDiff } = p1.velocity.sub(p2.velocity), [pos1, pos2] = [p1.position, p2.position], { dx: xDist, dy: yDist } = getDistances(pos2, pos1);
154 if (xVelocityDiff * xDist + yVelocityDiff * yDist < 0) {
155 return;
156 }
157 const angle = -Math.atan2(yDist, xDist), m1 = p1.mass, m2 = p2.mass, u1 = p1.velocity.rotate(angle), u2 = p2.velocity.rotate(angle), v1 = collisionVelocity(u1, u2, m1, m2), v2 = collisionVelocity(u2, u1, m1, m2), vFinal1 = v1.rotate(-angle), vFinal2 = v2.rotate(-angle);
158 p1.velocity.x = vFinal1.x * p1.factor.x;
159 p1.velocity.y = vFinal1.y * p1.factor.y;
160 p2.velocity.x = vFinal2.x * p2.factor.x;
161 p2.velocity.y = vFinal2.y * p2.factor.y;
162}
163export function rectBounce(particle, divBounds) {
164 const pPos = particle.getPosition(), size = particle.getRadius(), bounds = calculateBounds(pPos, size), resH = rectSideBounce({
165 min: bounds.left,
166 max: bounds.right,
167 }, {
168 min: bounds.top,
169 max: bounds.bottom,
170 }, {
171 min: divBounds.left,
172 max: divBounds.right,
173 }, {
174 min: divBounds.top,
175 max: divBounds.bottom,
176 }, particle.velocity.x, getValue(particle.options.bounce.horizontal));
177 if (resH.bounced) {
178 if (resH.velocity !== undefined) {
179 particle.velocity.x = resH.velocity;
180 }
181 if (resH.position !== undefined) {
182 particle.position.x = resH.position;
183 }
184 }
185 const resV = rectSideBounce({
186 min: bounds.top,
187 max: bounds.bottom,
188 }, {
189 min: bounds.left,
190 max: bounds.right,
191 }, {
192 min: divBounds.top,
193 max: divBounds.bottom,
194 }, {
195 min: divBounds.left,
196 max: divBounds.right,
197 }, particle.velocity.y, getValue(particle.options.bounce.vertical));
198 if (resV.bounced) {
199 if (resV.velocity !== undefined) {
200 particle.velocity.y = resV.velocity;
201 }
202 if (resV.position !== undefined) {
203 particle.position.y = resV.position;
204 }
205 }
206}
207export function executeOnSingleOrMultiple(obj, callback) {
208 return obj instanceof Array ? obj.map((item, index) => callback(item, index)) : callback(obj, 0);
209}
210export function itemFromSingleOrMultiple(obj, index, useIndex) {
211 return obj instanceof Array ? itemFromArray(obj, index, useIndex) : obj;
212}
213export function findItemFromSingleOrMultiple(obj, callback) {
214 return obj instanceof Array ? obj.find((t, index) => callback(t, index)) : callback(obj, 0) ? obj : undefined;
215}