UNPKG

12 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.Particles = void 0;
4const Particle_1 = require("./Particle");
5const Utils_1 = require("../Utils");
6const InteractionManager_1 = require("./InteractionManager");
7const ParticlesOptions_1 = require("../Options/Classes/Particles/ParticlesOptions");
8const Mover_1 = require("./Particle/Mover");
9class Particles {
10 constructor(container) {
11 this.container = container;
12 this.nextId = 0;
13 this.array = [];
14 this.zArray = [];
15 this.mover = new Mover_1.Mover(container);
16 this.limit = 0;
17 this.needsSort = false;
18 this.lastZIndex = 0;
19 this.freqs = {
20 links: new Map(),
21 triangles: new Map(),
22 };
23 this.interactionManager = new InteractionManager_1.InteractionManager(container);
24 const canvasSize = this.container.canvas.size;
25 this.linksColors = new Map();
26 this.quadTree = new Utils_1.QuadTree(new Utils_1.Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, (canvasSize.width * 3) / 2, (canvasSize.height * 3) / 2), 4);
27 this.updaters = Utils_1.Plugins.getUpdaters(container);
28 }
29 get count() {
30 return this.array.length;
31 }
32 init() {
33 var _a;
34 const container = this.container;
35 const options = container.actualOptions;
36 this.lastZIndex = 0;
37 this.needsSort = false;
38 this.freqs.links = new Map();
39 this.freqs.triangles = new Map();
40 let handled = false;
41 for (const [, plugin] of container.plugins) {
42 if (plugin.particlesInitialization !== undefined) {
43 handled = plugin.particlesInitialization();
44 }
45 if (handled) {
46 break;
47 }
48 }
49 this.addManualParticles();
50 if (!handled) {
51 for (const group in options.particles.groups) {
52 const groupOptions = options.particles.groups[group];
53 for (let i = this.count, j = 0; j < ((_a = groupOptions.number) === null || _a === void 0 ? void 0 : _a.value) && i < options.particles.number.value; i++, j++) {
54 this.addParticle(undefined, groupOptions, group);
55 }
56 }
57 for (let i = this.count; i < options.particles.number.value; i++) {
58 this.addParticle();
59 }
60 }
61 container.pathGenerator.init(container);
62 }
63 redraw() {
64 this.clear();
65 this.init();
66 this.draw({ value: 0, factor: 0 });
67 }
68 removeAt(index, quantity = 1, group, override) {
69 if (!(index >= 0 && index <= this.count)) {
70 return;
71 }
72 let deleted = 0;
73 for (let i = index; deleted < quantity && i < this.count; i++) {
74 const particle = this.array[i];
75 if (!particle || particle.group !== group) {
76 continue;
77 }
78 particle.destroy(override);
79 this.array.splice(i--, 1);
80 const zIdx = this.zArray.indexOf(particle);
81 this.zArray.splice(zIdx, 1);
82 deleted++;
83 }
84 }
85 remove(particle, group, override) {
86 this.removeAt(this.array.indexOf(particle), undefined, group, override);
87 }
88 update(delta) {
89 const container = this.container;
90 const particlesToDelete = [];
91 container.pathGenerator.update();
92 for (const [, plugin] of container.plugins) {
93 if (plugin.update !== undefined) {
94 plugin.update(delta);
95 }
96 }
97 for (const particle of this.array) {
98 const resizeFactor = container.canvas.resizeFactor;
99 if (resizeFactor) {
100 particle.position.x *= resizeFactor.width;
101 particle.position.y *= resizeFactor.height;
102 }
103 particle.bubble.inRange = false;
104 for (const [, plugin] of this.container.plugins) {
105 if (particle.destroyed) {
106 break;
107 }
108 if (plugin.particleUpdate) {
109 plugin.particleUpdate(particle, delta);
110 }
111 }
112 this.mover.move(particle, delta);
113 if (particle.destroyed) {
114 particlesToDelete.push(particle);
115 continue;
116 }
117 this.quadTree.insert(new Utils_1.Point(particle.getPosition(), particle));
118 }
119 for (const particle of particlesToDelete) {
120 this.remove(particle);
121 }
122 this.interactionManager.externalInteract(delta);
123 for (const particle of container.particles.array) {
124 for (const updater of this.updaters) {
125 updater.update(particle, delta);
126 }
127 if (!particle.destroyed && !particle.spawning) {
128 this.interactionManager.particlesInteract(particle, delta);
129 }
130 }
131 delete container.canvas.resizeFactor;
132 }
133 draw(delta) {
134 const container = this.container;
135 container.canvas.clear();
136 const canvasSize = this.container.canvas.size;
137 this.quadTree = new Utils_1.QuadTree(new Utils_1.Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, (canvasSize.width * 3) / 2, (canvasSize.height * 3) / 2), 4);
138 this.update(delta);
139 if (this.needsSort) {
140 this.zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
141 this.lastZIndex = this.zArray[this.zArray.length - 1].position.z;
142 this.needsSort = false;
143 }
144 for (const [, plugin] of container.plugins) {
145 container.canvas.drawPlugin(plugin, delta);
146 }
147 for (const p of this.zArray) {
148 p.draw(delta);
149 }
150 }
151 clear() {
152 this.array = [];
153 this.zArray = [];
154 }
155 push(nb, mouse, overrideOptions, group) {
156 this.pushing = true;
157 for (let i = 0; i < nb; i++) {
158 this.addParticle(mouse === null || mouse === void 0 ? void 0 : mouse.position, overrideOptions, group);
159 }
160 this.pushing = false;
161 }
162 addParticle(position, overrideOptions, group) {
163 const container = this.container;
164 const options = container.actualOptions;
165 const limit = options.particles.number.limit * container.density;
166 if (limit > 0) {
167 const countToRemove = this.count + 1 - limit;
168 if (countToRemove > 0) {
169 this.removeQuantity(countToRemove);
170 }
171 }
172 return this.pushParticle(position, overrideOptions, group);
173 }
174 addSplitParticle(parent) {
175 const splitOptions = parent.options.destroy.split;
176 const options = new ParticlesOptions_1.ParticlesOptions();
177 options.load(parent.options);
178 const factor = (0, Utils_1.getRangeValue)(splitOptions.factor.value);
179 options.color.load({
180 value: {
181 hsl: parent.getFillColor(),
182 },
183 });
184 if (typeof options.size.value === "number") {
185 options.size.value /= factor;
186 }
187 else {
188 options.size.value.min /= factor;
189 options.size.value.max /= factor;
190 }
191 options.load(splitOptions.particles);
192 const offset = splitOptions.sizeOffset ? (0, Utils_1.setRangeValue)(-parent.size.value, parent.size.value) : 0;
193 const position = {
194 x: parent.position.x + (0, Utils_1.randomInRange)(offset),
195 y: parent.position.y + (0, Utils_1.randomInRange)(offset),
196 };
197 return this.pushParticle(position, options, parent.group, (particle) => {
198 if (particle.size.value < 0.5) {
199 return false;
200 }
201 particle.velocity.length = (0, Utils_1.randomInRange)((0, Utils_1.setRangeValue)(parent.velocity.length, particle.velocity.length));
202 particle.splitCount = parent.splitCount + 1;
203 particle.unbreakable = true;
204 setTimeout(() => {
205 particle.unbreakable = false;
206 }, 500);
207 return true;
208 });
209 }
210 removeQuantity(quantity, group) {
211 this.removeAt(0, quantity, group);
212 }
213 getLinkFrequency(p1, p2) {
214 const key = `${Math.min(p1.id, p2.id)}_${Math.max(p1.id, p2.id)}`;
215 let res = this.freqs.links.get(key);
216 if (res === undefined) {
217 res = Math.random();
218 this.freqs.links.set(key, res);
219 }
220 return res;
221 }
222 getTriangleFrequency(p1, p2, p3) {
223 let [id1, id2, id3] = [p1.id, p2.id, p3.id];
224 if (id1 > id2) {
225 [id2, id1] = [id1, id2];
226 }
227 if (id2 > id3) {
228 [id3, id2] = [id2, id3];
229 }
230 if (id1 > id3) {
231 [id3, id1] = [id1, id3];
232 }
233 const key = `${id1}_${id2}_${id3}`;
234 let res = this.freqs.triangles.get(key);
235 if (res === undefined) {
236 res = Math.random();
237 this.freqs.triangles.set(key, res);
238 }
239 return res;
240 }
241 addManualParticles() {
242 const container = this.container;
243 const options = container.actualOptions;
244 for (const particle of options.manualParticles) {
245 const pos = particle.position
246 ? {
247 x: (particle.position.x * container.canvas.size.width) / 100,
248 y: (particle.position.y * container.canvas.size.height) / 100,
249 }
250 : undefined;
251 this.addParticle(pos, particle.options);
252 }
253 }
254 setDensity() {
255 const options = this.container.actualOptions;
256 for (const group in options.particles.groups) {
257 this.applyDensity(options.particles.groups[group], 0, group);
258 }
259 this.applyDensity(options.particles, options.manualParticles.length);
260 }
261 applyDensity(options, manualCount, group) {
262 var _a;
263 if (!((_a = options.number.density) === null || _a === void 0 ? void 0 : _a.enable)) {
264 return;
265 }
266 const numberOptions = options.number;
267 const densityFactor = this.initDensityFactor(numberOptions.density);
268 const optParticlesNumber = numberOptions.value;
269 const optParticlesLimit = numberOptions.limit > 0 ? numberOptions.limit : optParticlesNumber;
270 const particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount;
271 const particlesCount = Math.min(this.count, this.array.filter((t) => t.group === group).length);
272 this.limit = numberOptions.limit * densityFactor;
273 if (particlesCount < particlesNumber) {
274 this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
275 }
276 else if (particlesCount > particlesNumber) {
277 this.removeQuantity(particlesCount - particlesNumber, group);
278 }
279 }
280 initDensityFactor(densityOptions) {
281 const container = this.container;
282 if (!container.canvas.element || !densityOptions.enable) {
283 return 1;
284 }
285 const canvas = container.canvas.element;
286 const pxRatio = container.retina.pixelRatio;
287 return (canvas.width * canvas.height) / (densityOptions.factor * pxRatio ** 2 * densityOptions.area);
288 }
289 pushParticle(position, overrideOptions, group, initializer) {
290 try {
291 const particle = new Particle_1.Particle(this.nextId, this.container, position, overrideOptions, group);
292 let canAdd = true;
293 if (initializer) {
294 canAdd = initializer(particle);
295 }
296 if (!canAdd) {
297 return;
298 }
299 this.array.push(particle);
300 this.zArray.push(particle);
301 this.nextId++;
302 return particle;
303 }
304 catch (e) {
305 console.warn(`error adding particle: ${e}`);
306 return;
307 }
308 }
309}
310exports.Particles = Particles;