@tsparticles/preset-squares 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, 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, 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) {
@@ -967,7 +967,7 @@
967
967
  }
968
968
  }
969
969
  else {
970
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases[canvasFirstIndex];
970
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
971
971
  if (foundCanvas) {
972
972
  canvasEl = foundCanvas;
973
973
  canvasEl.dataset[generatedAttribute] = generatedFalse;
@@ -1004,7 +1004,7 @@
1004
1004
  return this._domArray;
1005
1005
  }
1006
1006
  get version() {
1007
- return "4.0.0-beta.16";
1007
+ return "4.0.0";
1008
1008
  }
1009
1009
  addEventListener(type, listener) {
1010
1010
  this._eventDispatcher.addEventListener(type, listener);
@@ -1035,7 +1035,11 @@
1035
1035
  }
1036
1036
  async load(params) {
1037
1037
  await this.init();
1038
- 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({
1038
+ let domSourceElement;
1039
+ if (typeof HTMLElement !== "undefined" && params.element instanceof HTMLElement) {
1040
+ domSourceElement = params.element;
1041
+ }
1042
+ 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({
1039
1043
  dispatchCallback: (eventType, args) => {
1040
1044
  this.dispatchEvent(eventType, args);
1041
1045
  },
@@ -1062,8 +1066,10 @@
1062
1066
  else {
1063
1067
  items.push(newItem);
1064
1068
  }
1065
- const domContainer = getDomContainer(id, params.element), canvasEl = getCanvasFromContainer(domContainer);
1066
- newItem.canvas.loadCanvas(canvasEl);
1069
+ const sourceCanvas = typeof OffscreenCanvas !== "undefined" && params.element instanceof OffscreenCanvas
1070
+ ? params.element
1071
+ : getCanvasFromContainer(getDomContainer(id, domSourceElement));
1072
+ newItem.canvas.loadCanvas(sourceCanvas);
1067
1073
  await newItem.start();
1068
1074
  return newItem;
1069
1075
  }
@@ -3084,7 +3090,7 @@
3084
3090
  })(EmitterClickMode || (EmitterClickMode = {}));
3085
3091
 
3086
3092
  async function loadEmittersPluginSimple(engine) {
3087
- engine.checkVersion("4.0.0-beta.16");
3093
+ engine.checkVersion("4.0.0");
3088
3094
  await engine.pluginManager.register(async (e) => {
3089
3095
  const instancesManager = await getEmittersInstancesManager(e);
3090
3096
  await addEmittersShapesManager(e);
@@ -3132,7 +3138,7 @@
3132
3138
  }
3133
3139
 
3134
3140
  async function loadHexColorPlugin(engine) {
3135
- engine.checkVersion("4.0.0-beta.16");
3141
+ engine.checkVersion("4.0.0");
3136
3142
  await engine.pluginManager.register(e => {
3137
3143
  e.pluginManager.addColorManager("hex", new HexColorManager());
3138
3144
  });
@@ -3201,7 +3207,7 @@
3201
3207
  }
3202
3208
 
3203
3209
  async function loadPaintUpdater(engine) {
3204
- engine.checkVersion("4.0.0-beta.16");
3210
+ engine.checkVersion("4.0.0");
3205
3211
  await engine.pluginManager.register(e => {
3206
3212
  e.pluginManager.addParticleUpdater("paint", container => {
3207
3213
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3335,7 +3341,7 @@
3335
3341
  }
3336
3342
 
3337
3343
  async function loadRotateUpdater(engine) {
3338
- engine.checkVersion("4.0.0-beta.16");
3344
+ engine.checkVersion("4.0.0");
3339
3345
  await engine.pluginManager.register(e => {
3340
3346
  e.pluginManager.addParticleUpdater("rotate", container => {
3341
3347
  return Promise.resolve(new RotateUpdater(container));
@@ -3380,7 +3386,7 @@
3380
3386
  }
3381
3387
 
3382
3388
  async function loadSizeUpdater(engine) {
3383
- engine.checkVersion("4.0.0-beta.16");
3389
+ engine.checkVersion("4.0.0");
3384
3390
  await engine.pluginManager.register(e => {
3385
3391
  e.pluginManager.addParticleUpdater("size", container => {
3386
3392
  return Promise.resolve(new SizeUpdater(container));
@@ -3404,7 +3410,7 @@
3404
3410
  }
3405
3411
 
3406
3412
  async function loadSquareShape(engine) {
3407
- engine.checkVersion("4.0.0-beta.16");
3413
+ engine.checkVersion("4.0.0");
3408
3414
  await engine.pluginManager.register(e => {
3409
3415
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
3410
3416
  });
@@ -3781,6 +3787,25 @@
3781
3787
  };
3782
3788
  }
3783
3789
 
3790
+ const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
3791
+ const transferredCanvas = transferredCanvases.get(canvas);
3792
+ if (transferredCanvas) {
3793
+ return transferredCanvas;
3794
+ }
3795
+ if (typeof canvas.transferControlToOffscreen !== "function") {
3796
+ throw new TypeError("OffscreenCanvas is required but not supported by this browser");
3797
+ }
3798
+ try {
3799
+ const offscreenCanvas = canvas.transferControlToOffscreen();
3800
+ transferredCanvases.set(canvas, offscreenCanvas);
3801
+ return offscreenCanvas;
3802
+ }
3803
+ catch {
3804
+ throw new TypeError("OffscreenCanvas transfer failed");
3805
+ }
3806
+ }, isHtmlCanvasElement = (canvas) => {
3807
+ return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
3808
+ };
3784
3809
  function setStyle(canvas, style, important = false) {
3785
3810
  if (!style) {
3786
3811
  return;
@@ -3811,8 +3836,9 @@
3811
3836
  }
3812
3837
  }
3813
3838
  class CanvasManager {
3814
- element;
3839
+ domElement;
3815
3840
  render;
3841
+ renderCanvas;
3816
3842
  size;
3817
3843
  zoom = defaultZoom;
3818
3844
  _container;
@@ -3847,9 +3873,10 @@
3847
3873
  destroy() {
3848
3874
  this.stop();
3849
3875
  if (this._generated) {
3850
- const element = this.element;
3876
+ const element = this.domElement;
3851
3877
  element?.remove();
3852
- this.element = undefined;
3878
+ this.domElement = undefined;
3879
+ this.renderCanvas = undefined;
3853
3880
  }
3854
3881
  else {
3855
3882
  this._resetOriginalStyle();
@@ -3882,16 +3909,17 @@
3882
3909
  this._initStyle();
3883
3910
  this.initBackground();
3884
3911
  this._safeMutationObserver(obs => {
3885
- if (!this.element || !(this.element instanceof Node)) {
3912
+ const element = this.domElement;
3913
+ if (!element || !(element instanceof Node)) {
3886
3914
  return;
3887
3915
  }
3888
- obs.observe(this.element, { attributes: true });
3916
+ obs.observe(element, { attributes: true });
3889
3917
  });
3890
3918
  this.initPlugins();
3891
3919
  this.render.init();
3892
3920
  }
3893
3921
  initBackground() {
3894
- const { _container } = this, options = _container.actualOptions, background = options.background, element = this.element;
3922
+ const { _container } = this, options = _container.actualOptions, background = options.background, element = this.domElement;
3895
3923
  if (!element) {
3896
3924
  return;
3897
3925
  }
@@ -3916,21 +3944,30 @@
3916
3944
  }
3917
3945
  }
3918
3946
  loadCanvas(canvas) {
3919
- if (this._generated && this.element) {
3920
- this.element.remove();
3947
+ if (this._generated && this.domElement) {
3948
+ this.domElement.remove();
3949
+ }
3950
+ const container = this._container, domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
3951
+ this.domElement = domCanvas;
3952
+ this._generated = domCanvas ? domCanvas.dataset[generatedAttribute] === "true" : false;
3953
+ this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
3954
+ const domElement = this.domElement;
3955
+ if (domElement) {
3956
+ domElement.ariaHidden = "true";
3957
+ this._originalStyle = cloneStyle(domElement.style);
3958
+ }
3959
+ const standardSize = this._standardSize, renderCanvas = this.renderCanvas;
3960
+ if (domElement) {
3961
+ standardSize.height = domElement.offsetHeight;
3962
+ standardSize.width = domElement.offsetWidth;
3963
+ }
3964
+ else {
3965
+ standardSize.height = renderCanvas.height;
3966
+ standardSize.width = renderCanvas.width;
3921
3967
  }
3922
- const container = this._container;
3923
- this._generated =
3924
- generatedAttribute in canvas.dataset ? canvas.dataset[generatedAttribute] === "true" : this._generated;
3925
- this.element = canvas;
3926
- this.element.ariaHidden = "true";
3927
- this._originalStyle = cloneStyle(this.element.style);
3928
- const standardSize = this._standardSize;
3929
- standardSize.height = canvas.offsetHeight;
3930
- standardSize.width = canvas.offsetWidth;
3931
3968
  const pxRatio = this._container.retina.pixelRatio, retinaSize = this.size;
3932
- canvas.height = retinaSize.height = standardSize.height * pxRatio;
3933
- canvas.width = retinaSize.width = standardSize.width * pxRatio;
3969
+ renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
3970
+ renderCanvas.width = retinaSize.width = standardSize.width * pxRatio;
3934
3971
  const canSupportHdrQuery = safeMatchMedia("(color-gamut: p3)");
3935
3972
  this.render.setContextSettings({
3936
3973
  alpha: true,
@@ -3938,42 +3975,48 @@
3938
3975
  desynchronized: true,
3939
3976
  willReadFrequently: false,
3940
3977
  });
3941
- this.render.setContext(this.element.getContext("2d", this.render.settings));
3978
+ this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
3942
3979
  this._safeMutationObserver(obs => {
3943
3980
  obs.disconnect();
3944
3981
  });
3945
3982
  container.retina.init();
3946
3983
  this.initBackground();
3947
3984
  this._safeMutationObserver(obs => {
3948
- if (!this.element || !(this.element instanceof Node)) {
3985
+ const element = this.domElement;
3986
+ if (!element || !(element instanceof Node)) {
3949
3987
  return;
3950
3988
  }
3951
- obs.observe(this.element, { attributes: true });
3989
+ obs.observe(element, { attributes: true });
3952
3990
  });
3953
3991
  }
3954
3992
  resize() {
3955
- if (!this.element) {
3993
+ const element = this.domElement;
3994
+ if (!element) {
3995
+ return false;
3996
+ }
3997
+ const container = this._container, renderCanvas = this.renderCanvas;
3998
+ if (renderCanvas === undefined) {
3956
3999
  return false;
3957
4000
  }
3958
- const container = this._container, currentSize = container.canvas._standardSize, newSize = {
3959
- width: this.element.offsetWidth,
3960
- height: this.element.offsetHeight,
4001
+ const currentSize = container.canvas._standardSize, newSize = {
4002
+ width: element.offsetWidth,
4003
+ height: element.offsetHeight,
3961
4004
  }, pxRatio = container.retina.pixelRatio, retinaSize = {
3962
4005
  width: newSize.width * pxRatio,
3963
4006
  height: newSize.height * pxRatio,
3964
4007
  };
3965
4008
  if (newSize.height === currentSize.height &&
3966
4009
  newSize.width === currentSize.width &&
3967
- retinaSize.height === this.element.height &&
3968
- retinaSize.width === this.element.width) {
4010
+ retinaSize.height === renderCanvas.height &&
4011
+ retinaSize.width === renderCanvas.width) {
3969
4012
  return false;
3970
4013
  }
3971
4014
  const oldSize = { ...currentSize };
3972
4015
  currentSize.height = newSize.height;
3973
4016
  currentSize.width = newSize.width;
3974
4017
  const canvasSize = this.size;
3975
- this.element.width = canvasSize.width = retinaSize.width;
3976
- this.element.height = canvasSize.height = retinaSize.height;
4018
+ renderCanvas.width = canvasSize.width = retinaSize.width;
4019
+ renderCanvas.height = canvasSize.height = retinaSize.height;
3977
4020
  if (this._container.started) {
3978
4021
  container.particles.setResizeFactor({
3979
4022
  width: currentSize.width / oldSize.width,
@@ -3983,7 +4026,7 @@
3983
4026
  return true;
3984
4027
  }
3985
4028
  setPointerEvents(type) {
3986
- const element = this.element;
4029
+ const element = this.domElement;
3987
4030
  if (!element) {
3988
4031
  return;
3989
4032
  }
@@ -4002,7 +4045,7 @@
4002
4045
  this.render.stop();
4003
4046
  }
4004
4047
  async windowResize() {
4005
- if (!this.element || !this.resize()) {
4048
+ if (!this.domElement || !this.resize()) {
4006
4049
  return;
4007
4050
  }
4008
4051
  const container = this._container, needsRefresh = container.updateActualOptions();
@@ -4018,7 +4061,7 @@
4018
4061
  }
4019
4062
  };
4020
4063
  _initStyle = () => {
4021
- const element = this.element, options = this._container.actualOptions;
4064
+ const element = this.domElement, options = this._container.actualOptions;
4022
4065
  if (!element) {
4023
4066
  return;
4024
4067
  }
@@ -4040,7 +4083,7 @@
4040
4083
  }
4041
4084
  };
4042
4085
  _repairStyle = () => {
4043
- const element = this.element;
4086
+ const element = this.domElement;
4044
4087
  if (!element) {
4045
4088
  return;
4046
4089
  }
@@ -4060,7 +4103,7 @@
4060
4103
  });
4061
4104
  };
4062
4105
  _resetOriginalStyle = () => {
4063
- const element = this.element, originalStyle = this._originalStyle;
4106
+ const element = this.domElement, originalStyle = this._originalStyle;
4064
4107
  if (!element || !originalStyle) {
4065
4108
  return;
4066
4109
  }
@@ -4073,7 +4116,7 @@
4073
4116
  callback(this._mutationObserver);
4074
4117
  };
4075
4118
  _setFullScreenStyle = () => {
4076
- const element = this.element;
4119
+ const element = this.domElement;
4077
4120
  if (!element) {
4078
4121
  return;
4079
4122
  }
@@ -4147,7 +4190,7 @@
4147
4190
  manageListener(globalThis, resizeEvent, handlers.resize, add);
4148
4191
  return;
4149
4192
  }
4150
- const canvasEl = container.canvas.element;
4193
+ const canvasEl = container.canvas.domElement;
4151
4194
  if (this._resizeObserver && !add) {
4152
4195
  if (canvasEl) {
4153
4196
  this._resizeObserver.unobserve(canvasEl);
@@ -4402,8 +4445,6 @@
4402
4445
  this._initPosition(position);
4403
4446
  this.initialVelocity = this._calculateVelocity();
4404
4447
  this.velocity = this.initialVelocity.copy();
4405
- const particles = container.particles;
4406
- particles.setLastZIndex(this.position.z);
4407
4448
  this.zIndexFactor = this.position.z / container.zLayers;
4408
4449
  this.sides = 24;
4409
4450
  let effectDrawer, shapeDrawer;
@@ -4553,7 +4594,7 @@
4553
4594
  return color;
4554
4595
  };
4555
4596
  _initPosition = position => {
4556
- const container = this._container, zIndexValue = getRangeValue(this.options.zIndex.value), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4597
+ const container = this._container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4557
4598
  if (!initialPosition) {
4558
4599
  throw new Error("a valid position cannot be found for particle");
4559
4600
  }
@@ -4687,10 +4728,8 @@
4687
4728
  _container;
4688
4729
  _groupLimits;
4689
4730
  _limit;
4690
- _maxZIndex;
4691
- _minZIndex;
4692
- _needsSort;
4693
4731
  _nextId;
4732
+ _particleBuckets;
4694
4733
  _particleResetPlugins;
4695
4734
  _particleUpdatePlugins;
4696
4735
  _pluginManager;
@@ -4699,19 +4738,17 @@
4699
4738
  _postUpdatePlugins;
4700
4739
  _resizeFactor;
4701
4740
  _updatePlugins;
4702
- _zArray;
4741
+ _zBuckets;
4703
4742
  constructor(pluginManager, container) {
4704
4743
  this._pluginManager = pluginManager;
4705
4744
  this._container = container;
4706
4745
  this._nextId = 0;
4707
4746
  this._array = [];
4708
- this._zArray = [];
4709
4747
  this._pool = [];
4710
4748
  this._limit = 0;
4711
4749
  this._groupLimits = new Map();
4712
- this._needsSort = false;
4713
- this._minZIndex = 0;
4714
- this._maxZIndex = 0;
4750
+ this._particleBuckets = new Map();
4751
+ this._zBuckets = this._createBuckets(this._container.zLayers);
4715
4752
  this.grid = new SpatialHashGrid(spatialHashGridCellSize);
4716
4753
  this.checkParticlePositionPlugins = [];
4717
4754
  this._particleResetPlugins = [];
@@ -4753,7 +4790,7 @@
4753
4790
  return;
4754
4791
  }
4755
4792
  this._array.push(particle);
4756
- this._zArray.push(particle);
4793
+ this._insertParticleIntoBucket(particle);
4757
4794
  this._nextId++;
4758
4795
  this._container.dispatchEvent(EventType.particleAdded, {
4759
4796
  particle,
@@ -4767,12 +4804,14 @@
4767
4804
  }
4768
4805
  clear() {
4769
4806
  this._array = [];
4770
- this._zArray = [];
4807
+ this._particleBuckets.clear();
4808
+ this._resetBuckets(this._container.zLayers);
4771
4809
  }
4772
4810
  destroy() {
4773
4811
  this._array = [];
4774
4812
  this._pool.length = 0;
4775
- this._zArray = [];
4813
+ this._particleBuckets.clear();
4814
+ this._zBuckets = [];
4776
4815
  this.checkParticlePositionPlugins = [];
4777
4816
  this._particleResetPlugins = [];
4778
4817
  this._particleUpdatePlugins = [];
@@ -4781,8 +4820,14 @@
4781
4820
  this._updatePlugins = [];
4782
4821
  }
4783
4822
  drawParticles(delta) {
4784
- for (const particle of this._zArray) {
4785
- particle.draw(delta);
4823
+ for (let i = this._zBuckets.length - one; i >= minIndex; i--) {
4824
+ const bucket = this._zBuckets[i];
4825
+ if (!bucket) {
4826
+ continue;
4827
+ }
4828
+ for (const particle of bucket) {
4829
+ particle.draw(delta);
4830
+ }
4786
4831
  }
4787
4832
  }
4788
4833
  filter(condition) {
@@ -4796,15 +4841,14 @@
4796
4841
  }
4797
4842
  async init() {
4798
4843
  const container = this._container, options = container.actualOptions;
4799
- this._minZIndex = 0;
4800
- this._maxZIndex = 0;
4801
- this._needsSort = false;
4802
4844
  this.checkParticlePositionPlugins = [];
4803
4845
  this._updatePlugins = [];
4804
4846
  this._particleUpdatePlugins = [];
4805
4847
  this._postUpdatePlugins = [];
4806
4848
  this._particleResetPlugins = [];
4807
4849
  this._postParticleUpdatePlugins = [];
4850
+ this._particleBuckets.clear();
4851
+ this._resetBuckets(container.zLayers);
4808
4852
  this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
4809
4853
  for (const plugin of container.plugins) {
4810
4854
  if (plugin.redrawInit) {
@@ -4905,79 +4949,25 @@
4905
4949
  }
4906
4950
  this._applyDensity(options.particles, pluginsCount);
4907
4951
  }
4908
- setLastZIndex(zIndex) {
4909
- this._needsSort ||= zIndex >= this._maxZIndex || (zIndex > this._minZIndex && zIndex < this._maxZIndex);
4910
- }
4911
4952
  setResizeFactor(factor) {
4912
4953
  this._resizeFactor = factor;
4913
4954
  }
4914
4955
  update(delta) {
4915
- const particlesToDelete = new Set();
4916
4956
  this.grid.clear();
4917
4957
  for (const plugin of this._updatePlugins) {
4918
4958
  plugin.update?.(delta);
4919
4959
  }
4920
- const resizeFactor = this._resizeFactor;
4921
- for (const particle of this._array) {
4922
- if (resizeFactor && !particle.ignoresResizeRatio) {
4923
- particle.position.x *= resizeFactor.width;
4924
- particle.position.y *= resizeFactor.height;
4925
- particle.initialPosition.x *= resizeFactor.width;
4926
- particle.initialPosition.y *= resizeFactor.height;
4927
- }
4928
- particle.ignoresResizeRatio = false;
4929
- for (const plugin of this._particleResetPlugins) {
4930
- plugin.particleReset?.(particle);
4931
- }
4932
- for (const plugin of this._particleUpdatePlugins) {
4933
- if (particle.destroyed) {
4934
- break;
4935
- }
4936
- plugin.particleUpdate?.(particle, delta);
4937
- }
4938
- if (particle.destroyed) {
4939
- particlesToDelete.add(particle);
4940
- continue;
4941
- }
4942
- this.grid.insert(particle);
4943
- }
4960
+ const particlesToDelete = this._updateParticlesPhase1(delta);
4944
4961
  for (const plugin of this._postUpdatePlugins) {
4945
4962
  plugin.postUpdate?.(delta);
4946
4963
  }
4947
- for (const particle of this._array) {
4948
- if (particle.destroyed) {
4949
- particlesToDelete.add(particle);
4950
- continue;
4951
- }
4952
- for (const updater of this._container.particleUpdaters) {
4953
- updater.update(particle, delta);
4954
- }
4955
- if (!particle.destroyed && !particle.spawning) {
4956
- for (const plugin of this._postParticleUpdatePlugins) {
4957
- plugin.postParticleUpdate?.(particle, delta);
4958
- }
4959
- }
4960
- else if (particle.destroyed) {
4961
- particlesToDelete.add(particle);
4962
- }
4963
- }
4964
+ this._updateParticlesPhase2(delta, particlesToDelete);
4964
4965
  if (particlesToDelete.size) {
4965
4966
  for (const particle of particlesToDelete) {
4966
4967
  this.remove(particle);
4967
4968
  }
4968
4969
  }
4969
4970
  delete this._resizeFactor;
4970
- if (this._needsSort) {
4971
- const zArray = this._zArray;
4972
- zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
4973
- const firstItem = zArray[minIndex], lastItem = zArray[zArray.length - lengthOffset];
4974
- if (!firstItem || !lastItem) {
4975
- return;
4976
- }
4977
- this._maxZIndex = firstItem.position.z;
4978
- this._minZIndex = lastItem.position.z;
4979
- this._needsSort = false;
4980
- }
4981
4971
  }
4982
4972
  _addToPool = (...particles) => {
4983
4973
  this._pool.push(...particles);
@@ -5007,13 +4997,52 @@
5007
4997
  this.removeQuantity(particlesCount - particlesNumber, group);
5008
4998
  }
5009
4999
  };
5000
+ _createBuckets = (zLayers) => {
5001
+ const bucketCount = Math.max(Math.floor(zLayers), one);
5002
+ return Array.from({ length: bucketCount }, () => []);
5003
+ };
5004
+ _getBucketIndex = (zIndex) => {
5005
+ const maxBucketIndex = this._zBuckets.length - one;
5006
+ if (maxBucketIndex <= minIndex) {
5007
+ return minIndex;
5008
+ }
5009
+ return Math.min(Math.max(Math.floor(zIndex), minIndex), maxBucketIndex);
5010
+ };
5011
+ _getParticleInsertIndex = (bucket, particleId) => {
5012
+ let start = minIndex, end = bucket.length;
5013
+ while (start < end) {
5014
+ const middle = Math.floor((start + end) / double), middleParticle = bucket[middle];
5015
+ if (!middleParticle) {
5016
+ end = middle;
5017
+ continue;
5018
+ }
5019
+ if (middleParticle.id < particleId) {
5020
+ start = middle + one;
5021
+ }
5022
+ else {
5023
+ end = middle;
5024
+ }
5025
+ }
5026
+ return start;
5027
+ };
5010
5028
  _initDensityFactor = densityOptions => {
5011
5029
  const container = this._container;
5012
- if (!container.canvas.element || !densityOptions.enable) {
5030
+ if (!densityOptions.enable) {
5031
+ return defaultDensityFactor;
5032
+ }
5033
+ const canvasSize = container.canvas.size, pxRatio = container.retina.pixelRatio;
5034
+ if (!canvasSize.width || !canvasSize.height) {
5013
5035
  return defaultDensityFactor;
5014
5036
  }
5015
- const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio;
5016
- return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp);
5037
+ return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5038
+ };
5039
+ _insertParticleIntoBucket = (particle) => {
5040
+ const bucketIndex = this._getBucketIndex(particle.position.z), bucket = this._zBuckets[bucketIndex];
5041
+ if (!bucket) {
5042
+ return;
5043
+ }
5044
+ bucket.splice(this._getParticleInsertIndex(bucket, particle.id), empty, particle);
5045
+ this._particleBuckets.set(particle.id, bucketIndex);
5017
5046
  };
5018
5047
  _removeParticle = (index, group, override) => {
5019
5048
  const particle = this._array[index];
@@ -5023,9 +5052,8 @@
5023
5052
  if (particle.group !== group) {
5024
5053
  return false;
5025
5054
  }
5026
- const zIdx = this._zArray.indexOf(particle);
5027
5055
  this._array.splice(index, deleteCount);
5028
- this._zArray.splice(zIdx, deleteCount);
5056
+ this._removeParticleFromBucket(particle);
5029
5057
  particle.destroy(override);
5030
5058
  this._container.dispatchEvent(EventType.particleRemoved, {
5031
5059
  particle,
@@ -5033,6 +5061,98 @@
5033
5061
  this._addToPool(particle);
5034
5062
  return true;
5035
5063
  };
5064
+ _removeParticleFromBucket = (particle) => {
5065
+ const bucketIndex = this._particleBuckets.get(particle.id) ?? this._getBucketIndex(particle.position.z), bucket = this._zBuckets[bucketIndex];
5066
+ if (!bucket) {
5067
+ this._particleBuckets.delete(particle.id);
5068
+ return;
5069
+ }
5070
+ const particleIndex = this._getParticleInsertIndex(bucket, particle.id);
5071
+ if (bucket[particleIndex]?.id !== particle.id) {
5072
+ this._particleBuckets.delete(particle.id);
5073
+ return;
5074
+ }
5075
+ bucket.splice(particleIndex, deleteCount);
5076
+ this._particleBuckets.delete(particle.id);
5077
+ };
5078
+ _resetBuckets = (zLayers) => {
5079
+ const bucketCount = Math.max(Math.floor(zLayers), one);
5080
+ if (this._zBuckets.length !== bucketCount) {
5081
+ this._zBuckets = this._createBuckets(bucketCount);
5082
+ return;
5083
+ }
5084
+ for (const bucket of this._zBuckets) {
5085
+ bucket.length = minIndex;
5086
+ }
5087
+ };
5088
+ _updateParticleBucket = (particle) => {
5089
+ const newBucketIndex = this._getBucketIndex(particle.position.z), currentBucketIndex = this._particleBuckets.get(particle.id);
5090
+ if (currentBucketIndex === undefined) {
5091
+ this._insertParticleIntoBucket(particle);
5092
+ return;
5093
+ }
5094
+ if (currentBucketIndex === newBucketIndex) {
5095
+ return;
5096
+ }
5097
+ const currentBucket = this._zBuckets[currentBucketIndex];
5098
+ if (currentBucket) {
5099
+ const particleIndex = this._getParticleInsertIndex(currentBucket, particle.id);
5100
+ if (currentBucket[particleIndex]?.id === particle.id) {
5101
+ currentBucket.splice(particleIndex, deleteCount);
5102
+ }
5103
+ }
5104
+ const newBucket = this._zBuckets[newBucketIndex];
5105
+ if (!newBucket) {
5106
+ this._particleBuckets.set(particle.id, newBucketIndex);
5107
+ return;
5108
+ }
5109
+ newBucket.splice(this._getParticleInsertIndex(newBucket, particle.id), empty, particle);
5110
+ this._particleBuckets.set(particle.id, newBucketIndex);
5111
+ };
5112
+ _updateParticlesPhase1 = (delta) => {
5113
+ const particlesToDelete = new Set(), resizeFactor = this._resizeFactor;
5114
+ for (const particle of this._array) {
5115
+ if (resizeFactor && !particle.ignoresResizeRatio) {
5116
+ particle.position.x *= resizeFactor.width;
5117
+ particle.position.y *= resizeFactor.height;
5118
+ particle.initialPosition.x *= resizeFactor.width;
5119
+ particle.initialPosition.y *= resizeFactor.height;
5120
+ }
5121
+ particle.ignoresResizeRatio = false;
5122
+ for (const plugin of this._particleResetPlugins) {
5123
+ plugin.particleReset?.(particle);
5124
+ }
5125
+ for (const plugin of this._particleUpdatePlugins) {
5126
+ if (particle.destroyed) {
5127
+ break;
5128
+ }
5129
+ plugin.particleUpdate?.(particle, delta);
5130
+ }
5131
+ if (particle.destroyed) {
5132
+ particlesToDelete.add(particle);
5133
+ continue;
5134
+ }
5135
+ this.grid.insert(particle);
5136
+ }
5137
+ return particlesToDelete;
5138
+ };
5139
+ _updateParticlesPhase2 = (delta, particlesToDelete) => {
5140
+ for (const particle of this._array) {
5141
+ if (particle.destroyed) {
5142
+ particlesToDelete.add(particle);
5143
+ continue;
5144
+ }
5145
+ for (const updater of this._container.particleUpdaters) {
5146
+ updater.update(particle, delta);
5147
+ }
5148
+ if (!particle.spawning) {
5149
+ for (const plugin of this._postParticleUpdatePlugins) {
5150
+ plugin.postParticleUpdate?.(particle, delta);
5151
+ }
5152
+ }
5153
+ this._updateParticleBucket(particle);
5154
+ }
5155
+ };
5036
5156
  }
5037
5157
 
5038
5158
  class Retina {
@@ -5048,9 +5168,8 @@
5048
5168
  const container = this.container, options = container.actualOptions;
5049
5169
  this.pixelRatio = options.detectRetina ? devicePixelRatio : defaultRatio;
5050
5170
  this.reduceFactor = defaultReduceFactor;
5051
- const ratio = this.pixelRatio, canvas = container.canvas;
5052
- if (canvas.element) {
5053
- const element = canvas.element;
5171
+ const ratio = this.pixelRatio, canvas = container.canvas, element = canvas.domElement;
5172
+ if (element) {
5054
5173
  canvas.size.width = element.offsetWidth * ratio;
5055
5174
  canvas.size.height = element.offsetHeight * ratio;
5056
5175
  }