@tsparticles/fireworks 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@
4
4
  * Demo / Generator : https://particles.js.org/
5
5
  * GitHub : https://www.github.com/matteobruni/tsparticles
6
6
  * How to use? : Check the GitHub README
7
- * v3.0.1
7
+ * v3.0.3
8
8
  */
9
9
  (function webpackUniversalModuleDefinition(root, factory) {
10
10
  if(typeof exports === 'object' && typeof module === 'object')
@@ -3900,6 +3900,12 @@ class Particle {
3900
3900
  updater.particleDestroyed && updater.particleDestroyed(this, override);
3901
3901
  }
3902
3902
  pathGenerator && pathGenerator.reset(this);
3903
+ this._engine.dispatchEvent("particleDestroyed", {
3904
+ container: this.container,
3905
+ data: {
3906
+ particle: this
3907
+ }
3908
+ });
3903
3909
  }
3904
3910
  draw(delta) {
3905
3911
  const container = this.container,
@@ -4252,6 +4258,11 @@ const qTreeRectangle = canvasSize => {
4252
4258
  };
4253
4259
  class Particles {
4254
4260
  constructor(engine, container) {
4261
+ this._addToPool = (...particles) => {
4262
+ for (const particle of particles) {
4263
+ this._pool.push(particle);
4264
+ }
4265
+ };
4255
4266
  this._applyDensity = (options, manualCount, group) => {
4256
4267
  const numberOptions = options.number;
4257
4268
  if (!options.number.density?.enable) {
@@ -4322,17 +4333,17 @@ class Particles {
4322
4333
  if (!particle || particle.group !== group) {
4323
4334
  return false;
4324
4335
  }
4325
- particle.destroy(override);
4326
4336
  const zIdx = this._zArray.indexOf(particle);
4327
4337
  this._array.splice(index, 1);
4328
4338
  this._zArray.splice(zIdx, 1);
4329
- this._pool.push(particle);
4339
+ particle.destroy(override);
4330
4340
  this._engine.dispatchEvent("particleRemoved", {
4331
4341
  container: this._container,
4332
4342
  data: {
4333
4343
  particle
4334
4344
  }
4335
4345
  });
4346
+ this._addToPool(particle);
4336
4347
  return true;
4337
4348
  };
4338
4349
  this._engine = engine;
@@ -4530,7 +4541,15 @@ class Particles {
4530
4541
  const checkDelete = p => !particlesToDelete.has(p);
4531
4542
  this._array = this.filter(checkDelete);
4532
4543
  this._zArray = this._zArray.filter(checkDelete);
4533
- this._pool.push(...particlesToDelete);
4544
+ for (const particle of particlesToDelete) {
4545
+ this._engine.dispatchEvent("particleRemoved", {
4546
+ container: this._container,
4547
+ data: {
4548
+ particle
4549
+ }
4550
+ });
4551
+ }
4552
+ this._addToPool(...particlesToDelete);
4534
4553
  }
4535
4554
  await this._interactionManager.externalInteract(delta);
4536
4555
  for (const particle of this._array) {
@@ -5146,7 +5165,7 @@ class Engine {
5146
5165
  return res;
5147
5166
  }
5148
5167
  get version() {
5149
- return "3.0.1";
5168
+ return "3.0.3";
5150
5169
  }
5151
5170
  addConfig(config) {
5152
5171
  const name = config.name ?? "default";
@@ -5261,7 +5280,7 @@ class Engine {
5261
5280
  this._initialized = true;
5262
5281
  }
5263
5282
  async load(params) {
5264
- const id = params.id ?? `tsparticles${Math.floor(getRandom() * 10000)}`,
5283
+ const id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * 10000)}`,
5265
5284
  {
5266
5285
  index,
5267
5286
  url
@@ -5561,6 +5580,7 @@ if (!isSsr()) {
5561
5580
 
5562
5581
  class FireworkOptions {
5563
5582
  constructor() {
5583
+ this.background = "none";
5564
5584
  this.brightness = {
5565
5585
  min: -30,
5566
5586
  max: 30
@@ -5571,7 +5591,7 @@ class FireworkOptions {
5571
5591
  min: 10,
5572
5592
  max: 30
5573
5593
  };
5574
- this.rate = 20;
5594
+ this.rate = 10;
5575
5595
  this.saturation = {
5576
5596
  min: -30,
5577
5597
  max: 30
@@ -5590,6 +5610,9 @@ class FireworkOptions {
5590
5610
  if (!data) {
5591
5611
  return;
5592
5612
  }
5613
+ if (data.background !== undefined) {
5614
+ this.background = data.background;
5615
+ }
5593
5616
  if (data.colors !== undefined) {
5594
5617
  if (isArray(data.colors)) {
5595
5618
  this.colors = [...data.colors];
@@ -7122,6 +7145,7 @@ class EmitterInstance {
7122
7145
  }
7123
7146
  if (this._lifeCount > 0 || this._immortal) {
7124
7147
  this.position = this._calcPosition();
7148
+ this._shape?.resize(this.position, this.size);
7125
7149
  this._spawnDelay = getRangeValue(this.options.life.delay ?? 0) * 1000 / this.container.retina.reduceFactor;
7126
7150
  } else {
7127
7151
  this._destroy();
@@ -7378,6 +7402,19 @@ class ShapeManager {
7378
7402
  return shapeGeneratorss.keys();
7379
7403
  }
7380
7404
  }
7405
+ ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/EmitterShapeBase.js
7406
+ class EmitterShapeBase {
7407
+ constructor(position, size, fill, options) {
7408
+ this.position = position;
7409
+ this.size = size;
7410
+ this.fill = fill;
7411
+ this.options = options;
7412
+ }
7413
+ resize(position, size) {
7414
+ this.position = position;
7415
+ this.size = size;
7416
+ }
7417
+ }
7381
7418
  ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/index.js
7382
7419
 
7383
7420
 
@@ -7482,6 +7519,81 @@ async function loadEmittersPlugin(engine, refresh = true) {
7482
7519
 
7483
7520
 
7484
7521
 
7522
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/square/dist/browser/EmittersSquareShape.js
7523
+
7524
+
7525
+ function randomSquareCoordinate(position, offset) {
7526
+ return position + offset * (getRandom() - 0.5);
7527
+ }
7528
+ class EmittersSquareShape extends EmitterShapeBase {
7529
+ constructor(position, size, fill, options) {
7530
+ super(position, size, fill, options);
7531
+ }
7532
+ async init() {}
7533
+ async randomPosition() {
7534
+ const fill = this.fill,
7535
+ position = this.position,
7536
+ size = this.size;
7537
+ if (fill) {
7538
+ return {
7539
+ position: {
7540
+ x: randomSquareCoordinate(position.x, size.width),
7541
+ y: randomSquareCoordinate(position.y, size.height)
7542
+ }
7543
+ };
7544
+ } else {
7545
+ const halfW = size.width / 2,
7546
+ halfH = size.height / 2,
7547
+ side = Math.floor(getRandom() * 4),
7548
+ v = (getRandom() - 0.5) * 2;
7549
+ switch (side) {
7550
+ case 0:
7551
+ return {
7552
+ position: {
7553
+ x: position.x + v * halfW,
7554
+ y: position.y - halfH
7555
+ }
7556
+ };
7557
+ case 1:
7558
+ return {
7559
+ position: {
7560
+ x: position.x - halfW,
7561
+ y: position.y + v * halfH
7562
+ }
7563
+ };
7564
+ case 2:
7565
+ return {
7566
+ position: {
7567
+ x: position.x + v * halfW,
7568
+ y: position.y + halfH
7569
+ }
7570
+ };
7571
+ case 3:
7572
+ default:
7573
+ return {
7574
+ position: {
7575
+ x: position.x + halfW,
7576
+ y: position.y + v * halfH
7577
+ }
7578
+ };
7579
+ }
7580
+ }
7581
+ }
7582
+ }
7583
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/square/dist/browser/EmittersSquareShapeGenerator.js
7584
+
7585
+ class EmittersSquareShapeGenerator {
7586
+ generate(position, size, fill, options) {
7587
+ return new EmittersSquareShape(position, size, fill, options);
7588
+ }
7589
+ }
7590
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/square/dist/browser/index.js
7591
+
7592
+ async function loadEmittersShapeSquare(engine, refresh = true) {
7593
+ const emittersEngine = engine;
7594
+ emittersEngine.addEmitterShapeGenerator && emittersEngine.addEmitterShapeGenerator("square", new EmittersSquareShapeGenerator());
7595
+ await emittersEngine.refresh(refresh);
7596
+ }
7485
7597
  ;// CONCATENATED MODULE: ../../updaters/life/dist/browser/Options/Classes/LifeDelay.js
7486
7598
 
7487
7599
  class LifeDelay extends ValueWithRandom {
@@ -8169,32 +8281,35 @@ class SoundsInstance {
8169
8281
  return;
8170
8282
  }
8171
8283
  for (const event of soundsOptions.events) {
8172
- const cb = async args => {
8173
- if (this._container !== args.container) {
8174
- return;
8175
- }
8176
- if (!this._container || this._container.muted || this._container.destroyed) {
8177
- executeOnSingleOrMultiple(event.event, item => {
8178
- this._engine.removeEventListener(item, cb);
8179
- });
8180
- return;
8181
- }
8182
- if (event.filter && !event.filter(args)) {
8183
- return;
8184
- }
8185
- if (event.audio) {
8186
- this._playBuffer(itemFromSingleOrMultiple(event.audio));
8187
- } else if (event.melodies) {
8188
- const melody = itemFromArray(event.melodies);
8189
- if (melody.melodies.length) {
8190
- await Promise.allSettled(melody.melodies.map(m => this._playNote(m.notes, 0, melody.loop)));
8191
- } else {
8192
- await this._playNote(melody.notes, 0, melody.loop);
8284
+ const cb = args => {
8285
+ (async () => {
8286
+ const filterNotValid = event.filter && !event.filter(args);
8287
+ if (this._container !== args.container) {
8288
+ return;
8193
8289
  }
8194
- } else if (event.notes) {
8195
- const note = itemFromArray(event.notes);
8196
- await this._playNote([note], 0, false);
8197
- }
8290
+ if (!this._container || this._container.muted || this._container.destroyed) {
8291
+ executeOnSingleOrMultiple(event.event, item => {
8292
+ this._engine.removeEventListener(item, cb);
8293
+ });
8294
+ return;
8295
+ }
8296
+ if (filterNotValid) {
8297
+ return;
8298
+ }
8299
+ if (event.audio) {
8300
+ this._playBuffer(itemFromSingleOrMultiple(event.audio));
8301
+ } else if (event.melodies) {
8302
+ const melody = itemFromArray(event.melodies);
8303
+ if (melody.melodies.length) {
8304
+ await Promise.allSettled(melody.melodies.map(m => this._playNote(m.notes, 0, melody.loop)));
8305
+ } else {
8306
+ await this._playNote(melody.notes, 0, melody.loop);
8307
+ }
8308
+ } else if (event.notes) {
8309
+ const note = itemFromArray(event.notes);
8310
+ await this._playNote([note], 0, false);
8311
+ }
8312
+ })();
8198
8313
  };
8199
8314
  executeOnSingleOrMultiple(event.event, item => {
8200
8315
  this._engine.addEventListener(item, cb);
@@ -8347,16 +8462,18 @@ class SoundsInstance {
8347
8462
  unmuteImg.style.display = container.muted ? "none" : "block";
8348
8463
  }
8349
8464
  };
8350
- this._updateMuteStatus = () => {
8465
+ this._updateMuteStatus = async () => {
8351
8466
  const container = this._container;
8352
8467
  if (container.muted) {
8468
+ await container.audioContext?.suspend();
8353
8469
  this._mute();
8354
8470
  } else {
8471
+ await container.audioContext?.resume();
8355
8472
  this._unmute();
8356
8473
  this._playMuteSound();
8357
8474
  }
8358
8475
  };
8359
- this._updateVolume = () => {
8476
+ this._updateVolume = async () => {
8360
8477
  const container = this._container,
8361
8478
  soundsOptions = container.actualOptions.sounds;
8362
8479
  if (!soundsOptions?.enable) {
@@ -8374,7 +8491,7 @@ class SoundsInstance {
8374
8491
  }
8375
8492
  if (stateChanged) {
8376
8493
  this._updateMuteIcons();
8377
- this._updateMuteStatus();
8494
+ await this._updateMuteStatus();
8378
8495
  }
8379
8496
  if (this._gain?.gain) {
8380
8497
  this._gain.gain.value = this._volume / 100;
@@ -8432,10 +8549,10 @@ class SoundsInstance {
8432
8549
  volumeUp
8433
8550
  } = soundsOptions.icons,
8434
8551
  margin = 10;
8435
- const toggleMute = () => {
8552
+ const toggleMute = async () => {
8436
8553
  container.muted = !container.muted;
8437
8554
  this._updateMuteIcons();
8438
- this._updateMuteStatus();
8555
+ await this._updateMuteStatus();
8439
8556
  };
8440
8557
  this._muteImg = initImage({
8441
8558
  container,
@@ -8465,12 +8582,12 @@ class SoundsInstance {
8465
8582
  iconOptions: volumeDown,
8466
8583
  margin,
8467
8584
  rightOffsets: [volumeUp.width],
8468
- clickCb: () => {
8585
+ clickCb: async () => {
8469
8586
  if (container.muted) {
8470
8587
  this._volume = 0;
8471
8588
  }
8472
8589
  this._volume -= soundsOptions.volume.step;
8473
- this._updateVolume();
8590
+ await this._updateVolume();
8474
8591
  }
8475
8592
  });
8476
8593
  this._volumeUpImg = initImage({
@@ -8481,12 +8598,12 @@ class SoundsInstance {
8481
8598
  iconOptions: volumeUp,
8482
8599
  margin,
8483
8600
  rightOffsets: [],
8484
- clickCb: () => {
8601
+ clickCb: async () => {
8485
8602
  if (container.muted) {
8486
8603
  this._volume = 0;
8487
8604
  }
8488
8605
  this._volume += soundsOptions.volume.step;
8489
- this._updateVolume();
8606
+ await this._updateVolume();
8490
8607
  }
8491
8608
  });
8492
8609
  }
@@ -8637,6 +8754,88 @@ class StrokeColorUpdater {
8637
8754
  async function loadStrokeColorUpdater(engine, refresh = true) {
8638
8755
  await engine.addParticleUpdater("strokeColor", container => new StrokeColorUpdater(container), refresh);
8639
8756
  }
8757
+ ;// CONCATENATED MODULE: ../../effects/trail/dist/browser/TrailDrawer.js
8758
+
8759
+ class TrailDrawer {
8760
+ draw(data) {
8761
+ const {
8762
+ context,
8763
+ radius,
8764
+ particle
8765
+ } = data,
8766
+ diameter = radius * 2,
8767
+ pxRatio = particle.container.retina.pixelRatio,
8768
+ currentPos = particle.getPosition();
8769
+ if (!particle.trail || !particle.trailLength) {
8770
+ return;
8771
+ }
8772
+ const pathLength = particle.trailLength;
8773
+ particle.trail.push({
8774
+ color: context.fillStyle ?? context.strokeStyle,
8775
+ position: {
8776
+ x: currentPos.x,
8777
+ y: currentPos.y
8778
+ }
8779
+ });
8780
+ if (particle.trail.length < 2) {
8781
+ return;
8782
+ }
8783
+ while (particle.trail.length > pathLength) {
8784
+ particle.trail.shift();
8785
+ }
8786
+ const trailLength = Math.min(particle.trail.length, pathLength),
8787
+ offsetPos = {
8788
+ x: currentPos.x,
8789
+ y: currentPos.y
8790
+ },
8791
+ canvasSize = {
8792
+ width: particle.container.canvas.size.width + diameter,
8793
+ height: particle.container.canvas.size.height + diameter
8794
+ };
8795
+ let lastPos = particle.trail[trailLength - 1].position;
8796
+ context.setTransform(1, 0, 0, 1, currentPos.x, currentPos.y);
8797
+ for (let i = trailLength; i > 0; i--) {
8798
+ const step = particle.trail[i - 1],
8799
+ position = step.position;
8800
+ context.beginPath();
8801
+ context.moveTo(lastPos.x - offsetPos.x, lastPos.y - offsetPos.y);
8802
+ const warp = {
8803
+ x: (lastPos.x + canvasSize.width) % canvasSize.width,
8804
+ y: (lastPos.y + canvasSize.height) % canvasSize.height
8805
+ };
8806
+ if (Math.abs(lastPos.x - position.x) > canvasSize.width / 2 || Math.abs(lastPos.y - position.y) > canvasSize.height / 2) {
8807
+ lastPos = position;
8808
+ continue;
8809
+ }
8810
+ context.lineTo((Math.abs(lastPos.x - position.x) > canvasSize.width / 2 ? warp.x : position.x) - offsetPos.x, (Math.abs(lastPos.y - position.y) > canvasSize.height / 2 ? warp.y : position.y) - offsetPos.y);
8811
+ const width = Math.max(i / trailLength * diameter, pxRatio, particle.trailMinWidth ?? -1);
8812
+ const oldAlpha = context.globalAlpha;
8813
+ context.globalAlpha = particle.trailFade ? i / trailLength : 1;
8814
+ context.lineWidth = particle.trailMaxWidth ? Math.min(width, particle.trailMaxWidth) : width;
8815
+ context.strokeStyle = step.color;
8816
+ context.stroke();
8817
+ context.globalAlpha = oldAlpha;
8818
+ lastPos = position;
8819
+ }
8820
+ const {
8821
+ transformData
8822
+ } = data;
8823
+ context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, currentPos.x, currentPos.y);
8824
+ }
8825
+ particleInit(container, particle) {
8826
+ particle.trail = [];
8827
+ const effectData = particle.effectData;
8828
+ particle.trailFade = effectData?.fade ?? true;
8829
+ particle.trailLength = getRangeValue(effectData?.length ?? 10) * container.retina.pixelRatio;
8830
+ particle.trailMaxWidth = effectData?.maxWidth ? getRangeValue(effectData.maxWidth) * container.retina.pixelRatio : undefined;
8831
+ particle.trailMinWidth = effectData?.minWidth ? getRangeValue(effectData.minWidth) * container.retina.pixelRatio : undefined;
8832
+ }
8833
+ }
8834
+ ;// CONCATENATED MODULE: ../../effects/trail/dist/browser/index.js
8835
+
8836
+ async function loadTrailEffect(engine, refresh = true) {
8837
+ await engine.addEffect("trail", new TrailDrawer(), refresh);
8838
+ }
8640
8839
  ;// CONCATENATED MODULE: ./dist/browser/fireworks.js
8641
8840
 
8642
8841
 
@@ -8648,11 +8847,13 @@ async function loadStrokeColorUpdater(engine, refresh = true) {
8648
8847
 
8649
8848
 
8650
8849
 
8850
+
8851
+
8651
8852
  let initialized = false;
8652
8853
  let initializing = false;
8653
8854
  const explodeSoundCheck = args => {
8654
8855
  const data = args.data;
8655
- return data.particle.shape === "line";
8856
+ return data.particle.shape === "circle" && !!data.particle.splitCount && data.particle.splitCount < 2;
8656
8857
  };
8657
8858
  class FireworksInstance {
8658
8859
  constructor(container) {
@@ -8685,12 +8886,14 @@ async function initPlugins() {
8685
8886
  }
8686
8887
  initializing = true;
8687
8888
  await loadEmittersPlugin(tsParticles, false);
8889
+ await loadEmittersShapeSquare(tsParticles, false);
8688
8890
  await loadSoundsPlugin(tsParticles, false);
8689
8891
  await loadLineShape(tsParticles, false);
8690
8892
  await loadRotateUpdater(tsParticles, false);
8691
8893
  await loadDestroyUpdater(tsParticles, false);
8692
8894
  await loadLifeUpdater(tsParticles, false);
8693
8895
  await loadStrokeColorUpdater(tsParticles, false);
8896
+ await loadTrailEffect(tsParticles, false);
8694
8897
  await loadBasic(tsParticles, false);
8695
8898
  initializing = false;
8696
8899
  initialized = true;
@@ -8709,9 +8912,9 @@ async function fireworks(idOrOptions, sourceOptions) {
8709
8912
  const particlesOptions = {
8710
8913
  detectRetina: true,
8711
8914
  background: {
8712
- color: "#000"
8915
+ color: options.background
8713
8916
  },
8714
- fpsLimit: 120,
8917
+ fpsLimit: 60,
8715
8918
  emitters: {
8716
8919
  direction: "top",
8717
8920
  life: {
@@ -8740,7 +8943,7 @@ async function fireworks(idOrOptions, sourceOptions) {
8740
8943
  value: 0
8741
8944
  },
8742
8945
  color: {
8743
- value: options.colors
8946
+ value: "#fff"
8744
8947
  },
8745
8948
  destroy: {
8746
8949
  mode: "split",
@@ -8761,8 +8964,8 @@ async function fireworks(idOrOptions, sourceOptions) {
8761
8964
  l: options.brightness
8762
8965
  },
8763
8966
  particles: {
8764
- stroke: {
8765
- width: 0
8967
+ color: {
8968
+ value: options.colors
8766
8969
  },
8767
8970
  number: {
8768
8971
  value: 0
@@ -8774,12 +8977,23 @@ async function fireworks(idOrOptions, sourceOptions) {
8774
8977
  },
8775
8978
  animation: {
8776
8979
  enable: true,
8777
- speed: 0.7,
8980
+ speed: 1,
8778
8981
  sync: false,
8779
8982
  startValue: "max",
8780
8983
  destroy: "min"
8781
8984
  }
8782
8985
  },
8986
+ effect: {
8987
+ type: "trail",
8988
+ options: {
8989
+ trail: {
8990
+ length: {
8991
+ min: 5,
8992
+ max: 10
8993
+ }
8994
+ }
8995
+ }
8996
+ },
8783
8997
  shape: {
8784
8998
  type: "circle"
8785
8999
  },
@@ -8827,32 +9041,27 @@ async function fireworks(idOrOptions, sourceOptions) {
8827
9041
  life: {
8828
9042
  count: 1
8829
9043
  },
8830
- shape: {
8831
- type: "line",
9044
+ effect: {
9045
+ type: "trail",
8832
9046
  options: {
8833
- line: {
8834
- cap: "round"
9047
+ trail: {
9048
+ length: {
9049
+ min: 10,
9050
+ max: 30
9051
+ },
9052
+ minWidth: 1,
9053
+ maxWidth: 1
8835
9054
  }
8836
9055
  }
8837
9056
  },
9057
+ shape: {
9058
+ type: "circle"
9059
+ },
8838
9060
  size: {
8839
- value: {
8840
- min: 0.1,
8841
- max: 50
8842
- },
8843
- animation: {
8844
- enable: true,
8845
- sync: true,
8846
- speed: 90,
8847
- startValue: "max",
8848
- destroy: "min"
8849
- }
9061
+ value: 1
8850
9062
  },
8851
- stroke: {
8852
- color: {
8853
- value: "#ffffff"
8854
- },
8855
- width: 0.5
9063
+ opacity: {
9064
+ value: 0.5
8856
9065
  },
8857
9066
  rotate: {
8858
9067
  path: true
@@ -8872,20 +9081,13 @@ async function fireworks(idOrOptions, sourceOptions) {
8872
9081
  outModes: {
8873
9082
  default: "destroy",
8874
9083
  top: "none"
8875
- },
8876
- trail: {
8877
- fill: {
8878
- color: "#000"
8879
- },
8880
- enable: true,
8881
- length: 10
8882
9084
  }
8883
9085
  }
8884
9086
  },
8885
9087
  sounds: {
8886
9088
  enable: options.sounds,
8887
9089
  events: [{
8888
- event: "particleRemoved",
9090
+ event: "particleDestroyed",
8889
9091
  filter: explodeSoundCheck,
8890
9092
  audio: ["https://particles.js.org/audio/explosion0.mp3", "https://particles.js.org/audio/explosion1.mp3", "https://particles.js.org/audio/explosion2.mp3"]
8891
9093
  }],