@tsparticles/preset-ambient 4.0.0-beta.16 → 4.0.0

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.
@@ -1,5 +1,5 @@
1
1
  (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* Preset v4.0.0-beta.16 */
2
+ /* Preset v4.0.0 */
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
5
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -15,7 +15,7 @@
15
15
  b: 0,
16
16
  c: 0,
17
17
  d: 1,
18
- }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity$1 = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
18
+ }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity$1 = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
19
19
 
20
20
  var MoveDirection;
21
21
  (function (MoveDirection) {
@@ -959,7 +959,7 @@
959
959
  }
960
960
  }
961
961
  else {
962
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases[canvasFirstIndex];
962
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
963
963
  if (foundCanvas) {
964
964
  canvasEl = foundCanvas;
965
965
  canvasEl.dataset[generatedAttribute] = generatedFalse;
@@ -996,7 +996,7 @@
996
996
  return this._domArray;
997
997
  }
998
998
  get version() {
999
- return "4.0.0-beta.16";
999
+ return "4.0.0";
1000
1000
  }
1001
1001
  addEventListener(type, listener) {
1002
1002
  this._eventDispatcher.addEventListener(type, listener);
@@ -1027,7 +1027,11 @@
1027
1027
  }
1028
1028
  async load(params) {
1029
1029
  await this.init();
1030
- const { Container } = await Promise.resolve().then(function () { return Container$1; }), id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options, currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container({
1030
+ let domSourceElement;
1031
+ if (typeof HTMLElement !== "undefined" && params.element instanceof HTMLElement) {
1032
+ domSourceElement = params.element;
1033
+ }
1034
+ const { Container } = await Promise.resolve().then(function () { return Container$1; }), id = params.id ?? domSourceElement?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options, currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container({
1031
1035
  dispatchCallback: (eventType, args) => {
1032
1036
  this.dispatchEvent(eventType, args);
1033
1037
  },
@@ -1054,8 +1058,10 @@
1054
1058
  else {
1055
1059
  items.push(newItem);
1056
1060
  }
1057
- const domContainer = getDomContainer(id, params.element), canvasEl = getCanvasFromContainer(domContainer);
1058
- newItem.canvas.loadCanvas(canvasEl);
1061
+ const sourceCanvas = typeof OffscreenCanvas !== "undefined" && params.element instanceof OffscreenCanvas
1062
+ ? params.element
1063
+ : getCanvasFromContainer(getDomContainer(id, domSourceElement));
1064
+ newItem.canvas.loadCanvas(sourceCanvas);
1059
1065
  await newItem.start();
1060
1066
  return newItem;
1061
1067
  }
@@ -2848,7 +2854,7 @@
2848
2854
  }
2849
2855
 
2850
2856
  async function loadCircleShape(engine) {
2851
- engine.checkVersion("4.0.0-beta.16");
2857
+ engine.checkVersion("4.0.0");
2852
2858
  await engine.pluginManager.register(e => {
2853
2859
  e.pluginManager.addShape(["circle"], () => {
2854
2860
  return Promise.resolve(new CircleDrawer());
@@ -2896,7 +2902,7 @@
2896
2902
  }
2897
2903
 
2898
2904
  async function loadHexColorPlugin(engine) {
2899
- engine.checkVersion("4.0.0-beta.16");
2905
+ engine.checkVersion("4.0.0");
2900
2906
  await engine.pluginManager.register(e => {
2901
2907
  e.pluginManager.addColorManager("hex", new HexColorManager());
2902
2908
  });
@@ -2949,7 +2955,7 @@
2949
2955
  }
2950
2956
 
2951
2957
  async function loadHslColorPlugin(engine) {
2952
- engine.checkVersion("4.0.0-beta.16");
2958
+ engine.checkVersion("4.0.0");
2953
2959
  await engine.pluginManager.register(e => {
2954
2960
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2955
2961
  });
@@ -2973,7 +2979,7 @@
2973
2979
  }
2974
2980
 
2975
2981
  async function loadMovePlugin(engine) {
2976
- engine.checkVersion("4.0.0-beta.16");
2982
+ engine.checkVersion("4.0.0");
2977
2983
  await engine.pluginManager.register(e => {
2978
2984
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2979
2985
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -3034,7 +3040,7 @@
3034
3040
  }
3035
3041
 
3036
3042
  async function loadOpacityUpdater(engine) {
3037
- engine.checkVersion("4.0.0-beta.16");
3043
+ engine.checkVersion("4.0.0");
3038
3044
  await engine.pluginManager.register(e => {
3039
3045
  e.pluginManager.addParticleUpdater("opacity", container => {
3040
3046
  return Promise.resolve(new OpacityUpdater(container));
@@ -3386,7 +3392,7 @@
3386
3392
  }
3387
3393
 
3388
3394
  async function loadOutModesUpdater(engine) {
3389
- engine.checkVersion("4.0.0-beta.16");
3395
+ engine.checkVersion("4.0.0");
3390
3396
  await engine.pluginManager.register(e => {
3391
3397
  e.pluginManager.addParticleUpdater("outModes", container => {
3392
3398
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3457,7 +3463,7 @@
3457
3463
  }
3458
3464
 
3459
3465
  async function loadPaintUpdater(engine) {
3460
- engine.checkVersion("4.0.0-beta.16");
3466
+ engine.checkVersion("4.0.0");
3461
3467
  await engine.pluginManager.register(e => {
3462
3468
  e.pluginManager.addParticleUpdater("paint", container => {
3463
3469
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3512,7 +3518,7 @@
3512
3518
  }
3513
3519
 
3514
3520
  async function loadRgbColorPlugin(engine) {
3515
- engine.checkVersion("4.0.0-beta.16");
3521
+ engine.checkVersion("4.0.0");
3516
3522
  await engine.pluginManager.register(e => {
3517
3523
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3518
3524
  });
@@ -3555,7 +3561,7 @@
3555
3561
  }
3556
3562
 
3557
3563
  async function loadSizeUpdater(engine) {
3558
- engine.checkVersion("4.0.0-beta.16");
3564
+ engine.checkVersion("4.0.0");
3559
3565
  await engine.pluginManager.register(e => {
3560
3566
  e.pluginManager.addParticleUpdater("size", container => {
3561
3567
  return Promise.resolve(new SizeUpdater(container));
@@ -3564,7 +3570,7 @@
3564
3570
  }
3565
3571
 
3566
3572
  async function loadBasic(engine) {
3567
- engine.checkVersion("4.0.0-beta.16");
3573
+ engine.checkVersion("4.0.0");
3568
3574
  await engine.pluginManager.register(async (e) => {
3569
3575
  await Promise.all([
3570
3576
  loadHexColorPlugin(e),
@@ -3995,6 +4001,25 @@
3995
4001
  };
3996
4002
  }
3997
4003
 
4004
+ const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
4005
+ const transferredCanvas = transferredCanvases.get(canvas);
4006
+ if (transferredCanvas) {
4007
+ return transferredCanvas;
4008
+ }
4009
+ if (typeof canvas.transferControlToOffscreen !== "function") {
4010
+ throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4011
+ }
4012
+ try {
4013
+ const offscreenCanvas = canvas.transferControlToOffscreen();
4014
+ transferredCanvases.set(canvas, offscreenCanvas);
4015
+ return offscreenCanvas;
4016
+ }
4017
+ catch {
4018
+ throw new TypeError("OffscreenCanvas transfer failed");
4019
+ }
4020
+ }, isHtmlCanvasElement = (canvas) => {
4021
+ return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4022
+ };
3998
4023
  function setStyle(canvas, style, important = false) {
3999
4024
  if (!style) {
4000
4025
  return;
@@ -4025,8 +4050,9 @@
4025
4050
  }
4026
4051
  }
4027
4052
  class CanvasManager {
4028
- element;
4053
+ domElement;
4029
4054
  render;
4055
+ renderCanvas;
4030
4056
  size;
4031
4057
  zoom = defaultZoom;
4032
4058
  _container;
@@ -4061,9 +4087,10 @@
4061
4087
  destroy() {
4062
4088
  this.stop();
4063
4089
  if (this._generated) {
4064
- const element = this.element;
4090
+ const element = this.domElement;
4065
4091
  element?.remove();
4066
- this.element = undefined;
4092
+ this.domElement = undefined;
4093
+ this.renderCanvas = undefined;
4067
4094
  }
4068
4095
  else {
4069
4096
  this._resetOriginalStyle();
@@ -4096,16 +4123,17 @@
4096
4123
  this._initStyle();
4097
4124
  this.initBackground();
4098
4125
  this._safeMutationObserver(obs => {
4099
- if (!this.element || !(this.element instanceof Node)) {
4126
+ const element = this.domElement;
4127
+ if (!element || !(element instanceof Node)) {
4100
4128
  return;
4101
4129
  }
4102
- obs.observe(this.element, { attributes: true });
4130
+ obs.observe(element, { attributes: true });
4103
4131
  });
4104
4132
  this.initPlugins();
4105
4133
  this.render.init();
4106
4134
  }
4107
4135
  initBackground() {
4108
- const { _container } = this, options = _container.actualOptions, background = options.background, element = this.element;
4136
+ const { _container } = this, options = _container.actualOptions, background = options.background, element = this.domElement;
4109
4137
  if (!element) {
4110
4138
  return;
4111
4139
  }
@@ -4130,21 +4158,30 @@
4130
4158
  }
4131
4159
  }
4132
4160
  loadCanvas(canvas) {
4133
- if (this._generated && this.element) {
4134
- this.element.remove();
4161
+ if (this._generated && this.domElement) {
4162
+ this.domElement.remove();
4163
+ }
4164
+ const container = this._container, domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
4165
+ this.domElement = domCanvas;
4166
+ this._generated = domCanvas ? domCanvas.dataset[generatedAttribute] === "true" : false;
4167
+ this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
4168
+ const domElement = this.domElement;
4169
+ if (domElement) {
4170
+ domElement.ariaHidden = "true";
4171
+ this._originalStyle = cloneStyle(domElement.style);
4172
+ }
4173
+ const standardSize = this._standardSize, renderCanvas = this.renderCanvas;
4174
+ if (domElement) {
4175
+ standardSize.height = domElement.offsetHeight;
4176
+ standardSize.width = domElement.offsetWidth;
4177
+ }
4178
+ else {
4179
+ standardSize.height = renderCanvas.height;
4180
+ standardSize.width = renderCanvas.width;
4135
4181
  }
4136
- const container = this._container;
4137
- this._generated =
4138
- generatedAttribute in canvas.dataset ? canvas.dataset[generatedAttribute] === "true" : this._generated;
4139
- this.element = canvas;
4140
- this.element.ariaHidden = "true";
4141
- this._originalStyle = cloneStyle(this.element.style);
4142
- const standardSize = this._standardSize;
4143
- standardSize.height = canvas.offsetHeight;
4144
- standardSize.width = canvas.offsetWidth;
4145
4182
  const pxRatio = this._container.retina.pixelRatio, retinaSize = this.size;
4146
- canvas.height = retinaSize.height = standardSize.height * pxRatio;
4147
- canvas.width = retinaSize.width = standardSize.width * pxRatio;
4183
+ renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
4184
+ renderCanvas.width = retinaSize.width = standardSize.width * pxRatio;
4148
4185
  const canSupportHdrQuery = safeMatchMedia("(color-gamut: p3)");
4149
4186
  this.render.setContextSettings({
4150
4187
  alpha: true,
@@ -4152,42 +4189,48 @@
4152
4189
  desynchronized: true,
4153
4190
  willReadFrequently: false,
4154
4191
  });
4155
- this.render.setContext(this.element.getContext("2d", this.render.settings));
4192
+ this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4156
4193
  this._safeMutationObserver(obs => {
4157
4194
  obs.disconnect();
4158
4195
  });
4159
4196
  container.retina.init();
4160
4197
  this.initBackground();
4161
4198
  this._safeMutationObserver(obs => {
4162
- if (!this.element || !(this.element instanceof Node)) {
4199
+ const element = this.domElement;
4200
+ if (!element || !(element instanceof Node)) {
4163
4201
  return;
4164
4202
  }
4165
- obs.observe(this.element, { attributes: true });
4203
+ obs.observe(element, { attributes: true });
4166
4204
  });
4167
4205
  }
4168
4206
  resize() {
4169
- if (!this.element) {
4207
+ const element = this.domElement;
4208
+ if (!element) {
4209
+ return false;
4210
+ }
4211
+ const container = this._container, renderCanvas = this.renderCanvas;
4212
+ if (renderCanvas === undefined) {
4170
4213
  return false;
4171
4214
  }
4172
- const container = this._container, currentSize = container.canvas._standardSize, newSize = {
4173
- width: this.element.offsetWidth,
4174
- height: this.element.offsetHeight,
4215
+ const currentSize = container.canvas._standardSize, newSize = {
4216
+ width: element.offsetWidth,
4217
+ height: element.offsetHeight,
4175
4218
  }, pxRatio = container.retina.pixelRatio, retinaSize = {
4176
4219
  width: newSize.width * pxRatio,
4177
4220
  height: newSize.height * pxRatio,
4178
4221
  };
4179
4222
  if (newSize.height === currentSize.height &&
4180
4223
  newSize.width === currentSize.width &&
4181
- retinaSize.height === this.element.height &&
4182
- retinaSize.width === this.element.width) {
4224
+ retinaSize.height === renderCanvas.height &&
4225
+ retinaSize.width === renderCanvas.width) {
4183
4226
  return false;
4184
4227
  }
4185
4228
  const oldSize = { ...currentSize };
4186
4229
  currentSize.height = newSize.height;
4187
4230
  currentSize.width = newSize.width;
4188
4231
  const canvasSize = this.size;
4189
- this.element.width = canvasSize.width = retinaSize.width;
4190
- this.element.height = canvasSize.height = retinaSize.height;
4232
+ renderCanvas.width = canvasSize.width = retinaSize.width;
4233
+ renderCanvas.height = canvasSize.height = retinaSize.height;
4191
4234
  if (this._container.started) {
4192
4235
  container.particles.setResizeFactor({
4193
4236
  width: currentSize.width / oldSize.width,
@@ -4197,7 +4240,7 @@
4197
4240
  return true;
4198
4241
  }
4199
4242
  setPointerEvents(type) {
4200
- const element = this.element;
4243
+ const element = this.domElement;
4201
4244
  if (!element) {
4202
4245
  return;
4203
4246
  }
@@ -4216,7 +4259,7 @@
4216
4259
  this.render.stop();
4217
4260
  }
4218
4261
  async windowResize() {
4219
- if (!this.element || !this.resize()) {
4262
+ if (!this.domElement || !this.resize()) {
4220
4263
  return;
4221
4264
  }
4222
4265
  const container = this._container, needsRefresh = container.updateActualOptions();
@@ -4232,7 +4275,7 @@
4232
4275
  }
4233
4276
  };
4234
4277
  _initStyle = () => {
4235
- const element = this.element, options = this._container.actualOptions;
4278
+ const element = this.domElement, options = this._container.actualOptions;
4236
4279
  if (!element) {
4237
4280
  return;
4238
4281
  }
@@ -4254,7 +4297,7 @@
4254
4297
  }
4255
4298
  };
4256
4299
  _repairStyle = () => {
4257
- const element = this.element;
4300
+ const element = this.domElement;
4258
4301
  if (!element) {
4259
4302
  return;
4260
4303
  }
@@ -4274,7 +4317,7 @@
4274
4317
  });
4275
4318
  };
4276
4319
  _resetOriginalStyle = () => {
4277
- const element = this.element, originalStyle = this._originalStyle;
4320
+ const element = this.domElement, originalStyle = this._originalStyle;
4278
4321
  if (!element || !originalStyle) {
4279
4322
  return;
4280
4323
  }
@@ -4287,7 +4330,7 @@
4287
4330
  callback(this._mutationObserver);
4288
4331
  };
4289
4332
  _setFullScreenStyle = () => {
4290
- const element = this.element;
4333
+ const element = this.domElement;
4291
4334
  if (!element) {
4292
4335
  return;
4293
4336
  }
@@ -4361,7 +4404,7 @@
4361
4404
  manageListener(globalThis, resizeEvent, handlers.resize, add);
4362
4405
  return;
4363
4406
  }
4364
- const canvasEl = container.canvas.element;
4407
+ const canvasEl = container.canvas.domElement;
4365
4408
  if (this._resizeObserver && !add) {
4366
4409
  if (canvasEl) {
4367
4410
  this._resizeObserver.unobserve(canvasEl);
@@ -4616,8 +4659,6 @@
4616
4659
  this._initPosition(position);
4617
4660
  this.initialVelocity = this._calculateVelocity();
4618
4661
  this.velocity = this.initialVelocity.copy();
4619
- const particles = container.particles;
4620
- particles.setLastZIndex(this.position.z);
4621
4662
  this.zIndexFactor = this.position.z / container.zLayers;
4622
4663
  this.sides = 24;
4623
4664
  let effectDrawer, shapeDrawer;
@@ -4767,7 +4808,7 @@
4767
4808
  return color;
4768
4809
  };
4769
4810
  _initPosition = position => {
4770
- const container = this._container, zIndexValue = getRangeValue(this.options.zIndex.value), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4811
+ const container = this._container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4771
4812
  if (!initialPosition) {
4772
4813
  throw new Error("a valid position cannot be found for particle");
4773
4814
  }
@@ -4901,10 +4942,8 @@
4901
4942
  _container;
4902
4943
  _groupLimits;
4903
4944
  _limit;
4904
- _maxZIndex;
4905
- _minZIndex;
4906
- _needsSort;
4907
4945
  _nextId;
4946
+ _particleBuckets;
4908
4947
  _particleResetPlugins;
4909
4948
  _particleUpdatePlugins;
4910
4949
  _pluginManager;
@@ -4913,19 +4952,17 @@
4913
4952
  _postUpdatePlugins;
4914
4953
  _resizeFactor;
4915
4954
  _updatePlugins;
4916
- _zArray;
4955
+ _zBuckets;
4917
4956
  constructor(pluginManager, container) {
4918
4957
  this._pluginManager = pluginManager;
4919
4958
  this._container = container;
4920
4959
  this._nextId = 0;
4921
4960
  this._array = [];
4922
- this._zArray = [];
4923
4961
  this._pool = [];
4924
4962
  this._limit = 0;
4925
4963
  this._groupLimits = new Map();
4926
- this._needsSort = false;
4927
- this._minZIndex = 0;
4928
- this._maxZIndex = 0;
4964
+ this._particleBuckets = new Map();
4965
+ this._zBuckets = this._createBuckets(this._container.zLayers);
4929
4966
  this.grid = new SpatialHashGrid(spatialHashGridCellSize);
4930
4967
  this.checkParticlePositionPlugins = [];
4931
4968
  this._particleResetPlugins = [];
@@ -4967,7 +5004,7 @@
4967
5004
  return;
4968
5005
  }
4969
5006
  this._array.push(particle);
4970
- this._zArray.push(particle);
5007
+ this._insertParticleIntoBucket(particle);
4971
5008
  this._nextId++;
4972
5009
  this._container.dispatchEvent(EventType.particleAdded, {
4973
5010
  particle,
@@ -4981,12 +5018,14 @@
4981
5018
  }
4982
5019
  clear() {
4983
5020
  this._array = [];
4984
- this._zArray = [];
5021
+ this._particleBuckets.clear();
5022
+ this._resetBuckets(this._container.zLayers);
4985
5023
  }
4986
5024
  destroy() {
4987
5025
  this._array = [];
4988
5026
  this._pool.length = 0;
4989
- this._zArray = [];
5027
+ this._particleBuckets.clear();
5028
+ this._zBuckets = [];
4990
5029
  this.checkParticlePositionPlugins = [];
4991
5030
  this._particleResetPlugins = [];
4992
5031
  this._particleUpdatePlugins = [];
@@ -4995,8 +5034,14 @@
4995
5034
  this._updatePlugins = [];
4996
5035
  }
4997
5036
  drawParticles(delta) {
4998
- for (const particle of this._zArray) {
4999
- particle.draw(delta);
5037
+ for (let i = this._zBuckets.length - one; i >= minIndex; i--) {
5038
+ const bucket = this._zBuckets[i];
5039
+ if (!bucket) {
5040
+ continue;
5041
+ }
5042
+ for (const particle of bucket) {
5043
+ particle.draw(delta);
5044
+ }
5000
5045
  }
5001
5046
  }
5002
5047
  filter(condition) {
@@ -5010,15 +5055,14 @@
5010
5055
  }
5011
5056
  async init() {
5012
5057
  const container = this._container, options = container.actualOptions;
5013
- this._minZIndex = 0;
5014
- this._maxZIndex = 0;
5015
- this._needsSort = false;
5016
5058
  this.checkParticlePositionPlugins = [];
5017
5059
  this._updatePlugins = [];
5018
5060
  this._particleUpdatePlugins = [];
5019
5061
  this._postUpdatePlugins = [];
5020
5062
  this._particleResetPlugins = [];
5021
5063
  this._postParticleUpdatePlugins = [];
5064
+ this._particleBuckets.clear();
5065
+ this._resetBuckets(container.zLayers);
5022
5066
  this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5023
5067
  for (const plugin of container.plugins) {
5024
5068
  if (plugin.redrawInit) {
@@ -5119,79 +5163,25 @@
5119
5163
  }
5120
5164
  this._applyDensity(options.particles, pluginsCount);
5121
5165
  }
5122
- setLastZIndex(zIndex) {
5123
- this._needsSort ||= zIndex >= this._maxZIndex || (zIndex > this._minZIndex && zIndex < this._maxZIndex);
5124
- }
5125
5166
  setResizeFactor(factor) {
5126
5167
  this._resizeFactor = factor;
5127
5168
  }
5128
5169
  update(delta) {
5129
- const particlesToDelete = new Set();
5130
5170
  this.grid.clear();
5131
5171
  for (const plugin of this._updatePlugins) {
5132
5172
  plugin.update?.(delta);
5133
5173
  }
5134
- const resizeFactor = this._resizeFactor;
5135
- for (const particle of this._array) {
5136
- if (resizeFactor && !particle.ignoresResizeRatio) {
5137
- particle.position.x *= resizeFactor.width;
5138
- particle.position.y *= resizeFactor.height;
5139
- particle.initialPosition.x *= resizeFactor.width;
5140
- particle.initialPosition.y *= resizeFactor.height;
5141
- }
5142
- particle.ignoresResizeRatio = false;
5143
- for (const plugin of this._particleResetPlugins) {
5144
- plugin.particleReset?.(particle);
5145
- }
5146
- for (const plugin of this._particleUpdatePlugins) {
5147
- if (particle.destroyed) {
5148
- break;
5149
- }
5150
- plugin.particleUpdate?.(particle, delta);
5151
- }
5152
- if (particle.destroyed) {
5153
- particlesToDelete.add(particle);
5154
- continue;
5155
- }
5156
- this.grid.insert(particle);
5157
- }
5174
+ const particlesToDelete = this._updateParticlesPhase1(delta);
5158
5175
  for (const plugin of this._postUpdatePlugins) {
5159
5176
  plugin.postUpdate?.(delta);
5160
5177
  }
5161
- for (const particle of this._array) {
5162
- if (particle.destroyed) {
5163
- particlesToDelete.add(particle);
5164
- continue;
5165
- }
5166
- for (const updater of this._container.particleUpdaters) {
5167
- updater.update(particle, delta);
5168
- }
5169
- if (!particle.destroyed && !particle.spawning) {
5170
- for (const plugin of this._postParticleUpdatePlugins) {
5171
- plugin.postParticleUpdate?.(particle, delta);
5172
- }
5173
- }
5174
- else if (particle.destroyed) {
5175
- particlesToDelete.add(particle);
5176
- }
5177
- }
5178
+ this._updateParticlesPhase2(delta, particlesToDelete);
5178
5179
  if (particlesToDelete.size) {
5179
5180
  for (const particle of particlesToDelete) {
5180
5181
  this.remove(particle);
5181
5182
  }
5182
5183
  }
5183
5184
  delete this._resizeFactor;
5184
- if (this._needsSort) {
5185
- const zArray = this._zArray;
5186
- zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
5187
- const firstItem = zArray[minIndex], lastItem = zArray[zArray.length - lengthOffset];
5188
- if (!firstItem || !lastItem) {
5189
- return;
5190
- }
5191
- this._maxZIndex = firstItem.position.z;
5192
- this._minZIndex = lastItem.position.z;
5193
- this._needsSort = false;
5194
- }
5195
5185
  }
5196
5186
  _addToPool = (...particles) => {
5197
5187
  this._pool.push(...particles);
@@ -5221,13 +5211,52 @@
5221
5211
  this.removeQuantity(particlesCount - particlesNumber, group);
5222
5212
  }
5223
5213
  };
5214
+ _createBuckets = (zLayers) => {
5215
+ const bucketCount = Math.max(Math.floor(zLayers), one);
5216
+ return Array.from({ length: bucketCount }, () => []);
5217
+ };
5218
+ _getBucketIndex = (zIndex) => {
5219
+ const maxBucketIndex = this._zBuckets.length - one;
5220
+ if (maxBucketIndex <= minIndex) {
5221
+ return minIndex;
5222
+ }
5223
+ return Math.min(Math.max(Math.floor(zIndex), minIndex), maxBucketIndex);
5224
+ };
5225
+ _getParticleInsertIndex = (bucket, particleId) => {
5226
+ let start = minIndex, end = bucket.length;
5227
+ while (start < end) {
5228
+ const middle = Math.floor((start + end) / double), middleParticle = bucket[middle];
5229
+ if (!middleParticle) {
5230
+ end = middle;
5231
+ continue;
5232
+ }
5233
+ if (middleParticle.id < particleId) {
5234
+ start = middle + one;
5235
+ }
5236
+ else {
5237
+ end = middle;
5238
+ }
5239
+ }
5240
+ return start;
5241
+ };
5224
5242
  _initDensityFactor = densityOptions => {
5225
5243
  const container = this._container;
5226
- if (!container.canvas.element || !densityOptions.enable) {
5244
+ if (!densityOptions.enable) {
5245
+ return defaultDensityFactor;
5246
+ }
5247
+ const canvasSize = container.canvas.size, pxRatio = container.retina.pixelRatio;
5248
+ if (!canvasSize.width || !canvasSize.height) {
5227
5249
  return defaultDensityFactor;
5228
5250
  }
5229
- const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio;
5230
- return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp);
5251
+ return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5252
+ };
5253
+ _insertParticleIntoBucket = (particle) => {
5254
+ const bucketIndex = this._getBucketIndex(particle.position.z), bucket = this._zBuckets[bucketIndex];
5255
+ if (!bucket) {
5256
+ return;
5257
+ }
5258
+ bucket.splice(this._getParticleInsertIndex(bucket, particle.id), empty, particle);
5259
+ this._particleBuckets.set(particle.id, bucketIndex);
5231
5260
  };
5232
5261
  _removeParticle = (index, group, override) => {
5233
5262
  const particle = this._array[index];
@@ -5237,9 +5266,8 @@
5237
5266
  if (particle.group !== group) {
5238
5267
  return false;
5239
5268
  }
5240
- const zIdx = this._zArray.indexOf(particle);
5241
5269
  this._array.splice(index, deleteCount);
5242
- this._zArray.splice(zIdx, deleteCount);
5270
+ this._removeParticleFromBucket(particle);
5243
5271
  particle.destroy(override);
5244
5272
  this._container.dispatchEvent(EventType.particleRemoved, {
5245
5273
  particle,
@@ -5247,6 +5275,98 @@
5247
5275
  this._addToPool(particle);
5248
5276
  return true;
5249
5277
  };
5278
+ _removeParticleFromBucket = (particle) => {
5279
+ const bucketIndex = this._particleBuckets.get(particle.id) ?? this._getBucketIndex(particle.position.z), bucket = this._zBuckets[bucketIndex];
5280
+ if (!bucket) {
5281
+ this._particleBuckets.delete(particle.id);
5282
+ return;
5283
+ }
5284
+ const particleIndex = this._getParticleInsertIndex(bucket, particle.id);
5285
+ if (bucket[particleIndex]?.id !== particle.id) {
5286
+ this._particleBuckets.delete(particle.id);
5287
+ return;
5288
+ }
5289
+ bucket.splice(particleIndex, deleteCount);
5290
+ this._particleBuckets.delete(particle.id);
5291
+ };
5292
+ _resetBuckets = (zLayers) => {
5293
+ const bucketCount = Math.max(Math.floor(zLayers), one);
5294
+ if (this._zBuckets.length !== bucketCount) {
5295
+ this._zBuckets = this._createBuckets(bucketCount);
5296
+ return;
5297
+ }
5298
+ for (const bucket of this._zBuckets) {
5299
+ bucket.length = minIndex;
5300
+ }
5301
+ };
5302
+ _updateParticleBucket = (particle) => {
5303
+ const newBucketIndex = this._getBucketIndex(particle.position.z), currentBucketIndex = this._particleBuckets.get(particle.id);
5304
+ if (currentBucketIndex === undefined) {
5305
+ this._insertParticleIntoBucket(particle);
5306
+ return;
5307
+ }
5308
+ if (currentBucketIndex === newBucketIndex) {
5309
+ return;
5310
+ }
5311
+ const currentBucket = this._zBuckets[currentBucketIndex];
5312
+ if (currentBucket) {
5313
+ const particleIndex = this._getParticleInsertIndex(currentBucket, particle.id);
5314
+ if (currentBucket[particleIndex]?.id === particle.id) {
5315
+ currentBucket.splice(particleIndex, deleteCount);
5316
+ }
5317
+ }
5318
+ const newBucket = this._zBuckets[newBucketIndex];
5319
+ if (!newBucket) {
5320
+ this._particleBuckets.set(particle.id, newBucketIndex);
5321
+ return;
5322
+ }
5323
+ newBucket.splice(this._getParticleInsertIndex(newBucket, particle.id), empty, particle);
5324
+ this._particleBuckets.set(particle.id, newBucketIndex);
5325
+ };
5326
+ _updateParticlesPhase1 = (delta) => {
5327
+ const particlesToDelete = new Set(), resizeFactor = this._resizeFactor;
5328
+ for (const particle of this._array) {
5329
+ if (resizeFactor && !particle.ignoresResizeRatio) {
5330
+ particle.position.x *= resizeFactor.width;
5331
+ particle.position.y *= resizeFactor.height;
5332
+ particle.initialPosition.x *= resizeFactor.width;
5333
+ particle.initialPosition.y *= resizeFactor.height;
5334
+ }
5335
+ particle.ignoresResizeRatio = false;
5336
+ for (const plugin of this._particleResetPlugins) {
5337
+ plugin.particleReset?.(particle);
5338
+ }
5339
+ for (const plugin of this._particleUpdatePlugins) {
5340
+ if (particle.destroyed) {
5341
+ break;
5342
+ }
5343
+ plugin.particleUpdate?.(particle, delta);
5344
+ }
5345
+ if (particle.destroyed) {
5346
+ particlesToDelete.add(particle);
5347
+ continue;
5348
+ }
5349
+ this.grid.insert(particle);
5350
+ }
5351
+ return particlesToDelete;
5352
+ };
5353
+ _updateParticlesPhase2 = (delta, particlesToDelete) => {
5354
+ for (const particle of this._array) {
5355
+ if (particle.destroyed) {
5356
+ particlesToDelete.add(particle);
5357
+ continue;
5358
+ }
5359
+ for (const updater of this._container.particleUpdaters) {
5360
+ updater.update(particle, delta);
5361
+ }
5362
+ if (!particle.spawning) {
5363
+ for (const plugin of this._postParticleUpdatePlugins) {
5364
+ plugin.postParticleUpdate?.(particle, delta);
5365
+ }
5366
+ }
5367
+ this._updateParticleBucket(particle);
5368
+ }
5369
+ };
5250
5370
  }
5251
5371
 
5252
5372
  class Retina {
@@ -5262,9 +5382,8 @@
5262
5382
  const container = this.container, options = container.actualOptions;
5263
5383
  this.pixelRatio = options.detectRetina ? devicePixelRatio : defaultRatio;
5264
5384
  this.reduceFactor = defaultReduceFactor;
5265
- const ratio = this.pixelRatio, canvas = container.canvas;
5266
- if (canvas.element) {
5267
- const element = canvas.element;
5385
+ const ratio = this.pixelRatio, canvas = container.canvas, element = canvas.domElement;
5386
+ if (element) {
5268
5387
  canvas.size.width = element.offsetWidth * ratio;
5269
5388
  canvas.size.height = element.offsetHeight * ratio;
5270
5389
  }