@tsparticles/basic 4.0.0-beta.15 → 4.0.0-beta.17

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
- /* tsParticles v4.0.0-beta.15 */
2
+ /* tsParticles v4.0.0-beta.17 */
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) :
@@ -1081,7 +1081,7 @@
1081
1081
  }
1082
1082
  }
1083
1083
  else {
1084
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases[canvasFirstIndex];
1084
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
1085
1085
  if (foundCanvas) {
1086
1086
  canvasEl = foundCanvas;
1087
1087
  canvasEl.dataset[generatedAttribute] = generatedFalse;
@@ -1118,7 +1118,7 @@
1118
1118
  return this._domArray;
1119
1119
  }
1120
1120
  get version() {
1121
- return "4.0.0-beta.15";
1121
+ return "4.0.0-beta.17";
1122
1122
  }
1123
1123
  addEventListener(type, listener) {
1124
1124
  this._eventDispatcher.addEventListener(type, listener);
@@ -1149,7 +1149,11 @@
1149
1149
  }
1150
1150
  async load(params) {
1151
1151
  await this.init();
1152
- 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({
1152
+ let domSourceElement;
1153
+ if (typeof HTMLElement !== "undefined" && params.element instanceof HTMLElement) {
1154
+ domSourceElement = params.element;
1155
+ }
1156
+ 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({
1153
1157
  dispatchCallback: (eventType, args) => {
1154
1158
  this.dispatchEvent(eventType, args);
1155
1159
  },
@@ -1176,8 +1180,10 @@
1176
1180
  else {
1177
1181
  items.push(newItem);
1178
1182
  }
1179
- const domContainer = getDomContainer(id, params.element), canvasEl = getCanvasFromContainer(domContainer);
1180
- newItem.canvas.loadCanvas(canvasEl);
1183
+ const sourceCanvas = typeof OffscreenCanvas !== "undefined" && params.element instanceof OffscreenCanvas
1184
+ ? params.element
1185
+ : getCanvasFromContainer(getDomContainer(id, domSourceElement));
1186
+ newItem.canvas.loadCanvas(sourceCanvas);
1181
1187
  await newItem.start();
1182
1188
  return newItem;
1183
1189
  }
@@ -3034,7 +3040,7 @@
3034
3040
  }
3035
3041
 
3036
3042
  async function loadCircleShape(engine) {
3037
- engine.checkVersion("4.0.0-beta.15");
3043
+ engine.checkVersion("4.0.0-beta.17");
3038
3044
  await engine.pluginManager.register(e => {
3039
3045
  e.pluginManager.addShape(["circle"], () => {
3040
3046
  return Promise.resolve(new CircleDrawer());
@@ -3082,7 +3088,7 @@
3082
3088
  }
3083
3089
 
3084
3090
  async function loadHexColorPlugin(engine) {
3085
- engine.checkVersion("4.0.0-beta.15");
3091
+ engine.checkVersion("4.0.0-beta.17");
3086
3092
  await engine.pluginManager.register(e => {
3087
3093
  e.pluginManager.addColorManager("hex", new HexColorManager());
3088
3094
  });
@@ -3135,7 +3141,7 @@
3135
3141
  }
3136
3142
 
3137
3143
  async function loadHslColorPlugin(engine) {
3138
- engine.checkVersion("4.0.0-beta.15");
3144
+ engine.checkVersion("4.0.0-beta.17");
3139
3145
  await engine.pluginManager.register(e => {
3140
3146
  e.pluginManager.addColorManager("hsl", new HslColorManager());
3141
3147
  });
@@ -3159,7 +3165,7 @@
3159
3165
  }
3160
3166
 
3161
3167
  async function loadMovePlugin(engine) {
3162
- engine.checkVersion("4.0.0-beta.15");
3168
+ engine.checkVersion("4.0.0-beta.17");
3163
3169
  await engine.pluginManager.register(e => {
3164
3170
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
3165
3171
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -3220,7 +3226,7 @@
3220
3226
  }
3221
3227
 
3222
3228
  async function loadOpacityUpdater(engine) {
3223
- engine.checkVersion("4.0.0-beta.15");
3229
+ engine.checkVersion("4.0.0-beta.17");
3224
3230
  await engine.pluginManager.register(e => {
3225
3231
  e.pluginManager.addParticleUpdater("opacity", container => {
3226
3232
  return Promise.resolve(new OpacityUpdater(container));
@@ -3572,7 +3578,7 @@
3572
3578
  }
3573
3579
 
3574
3580
  async function loadOutModesUpdater(engine) {
3575
- engine.checkVersion("4.0.0-beta.15");
3581
+ engine.checkVersion("4.0.0-beta.17");
3576
3582
  await engine.pluginManager.register(e => {
3577
3583
  e.pluginManager.addParticleUpdater("outModes", container => {
3578
3584
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3643,7 +3649,7 @@
3643
3649
  }
3644
3650
 
3645
3651
  async function loadPaintUpdater(engine) {
3646
- engine.checkVersion("4.0.0-beta.15");
3652
+ engine.checkVersion("4.0.0-beta.17");
3647
3653
  await engine.pluginManager.register(e => {
3648
3654
  e.pluginManager.addParticleUpdater("paint", container => {
3649
3655
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3698,7 +3704,7 @@
3698
3704
  }
3699
3705
 
3700
3706
  async function loadRgbColorPlugin(engine) {
3701
- engine.checkVersion("4.0.0-beta.15");
3707
+ engine.checkVersion("4.0.0-beta.17");
3702
3708
  await engine.pluginManager.register(e => {
3703
3709
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3704
3710
  });
@@ -3741,7 +3747,7 @@
3741
3747
  }
3742
3748
 
3743
3749
  async function loadSizeUpdater(engine) {
3744
- engine.checkVersion("4.0.0-beta.15");
3750
+ engine.checkVersion("4.0.0-beta.17");
3745
3751
  await engine.pluginManager.register(e => {
3746
3752
  e.pluginManager.addParticleUpdater("size", container => {
3747
3753
  return Promise.resolve(new SizeUpdater(container));
@@ -3750,7 +3756,7 @@
3750
3756
  }
3751
3757
 
3752
3758
  async function loadBasic(engine) {
3753
- engine.checkVersion("4.0.0-beta.15");
3759
+ engine.checkVersion("4.0.0-beta.17");
3754
3760
  await engine.pluginManager.register(async (e) => {
3755
3761
  await Promise.all([
3756
3762
  loadHexColorPlugin(e),
@@ -4071,6 +4077,25 @@
4071
4077
  };
4072
4078
  }
4073
4079
 
4080
+ const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
4081
+ const transferredCanvas = transferredCanvases.get(canvas);
4082
+ if (transferredCanvas) {
4083
+ return transferredCanvas;
4084
+ }
4085
+ if (typeof canvas.transferControlToOffscreen !== "function") {
4086
+ throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4087
+ }
4088
+ try {
4089
+ const offscreenCanvas = canvas.transferControlToOffscreen();
4090
+ transferredCanvases.set(canvas, offscreenCanvas);
4091
+ return offscreenCanvas;
4092
+ }
4093
+ catch {
4094
+ throw new TypeError("OffscreenCanvas transfer failed");
4095
+ }
4096
+ }, isHtmlCanvasElement = (canvas) => {
4097
+ return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4098
+ };
4074
4099
  function setStyle(canvas, style, important = false) {
4075
4100
  if (!style) {
4076
4101
  return;
@@ -4101,8 +4126,9 @@
4101
4126
  }
4102
4127
  }
4103
4128
  class CanvasManager {
4104
- element;
4129
+ domElement;
4105
4130
  render;
4131
+ renderCanvas;
4106
4132
  size;
4107
4133
  zoom = defaultZoom;
4108
4134
  _container;
@@ -4137,9 +4163,10 @@
4137
4163
  destroy() {
4138
4164
  this.stop();
4139
4165
  if (this._generated) {
4140
- const element = this.element;
4166
+ const element = this.domElement;
4141
4167
  element?.remove();
4142
- this.element = undefined;
4168
+ this.domElement = undefined;
4169
+ this.renderCanvas = undefined;
4143
4170
  }
4144
4171
  else {
4145
4172
  this._resetOriginalStyle();
@@ -4172,16 +4199,17 @@
4172
4199
  this._initStyle();
4173
4200
  this.initBackground();
4174
4201
  this._safeMutationObserver(obs => {
4175
- if (!this.element || !(this.element instanceof Node)) {
4202
+ const element = this.domElement;
4203
+ if (!element || !(element instanceof Node)) {
4176
4204
  return;
4177
4205
  }
4178
- obs.observe(this.element, { attributes: true });
4206
+ obs.observe(element, { attributes: true });
4179
4207
  });
4180
4208
  this.initPlugins();
4181
4209
  this.render.init();
4182
4210
  }
4183
4211
  initBackground() {
4184
- const { _container } = this, options = _container.actualOptions, background = options.background, element = this.element;
4212
+ const { _container } = this, options = _container.actualOptions, background = options.background, element = this.domElement;
4185
4213
  if (!element) {
4186
4214
  return;
4187
4215
  }
@@ -4206,21 +4234,30 @@
4206
4234
  }
4207
4235
  }
4208
4236
  loadCanvas(canvas) {
4209
- if (this._generated && this.element) {
4210
- this.element.remove();
4237
+ if (this._generated && this.domElement) {
4238
+ this.domElement.remove();
4239
+ }
4240
+ const container = this._container, domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
4241
+ this.domElement = domCanvas;
4242
+ this._generated = domCanvas ? domCanvas.dataset[generatedAttribute] === "true" : false;
4243
+ this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
4244
+ const domElement = this.domElement;
4245
+ if (domElement) {
4246
+ domElement.ariaHidden = "true";
4247
+ this._originalStyle = cloneStyle(domElement.style);
4248
+ }
4249
+ const standardSize = this._standardSize, renderCanvas = this.renderCanvas;
4250
+ if (domElement) {
4251
+ standardSize.height = domElement.offsetHeight;
4252
+ standardSize.width = domElement.offsetWidth;
4253
+ }
4254
+ else {
4255
+ standardSize.height = renderCanvas.height;
4256
+ standardSize.width = renderCanvas.width;
4211
4257
  }
4212
- const container = this._container;
4213
- this._generated =
4214
- generatedAttribute in canvas.dataset ? canvas.dataset[generatedAttribute] === "true" : this._generated;
4215
- this.element = canvas;
4216
- this.element.ariaHidden = "true";
4217
- this._originalStyle = cloneStyle(this.element.style);
4218
- const standardSize = this._standardSize;
4219
- standardSize.height = canvas.offsetHeight;
4220
- standardSize.width = canvas.offsetWidth;
4221
4258
  const pxRatio = this._container.retina.pixelRatio, retinaSize = this.size;
4222
- canvas.height = retinaSize.height = standardSize.height * pxRatio;
4223
- canvas.width = retinaSize.width = standardSize.width * pxRatio;
4259
+ renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
4260
+ renderCanvas.width = retinaSize.width = standardSize.width * pxRatio;
4224
4261
  const canSupportHdrQuery = safeMatchMedia("(color-gamut: p3)");
4225
4262
  this.render.setContextSettings({
4226
4263
  alpha: true,
@@ -4228,42 +4265,48 @@
4228
4265
  desynchronized: true,
4229
4266
  willReadFrequently: false,
4230
4267
  });
4231
- this.render.setContext(this.element.getContext("2d", this.render.settings));
4268
+ this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4232
4269
  this._safeMutationObserver(obs => {
4233
4270
  obs.disconnect();
4234
4271
  });
4235
4272
  container.retina.init();
4236
4273
  this.initBackground();
4237
4274
  this._safeMutationObserver(obs => {
4238
- if (!this.element || !(this.element instanceof Node)) {
4275
+ const element = this.domElement;
4276
+ if (!element || !(element instanceof Node)) {
4239
4277
  return;
4240
4278
  }
4241
- obs.observe(this.element, { attributes: true });
4279
+ obs.observe(element, { attributes: true });
4242
4280
  });
4243
4281
  }
4244
4282
  resize() {
4245
- if (!this.element) {
4283
+ const element = this.domElement;
4284
+ if (!element) {
4285
+ return false;
4286
+ }
4287
+ const container = this._container, renderCanvas = this.renderCanvas;
4288
+ if (renderCanvas === undefined) {
4246
4289
  return false;
4247
4290
  }
4248
- const container = this._container, currentSize = container.canvas._standardSize, newSize = {
4249
- width: this.element.offsetWidth,
4250
- height: this.element.offsetHeight,
4291
+ const currentSize = container.canvas._standardSize, newSize = {
4292
+ width: element.offsetWidth,
4293
+ height: element.offsetHeight,
4251
4294
  }, pxRatio = container.retina.pixelRatio, retinaSize = {
4252
4295
  width: newSize.width * pxRatio,
4253
4296
  height: newSize.height * pxRatio,
4254
4297
  };
4255
4298
  if (newSize.height === currentSize.height &&
4256
4299
  newSize.width === currentSize.width &&
4257
- retinaSize.height === this.element.height &&
4258
- retinaSize.width === this.element.width) {
4300
+ retinaSize.height === renderCanvas.height &&
4301
+ retinaSize.width === renderCanvas.width) {
4259
4302
  return false;
4260
4303
  }
4261
4304
  const oldSize = { ...currentSize };
4262
4305
  currentSize.height = newSize.height;
4263
4306
  currentSize.width = newSize.width;
4264
4307
  const canvasSize = this.size;
4265
- this.element.width = canvasSize.width = retinaSize.width;
4266
- this.element.height = canvasSize.height = retinaSize.height;
4308
+ renderCanvas.width = canvasSize.width = retinaSize.width;
4309
+ renderCanvas.height = canvasSize.height = retinaSize.height;
4267
4310
  if (this._container.started) {
4268
4311
  container.particles.setResizeFactor({
4269
4312
  width: currentSize.width / oldSize.width,
@@ -4273,7 +4316,7 @@
4273
4316
  return true;
4274
4317
  }
4275
4318
  setPointerEvents(type) {
4276
- const element = this.element;
4319
+ const element = this.domElement;
4277
4320
  if (!element) {
4278
4321
  return;
4279
4322
  }
@@ -4292,7 +4335,7 @@
4292
4335
  this.render.stop();
4293
4336
  }
4294
4337
  async windowResize() {
4295
- if (!this.element || !this.resize()) {
4338
+ if (!this.domElement || !this.resize()) {
4296
4339
  return;
4297
4340
  }
4298
4341
  const container = this._container, needsRefresh = container.updateActualOptions();
@@ -4308,7 +4351,7 @@
4308
4351
  }
4309
4352
  };
4310
4353
  _initStyle = () => {
4311
- const element = this.element, options = this._container.actualOptions;
4354
+ const element = this.domElement, options = this._container.actualOptions;
4312
4355
  if (!element) {
4313
4356
  return;
4314
4357
  }
@@ -4330,7 +4373,7 @@
4330
4373
  }
4331
4374
  };
4332
4375
  _repairStyle = () => {
4333
- const element = this.element;
4376
+ const element = this.domElement;
4334
4377
  if (!element) {
4335
4378
  return;
4336
4379
  }
@@ -4350,7 +4393,7 @@
4350
4393
  });
4351
4394
  };
4352
4395
  _resetOriginalStyle = () => {
4353
- const element = this.element, originalStyle = this._originalStyle;
4396
+ const element = this.domElement, originalStyle = this._originalStyle;
4354
4397
  if (!element || !originalStyle) {
4355
4398
  return;
4356
4399
  }
@@ -4363,7 +4406,7 @@
4363
4406
  callback(this._mutationObserver);
4364
4407
  };
4365
4408
  _setFullScreenStyle = () => {
4366
- const element = this.element;
4409
+ const element = this.domElement;
4367
4410
  if (!element) {
4368
4411
  return;
4369
4412
  }
@@ -4437,7 +4480,7 @@
4437
4480
  manageListener(globalThis, resizeEvent, handlers.resize, add);
4438
4481
  return;
4439
4482
  }
4440
- const canvasEl = container.canvas.element;
4483
+ const canvasEl = container.canvas.domElement;
4441
4484
  if (this._resizeObserver && !add) {
4442
4485
  if (canvasEl) {
4443
4486
  this._resizeObserver.unobserve(canvasEl);
@@ -4692,8 +4735,6 @@
4692
4735
  this._initPosition(position);
4693
4736
  this.initialVelocity = this._calculateVelocity();
4694
4737
  this.velocity = this.initialVelocity.copy();
4695
- const particles = container.particles;
4696
- particles.setLastZIndex(this.position.z);
4697
4738
  this.zIndexFactor = this.position.z / container.zLayers;
4698
4739
  this.sides = 24;
4699
4740
  let effectDrawer, shapeDrawer;
@@ -4843,7 +4884,7 @@
4843
4884
  return color;
4844
4885
  };
4845
4886
  _initPosition = position => {
4846
- const container = this._container, zIndexValue = getRangeValue(this.options.zIndex.value), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4887
+ const container = this._container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4847
4888
  if (!initialPosition) {
4848
4889
  throw new Error("a valid position cannot be found for particle");
4849
4890
  }
@@ -4977,10 +5018,8 @@
4977
5018
  _container;
4978
5019
  _groupLimits;
4979
5020
  _limit;
4980
- _maxZIndex;
4981
- _minZIndex;
4982
- _needsSort;
4983
5021
  _nextId;
5022
+ _particleBuckets;
4984
5023
  _particleResetPlugins;
4985
5024
  _particleUpdatePlugins;
4986
5025
  _pluginManager;
@@ -4989,19 +5028,17 @@
4989
5028
  _postUpdatePlugins;
4990
5029
  _resizeFactor;
4991
5030
  _updatePlugins;
4992
- _zArray;
5031
+ _zBuckets;
4993
5032
  constructor(pluginManager, container) {
4994
5033
  this._pluginManager = pluginManager;
4995
5034
  this._container = container;
4996
5035
  this._nextId = 0;
4997
5036
  this._array = [];
4998
- this._zArray = [];
4999
5037
  this._pool = [];
5000
5038
  this._limit = 0;
5001
5039
  this._groupLimits = new Map();
5002
- this._needsSort = false;
5003
- this._minZIndex = 0;
5004
- this._maxZIndex = 0;
5040
+ this._particleBuckets = new Map();
5041
+ this._zBuckets = this._createBuckets(this._container.zLayers);
5005
5042
  this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5006
5043
  this.checkParticlePositionPlugins = [];
5007
5044
  this._particleResetPlugins = [];
@@ -5043,7 +5080,7 @@
5043
5080
  return;
5044
5081
  }
5045
5082
  this._array.push(particle);
5046
- this._zArray.push(particle);
5083
+ this._insertParticleIntoBucket(particle);
5047
5084
  this._nextId++;
5048
5085
  this._container.dispatchEvent(exports.EventType.particleAdded, {
5049
5086
  particle,
@@ -5057,12 +5094,14 @@
5057
5094
  }
5058
5095
  clear() {
5059
5096
  this._array = [];
5060
- this._zArray = [];
5097
+ this._particleBuckets.clear();
5098
+ this._resetBuckets(this._container.zLayers);
5061
5099
  }
5062
5100
  destroy() {
5063
5101
  this._array = [];
5064
5102
  this._pool.length = 0;
5065
- this._zArray = [];
5103
+ this._particleBuckets.clear();
5104
+ this._zBuckets = [];
5066
5105
  this.checkParticlePositionPlugins = [];
5067
5106
  this._particleResetPlugins = [];
5068
5107
  this._particleUpdatePlugins = [];
@@ -5071,8 +5110,14 @@
5071
5110
  this._updatePlugins = [];
5072
5111
  }
5073
5112
  drawParticles(delta) {
5074
- for (const particle of this._zArray) {
5075
- particle.draw(delta);
5113
+ for (let i = this._zBuckets.length - one; i >= minIndex; i--) {
5114
+ const bucket = this._zBuckets[i];
5115
+ if (!bucket) {
5116
+ continue;
5117
+ }
5118
+ for (const particle of bucket) {
5119
+ particle.draw(delta);
5120
+ }
5076
5121
  }
5077
5122
  }
5078
5123
  filter(condition) {
@@ -5086,15 +5131,14 @@
5086
5131
  }
5087
5132
  async init() {
5088
5133
  const container = this._container, options = container.actualOptions;
5089
- this._minZIndex = 0;
5090
- this._maxZIndex = 0;
5091
- this._needsSort = false;
5092
5134
  this.checkParticlePositionPlugins = [];
5093
5135
  this._updatePlugins = [];
5094
5136
  this._particleUpdatePlugins = [];
5095
5137
  this._postUpdatePlugins = [];
5096
5138
  this._particleResetPlugins = [];
5097
5139
  this._postParticleUpdatePlugins = [];
5140
+ this._particleBuckets.clear();
5141
+ this._resetBuckets(container.zLayers);
5098
5142
  this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5099
5143
  for (const plugin of container.plugins) {
5100
5144
  if (plugin.redrawInit) {
@@ -5195,79 +5239,25 @@
5195
5239
  }
5196
5240
  this._applyDensity(options.particles, pluginsCount);
5197
5241
  }
5198
- setLastZIndex(zIndex) {
5199
- this._needsSort ||= zIndex >= this._maxZIndex || (zIndex > this._minZIndex && zIndex < this._maxZIndex);
5200
- }
5201
5242
  setResizeFactor(factor) {
5202
5243
  this._resizeFactor = factor;
5203
5244
  }
5204
5245
  update(delta) {
5205
- const particlesToDelete = new Set();
5206
5246
  this.grid.clear();
5207
5247
  for (const plugin of this._updatePlugins) {
5208
5248
  plugin.update?.(delta);
5209
5249
  }
5210
- const resizeFactor = this._resizeFactor;
5211
- for (const particle of this._array) {
5212
- if (resizeFactor && !particle.ignoresResizeRatio) {
5213
- particle.position.x *= resizeFactor.width;
5214
- particle.position.y *= resizeFactor.height;
5215
- particle.initialPosition.x *= resizeFactor.width;
5216
- particle.initialPosition.y *= resizeFactor.height;
5217
- }
5218
- particle.ignoresResizeRatio = false;
5219
- for (const plugin of this._particleResetPlugins) {
5220
- plugin.particleReset?.(particle);
5221
- }
5222
- for (const plugin of this._particleUpdatePlugins) {
5223
- if (particle.destroyed) {
5224
- break;
5225
- }
5226
- plugin.particleUpdate?.(particle, delta);
5227
- }
5228
- if (particle.destroyed) {
5229
- particlesToDelete.add(particle);
5230
- continue;
5231
- }
5232
- this.grid.insert(particle);
5233
- }
5250
+ const particlesToDelete = this._updateParticlesPhase1(delta);
5234
5251
  for (const plugin of this._postUpdatePlugins) {
5235
5252
  plugin.postUpdate?.(delta);
5236
5253
  }
5237
- for (const particle of this._array) {
5238
- if (particle.destroyed) {
5239
- particlesToDelete.add(particle);
5240
- continue;
5241
- }
5242
- for (const updater of this._container.particleUpdaters) {
5243
- updater.update(particle, delta);
5244
- }
5245
- if (!particle.destroyed && !particle.spawning) {
5246
- for (const plugin of this._postParticleUpdatePlugins) {
5247
- plugin.postParticleUpdate?.(particle, delta);
5248
- }
5249
- }
5250
- else if (particle.destroyed) {
5251
- particlesToDelete.add(particle);
5252
- }
5253
- }
5254
+ this._updateParticlesPhase2(delta, particlesToDelete);
5254
5255
  if (particlesToDelete.size) {
5255
5256
  for (const particle of particlesToDelete) {
5256
5257
  this.remove(particle);
5257
5258
  }
5258
5259
  }
5259
5260
  delete this._resizeFactor;
5260
- if (this._needsSort) {
5261
- const zArray = this._zArray;
5262
- zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
5263
- const firstItem = zArray[minIndex], lastItem = zArray[zArray.length - lengthOffset];
5264
- if (!firstItem || !lastItem) {
5265
- return;
5266
- }
5267
- this._maxZIndex = firstItem.position.z;
5268
- this._minZIndex = lastItem.position.z;
5269
- this._needsSort = false;
5270
- }
5271
5261
  }
5272
5262
  _addToPool = (...particles) => {
5273
5263
  this._pool.push(...particles);
@@ -5297,13 +5287,52 @@
5297
5287
  this.removeQuantity(particlesCount - particlesNumber, group);
5298
5288
  }
5299
5289
  };
5290
+ _createBuckets = (zLayers) => {
5291
+ const bucketCount = Math.max(Math.floor(zLayers), one);
5292
+ return Array.from({ length: bucketCount }, () => []);
5293
+ };
5294
+ _getBucketIndex = (zIndex) => {
5295
+ const maxBucketIndex = this._zBuckets.length - one;
5296
+ if (maxBucketIndex <= minIndex) {
5297
+ return minIndex;
5298
+ }
5299
+ return Math.min(Math.max(Math.floor(zIndex), minIndex), maxBucketIndex);
5300
+ };
5301
+ _getParticleInsertIndex = (bucket, particleId) => {
5302
+ let start = minIndex, end = bucket.length;
5303
+ while (start < end) {
5304
+ const middle = Math.floor((start + end) / double), middleParticle = bucket[middle];
5305
+ if (!middleParticle) {
5306
+ end = middle;
5307
+ continue;
5308
+ }
5309
+ if (middleParticle.id < particleId) {
5310
+ start = middle + one;
5311
+ }
5312
+ else {
5313
+ end = middle;
5314
+ }
5315
+ }
5316
+ return start;
5317
+ };
5300
5318
  _initDensityFactor = densityOptions => {
5301
5319
  const container = this._container;
5302
- if (!container.canvas.element || !densityOptions.enable) {
5320
+ if (!densityOptions.enable) {
5321
+ return defaultDensityFactor;
5322
+ }
5323
+ const canvasSize = container.canvas.size, pxRatio = container.retina.pixelRatio;
5324
+ if (!canvasSize.width || !canvasSize.height) {
5303
5325
  return defaultDensityFactor;
5304
5326
  }
5305
- const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio;
5306
- return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp);
5327
+ return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5328
+ };
5329
+ _insertParticleIntoBucket = (particle) => {
5330
+ const bucketIndex = this._getBucketIndex(particle.position.z), bucket = this._zBuckets[bucketIndex];
5331
+ if (!bucket) {
5332
+ return;
5333
+ }
5334
+ bucket.splice(this._getParticleInsertIndex(bucket, particle.id), empty, particle);
5335
+ this._particleBuckets.set(particle.id, bucketIndex);
5307
5336
  };
5308
5337
  _removeParticle = (index, group, override) => {
5309
5338
  const particle = this._array[index];
@@ -5313,9 +5342,8 @@
5313
5342
  if (particle.group !== group) {
5314
5343
  return false;
5315
5344
  }
5316
- const zIdx = this._zArray.indexOf(particle);
5317
5345
  this._array.splice(index, deleteCount);
5318
- this._zArray.splice(zIdx, deleteCount);
5346
+ this._removeParticleFromBucket(particle);
5319
5347
  particle.destroy(override);
5320
5348
  this._container.dispatchEvent(exports.EventType.particleRemoved, {
5321
5349
  particle,
@@ -5323,6 +5351,98 @@
5323
5351
  this._addToPool(particle);
5324
5352
  return true;
5325
5353
  };
5354
+ _removeParticleFromBucket = (particle) => {
5355
+ const bucketIndex = this._particleBuckets.get(particle.id) ?? this._getBucketIndex(particle.position.z), bucket = this._zBuckets[bucketIndex];
5356
+ if (!bucket) {
5357
+ this._particleBuckets.delete(particle.id);
5358
+ return;
5359
+ }
5360
+ const particleIndex = this._getParticleInsertIndex(bucket, particle.id);
5361
+ if (bucket[particleIndex]?.id !== particle.id) {
5362
+ this._particleBuckets.delete(particle.id);
5363
+ return;
5364
+ }
5365
+ bucket.splice(particleIndex, deleteCount);
5366
+ this._particleBuckets.delete(particle.id);
5367
+ };
5368
+ _resetBuckets = (zLayers) => {
5369
+ const bucketCount = Math.max(Math.floor(zLayers), one);
5370
+ if (this._zBuckets.length !== bucketCount) {
5371
+ this._zBuckets = this._createBuckets(bucketCount);
5372
+ return;
5373
+ }
5374
+ for (const bucket of this._zBuckets) {
5375
+ bucket.length = minIndex;
5376
+ }
5377
+ };
5378
+ _updateParticleBucket = (particle) => {
5379
+ const newBucketIndex = this._getBucketIndex(particle.position.z), currentBucketIndex = this._particleBuckets.get(particle.id);
5380
+ if (currentBucketIndex === undefined) {
5381
+ this._insertParticleIntoBucket(particle);
5382
+ return;
5383
+ }
5384
+ if (currentBucketIndex === newBucketIndex) {
5385
+ return;
5386
+ }
5387
+ const currentBucket = this._zBuckets[currentBucketIndex];
5388
+ if (currentBucket) {
5389
+ const particleIndex = this._getParticleInsertIndex(currentBucket, particle.id);
5390
+ if (currentBucket[particleIndex]?.id === particle.id) {
5391
+ currentBucket.splice(particleIndex, deleteCount);
5392
+ }
5393
+ }
5394
+ const newBucket = this._zBuckets[newBucketIndex];
5395
+ if (!newBucket) {
5396
+ this._particleBuckets.set(particle.id, newBucketIndex);
5397
+ return;
5398
+ }
5399
+ newBucket.splice(this._getParticleInsertIndex(newBucket, particle.id), empty, particle);
5400
+ this._particleBuckets.set(particle.id, newBucketIndex);
5401
+ };
5402
+ _updateParticlesPhase1 = (delta) => {
5403
+ const particlesToDelete = new Set(), resizeFactor = this._resizeFactor;
5404
+ for (const particle of this._array) {
5405
+ if (resizeFactor && !particle.ignoresResizeRatio) {
5406
+ particle.position.x *= resizeFactor.width;
5407
+ particle.position.y *= resizeFactor.height;
5408
+ particle.initialPosition.x *= resizeFactor.width;
5409
+ particle.initialPosition.y *= resizeFactor.height;
5410
+ }
5411
+ particle.ignoresResizeRatio = false;
5412
+ for (const plugin of this._particleResetPlugins) {
5413
+ plugin.particleReset?.(particle);
5414
+ }
5415
+ for (const plugin of this._particleUpdatePlugins) {
5416
+ if (particle.destroyed) {
5417
+ break;
5418
+ }
5419
+ plugin.particleUpdate?.(particle, delta);
5420
+ }
5421
+ if (particle.destroyed) {
5422
+ particlesToDelete.add(particle);
5423
+ continue;
5424
+ }
5425
+ this.grid.insert(particle);
5426
+ }
5427
+ return particlesToDelete;
5428
+ };
5429
+ _updateParticlesPhase2 = (delta, particlesToDelete) => {
5430
+ for (const particle of this._array) {
5431
+ if (particle.destroyed) {
5432
+ particlesToDelete.add(particle);
5433
+ continue;
5434
+ }
5435
+ for (const updater of this._container.particleUpdaters) {
5436
+ updater.update(particle, delta);
5437
+ }
5438
+ if (!particle.spawning) {
5439
+ for (const plugin of this._postParticleUpdatePlugins) {
5440
+ plugin.postParticleUpdate?.(particle, delta);
5441
+ }
5442
+ }
5443
+ this._updateParticleBucket(particle);
5444
+ }
5445
+ };
5326
5446
  }
5327
5447
 
5328
5448
  class Retina {
@@ -5338,9 +5458,8 @@
5338
5458
  const container = this.container, options = container.actualOptions;
5339
5459
  this.pixelRatio = options.detectRetina ? devicePixelRatio : defaultRatio;
5340
5460
  this.reduceFactor = defaultReduceFactor;
5341
- const ratio = this.pixelRatio, canvas = container.canvas;
5342
- if (canvas.element) {
5343
- const element = canvas.element;
5461
+ const ratio = this.pixelRatio, canvas = container.canvas, element = canvas.domElement;
5462
+ if (element) {
5344
5463
  canvas.size.width = element.offsetWidth * ratio;
5345
5464
  canvas.size.height = element.offsetHeight * ratio;
5346
5465
  }