1 | import { collisionVelocity, getDistances, getRandom, getValue } from "./NumberUtils";
|
2 | import { Vector } from "../Core/Utils/Vector";
|
3 | function 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 | }
|
18 | function 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 | }
|
24 | export function isSsr() {
|
25 | return typeof window === "undefined" || !window || typeof window.document === "undefined" || !window.document;
|
26 | }
|
27 | export function hasMatchMedia() {
|
28 | return !isSsr() && typeof matchMedia !== "undefined";
|
29 | }
|
30 | export function safeMatchMedia(query) {
|
31 | if (!hasMatchMedia()) {
|
32 | return;
|
33 | }
|
34 | return matchMedia(query);
|
35 | }
|
36 | export function animate() {
|
37 | return isSsr()
|
38 | ? (callback) => setTimeout(callback)
|
39 | : (callback) => (requestAnimationFrame || setTimeout)(callback);
|
40 | }
|
41 | export function cancelAnimation() {
|
42 | return isSsr()
|
43 | ? (handle) => clearTimeout(handle)
|
44 | : (handle) => (cancelAnimationFrame || clearTimeout)(handle);
|
45 | }
|
46 | export function isInArray(value, array) {
|
47 | return value === array || (array instanceof Array && array.indexOf(value) > -1);
|
48 | }
|
49 | export 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 | }
|
56 | export function arrayRandomIndex(array) {
|
57 | return Math.floor(getRandom() * array.length);
|
58 | }
|
59 | export function itemFromArray(array, index, useIndex = true) {
|
60 | return array[index !== undefined && useIndex ? index % array.length : arrayRandomIndex(array)];
|
61 | }
|
62 | export function isPointInside(point, size, offset, radius, direction) {
|
63 | return areBoundsInside(calculateBounds(point, radius !== null && radius !== void 0 ? radius : 0), size, offset, direction);
|
64 | }
|
65 | export 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 | }
|
81 | export 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 | }
|
89 | export 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 | }
|
118 | export function isDivModeEnabled(mode, divs) {
|
119 | return !!findItemFromSingleOrMultiple(divs, (t) => t.enable && isInArray(mode, t.mode));
|
120 | }
|
121 | export 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 | }
|
129 | export function singleDivModeExecute(div, callback) {
|
130 | const selectors = div.selectors;
|
131 | executeOnSingleOrMultiple(selectors, (selector) => {
|
132 | callback(selector, div);
|
133 | });
|
134 | }
|
135 | export function divMode(divs, element) {
|
136 | if (!element || !divs) {
|
137 | return;
|
138 | }
|
139 | return findItemFromSingleOrMultiple(divs, (div) => {
|
140 | return checkSelector(element, div.selectors);
|
141 | });
|
142 | }
|
143 | export 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 | }
|
152 | export 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 | }
|
163 | export 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 | }
|
207 | export function executeOnSingleOrMultiple(obj, callback) {
|
208 | return obj instanceof Array ? obj.map((item, index) => callback(item, index)) : callback(obj, 0);
|
209 | }
|
210 | export function itemFromSingleOrMultiple(obj, index, useIndex) {
|
211 | return obj instanceof Array ? itemFromArray(obj, index, useIndex) : obj;
|
212 | }
|
213 | export function findItemFromSingleOrMultiple(obj, callback) {
|
214 | return obj instanceof Array ? obj.find((t, index) => callback(t, index)) : callback(obj, 0) ? obj : undefined;
|
215 | }
|