canvasparticles-js 3.5.0 → 3.5.1

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.
package/README.md CHANGED
@@ -11,6 +11,7 @@ Creating a fun and interactive background. Colors, interaction and gravity can b
11
11
 
12
12
  [Showcase](#showcase)<br>
13
13
  [Implementation](#implementation)<br>
14
+ [Class instantiation](#class-instantiation)<br>
14
15
  [Options](#options)<br>
15
16
  [One pager example](#one-pager-example)
16
17
 
@@ -24,13 +25,13 @@ If you dont like reading documentation this website is for you:<br>
24
25
  Particles will be drawn onto this `<canvas>` element
25
26
 
26
27
  ```html
27
- <canvas id="canvas-particles"></canvas>
28
+ <canvas id="my-canvas"></canvas>
28
29
  ```
29
30
 
30
31
  Resize the `<canvas>` so it covers the whole page and place it behind all elements.
31
32
 
32
33
  ```css
33
- #canvas-particles {
34
+ #my-canvas {
34
35
  position: fixed;
35
36
  top: 0;
36
37
  left: 0;
@@ -60,7 +61,7 @@ Inside _initParticles.js_:
60
61
  ```js
61
62
  import CanvasParticles from 'canvasparticles-js'
62
63
 
63
- const selector = '#canvas-particles' // Query Selector for the canvas
64
+ const selector = '#my-canvas' // Query Selector for the canvas
64
65
  const options = { ... } // See #options
65
66
  new CanvasParticles(selector, options).start()
66
67
  ```
@@ -99,7 +100,7 @@ Inside _initParticles.js_:
99
100
  ```js
100
101
  import CanvasParticles from './canvasParticles.mjs'
101
102
 
102
- const selector = '#canvas-particles' // Query Selector for the canvas
103
+ const selector = '#my-canvas' // Query Selector for the canvas
103
104
  const options = { ... } // See #options
104
105
  new CanvasParticles(selector, options).start()
105
106
  ```
@@ -124,7 +125,7 @@ Add an inline `<script>` element at the very bottom of the `<body>`.
124
125
 
125
126
  <script>
126
127
  const initParticles = () => {
127
- const selector = '#canvas-particles' // Query Selector for the canvas
128
+ const selector = '#my-canvas' // Query Selector for the canvas
128
129
  const options = { ... } // See #options
129
130
  new CanvasParticles(selector, options).start()
130
131
  }
@@ -141,7 +142,7 @@ Add an inline `<script>` element at the very bottom of the `<body>`.
141
142
  ### Start animating
142
143
 
143
144
  ```js
144
- const selector = '#canvas-particles' // Query Selector for the canvas
145
+ const selector = '#my-canvas' // Query Selector for the canvas
145
146
  const options = { ... } // See #options
146
147
  new CanvasParticles(selector, options).start()
147
148
  ```
@@ -152,6 +153,58 @@ new CanvasParticles(selector, options).start()
152
153
  const particles = new CanvasParticles(selector, options)
153
154
  particles.start()
154
155
  particles.stop()
156
+ particles.stop({ clear: false }) // Default: true
157
+ ```
158
+
159
+ ## Class instantiation
160
+
161
+ ### Valid ways to instantiate `CanvasParticles`
162
+
163
+ ```js
164
+ const selector = '#my-canvas'
165
+ const options = {}
166
+ const myCanvas = document.querySelector(selector)
167
+
168
+ let instance, canvas
169
+
170
+ // Basic instantiation
171
+ instance = new CanvasParticles(selector)
172
+ instance = new CanvasParticles(myCanvas)
173
+
174
+ // Instantiation with custom options
175
+ instance = new CanvasParticles(selector, options)
176
+ instance = new CanvasParticles(myCanvas, options)
177
+ ```
178
+
179
+ ### Chaining methods
180
+
181
+ You can chain .start() for a cleaner syntax:
182
+
183
+ ```js
184
+ instance = new CanvasParticles(selector).start()
185
+
186
+ // Access the canvas directly
187
+ canvas = new CanvasParticles(selector).canvas
188
+ canvas = new CanvasParticles(selector).start().canvas
189
+ ```
190
+
191
+ ### Without chaining
192
+
193
+ If you prefer not to chain methods, you can instantiate first and start later:
194
+
195
+ ```js
196
+ instance = new CanvasParticles(selector)
197
+ instance.start()
198
+ canvas = instance.canvas
199
+ ```
200
+
201
+ ### Incorrect usage
202
+
203
+ The following will not return the expected value because `CanvasParticles` only supports method chaining for `.start()`:
204
+
205
+ ```js
206
+ instance = new CanvasParticles(selector).anyOtherMethod()
207
+ canvas = new CanvasParticles(selector).anyOtherMethod().canvas
155
208
  ```
156
209
 
157
210
  ## Options
@@ -9,36 +9,41 @@
9
9
  typeof self !== 'undefined' ? self : this,
10
10
  () =>
11
11
  class CanvasParticles {
12
- static version = '3.5.0'
12
+ static version = '3.5.1'
13
13
 
14
14
  // Start or stop the animation when the canvas enters or exits the viewport
15
15
  static canvasObserver = new IntersectionObserver(entry => {
16
16
  entry.forEach(change => {
17
17
  // CanvasParticles instance of the target canvas
18
- const instance = change.target.instance
18
+ const canvas = change.target
19
+ const instance = canvas.instance
19
20
 
20
- if (change.isIntersecting) instance.options.animation.startOnEnter && instance.start()
21
- else instance.options.animation.stopOnLeave && instance.stop({ clear: false })
21
+ if ((canvas.inViewbox = change.isIntersecting)) instance.options.animation.startOnEnter && instance.start({ auto: true })
22
+ else instance.options.animation.stopOnLeave && instance.stop({ auto: true, clear: false })
22
23
  })
23
24
  })
24
25
 
25
26
  /**
26
27
  * Creates a new CanvasParticles instance.
27
- * @param {string} [selector] - The CSS selector for the canvas element.
28
+ * @param {string} [selector] - The CSS selector to the canvas element or the HTMLCanvasElement itself.
28
29
  * @param {Object} [options={}] - Object structure: https://github.com/Khoeckman/canvasParticles?tab=readme-ov-file#options
29
30
  */
30
31
  constructor(selector, options = {}) {
31
- // Find and initialize canvas
32
- if (typeof selector !== 'string') throw new TypeError('selector is not a string')
33
-
34
- this.canvas = document.querySelector(selector)
35
- if (!(this.canvas instanceof HTMLCanvasElement)) throw new Error('selector does not point to a canvas')
32
+ if (selector instanceof HTMLCanvasElement) this.canvas = selector
33
+ else {
34
+ // Find and initialize canvas
35
+ if (typeof selector !== 'string') throw new TypeError('selector is not a string and neither a HTMLCanvasElement itself')
36
36
 
37
- this.canvas.instance = this
37
+ this.canvas = document.querySelector(selector)
38
+ if (!(this.canvas instanceof HTMLCanvasElement)) throw new Error('selector does not point to a canvas')
39
+ }
40
+ this.canvas.instance = this // Circular assignment to find the instance bound to this canvas inside the 'canvasObserver'
41
+ this.canvas.inViewbox = true
38
42
 
39
43
  // Get 2d drawing functions
40
44
  this.ctx = this.canvas.getContext('2d')
41
45
 
46
+ this.enableAnimating = false
42
47
  this.animating = false
43
48
  this.particles = []
44
49
  this.setOptions(options)
@@ -55,7 +60,7 @@
55
60
 
56
61
  #setupEventHandlers() {
57
62
  const updateMousePos = event => {
58
- if (!this.animating) return
63
+ if (!this.enableAnimating) return
59
64
 
60
65
  if (event instanceof MouseEvent) {
61
66
  this.clientX = event.clientX
@@ -322,8 +327,8 @@
322
327
  * This is necessary because the rendering process involves up to [particles ** 2 / 2] lookups per frame.
323
328
  *
324
329
  * @private
325
- * @param {string} color - The base color in the format `#rrggbb`.
326
- * @returns {Object} - A lookup table mapping each alpha value (0–255) to its corresponding stroke style string in the format `#rrggbbaa`.
330
+ * @param {string} color - The base color in the format '#rrggbb'.
331
+ * @returns {Object} - A lookup table mapping each alpha value (0–255) to its corresponding stroke style string in the format '#rrggbbaa'.
327
332
  *
328
333
  * @example
329
334
  * const strokeStyleTable = this.#generateStrokeStyleTable("#abcdef");
@@ -333,7 +338,7 @@
333
338
  * Notes:
334
339
  * - This function precomputes all possible stroke styles by appending a two-character
335
340
  * hexadecimal alpha value (0x00–0xFF) to the base color.
336
- * - The table is stored in `this.strokeStyleTable` for quick lookups.
341
+ * - The table is stored in 'this.strokeStyleTable' for quick lookups.
337
342
  */
338
343
  #generateStrokeStyleTable(color) {
339
344
  const table = {}
@@ -457,22 +462,39 @@
457
462
 
458
463
  /**
459
464
  * Starts the particle animation.
460
- * Does nothing if already animating.
461
465
  *
462
- * @returns {CanvasParticles} - The current instance.
466
+ * - If the animation is already running, do nothing.
467
+ * - If the canvas is not within the viewbox and 'startOnEnter' is enabled, animation will be stopped until it enters the viewbox.
468
+ *
469
+ * @param {Object} [options] - Optional configuration for starting the animation.
470
+ * @param {boolean} [options.auto] - If true, indicates that the request comes from 'CanvasParticles.canvasObserver'.
471
+ * @returns {CanvasParticles} The current instance for method chaining.
463
472
  */
464
- start() {
465
- if (!this.animating) {
473
+ start(options) {
474
+ if (!this.animating && (!options?.auto || this.enableAnimating)) {
475
+ this.enableAnimating = true
466
476
  this.animating = true
467
477
  requestAnimationFrame(() => this.#animation())
468
478
  }
479
+
480
+ // Stop animating because it will start automatically once the canvas enters the viewbox
481
+ if (!this.canvas.inViewbox && this.options.animation.startOnEnter) this.animating = false
482
+
469
483
  return this
470
484
  }
471
485
 
472
486
  /**
473
- * Stops the particle animation and clears the canvas.
487
+ * Stops the particle animation and optionally clears the canvas.
488
+ *
489
+ * - If 'options.clear' is not strictly false, the canvas will be cleared.
490
+ *
491
+ * @param {Object} [options] - Optional configuration for stopping the animation.
492
+ * @param {boolean} [options.auto] - If true, indicates that the request comes from 'CanvasParticles.canvasObserver'.
493
+ * @param {boolean} [options.clear] - If strictly false, prevents clearing the canvas-.
494
+ * @returns {boolean} `true` when the animation is successfully stopped.
474
495
  */
475
496
  stop(options) {
497
+ if (!options?.auto) this.enableAnimating = false
476
498
  this.animating = false
477
499
  if (options?.clear !== false) this.canvas.width = this.canvas.width
478
500
 
@@ -527,12 +549,15 @@
527
549
  }
528
550
 
529
551
  /**
530
- * Set canvas background.
531
- * @param {string} background - The style of the background. Can be any CSS supported background format.
552
+ * Sets the canvas background.
553
+ *
554
+ * @param {string} background - The style of the background. Can be any CSS-supported background value.
555
+ * @throws {TypeError} If background is not a string.
532
556
  */
533
557
  setBackground(background) {
534
- if (typeof background === 'string') return (this.canvas.style.background = this.options.background = background), true
535
- return false
558
+ if (background === false) return
559
+ if (typeof background !== 'string') throw new TypeError('background is not a string')
560
+ this.canvas.style.background = this.options.background = background
536
561
  }
537
562
 
538
563
  /**
@@ -2,36 +2,41 @@
2
2
  // https://github.com/Khoeckman/canvasParticles/blob/main/LICENSE
3
3
 
4
4
  export default class CanvasParticles {
5
- static version = '3.5.0'
5
+ static version = '3.5.1'
6
6
 
7
7
  // Start or stop the animation when the canvas enters or exits the viewport
8
8
  static canvasObserver = new IntersectionObserver(entry => {
9
9
  entry.forEach(change => {
10
10
  // CanvasParticles instance of the target canvas
11
- const instance = change.target.instance
11
+ const canvas = change.target
12
+ const instance = canvas.instance
12
13
 
13
- if (change.isIntersecting) instance.options.animation.startOnEnter && instance.start()
14
- else instance.options.animation.stopOnLeave && instance.stop({ clear: false })
14
+ if ((canvas.inViewbox = change.isIntersecting)) instance.options.animation.startOnEnter && instance.start({ auto: true })
15
+ else instance.options.animation.stopOnLeave && instance.stop({ auto: true, clear: false })
15
16
  })
16
17
  })
17
18
 
18
19
  /**
19
20
  * Creates a new CanvasParticles instance.
20
- * @param {string} [selector] - The CSS selector for the canvas element.
21
+ * @param {string} [selector] - The CSS selector to the canvas element or the HTMLCanvasElement itself.
21
22
  * @param {Object} [options={}] - Object structure: https://github.com/Khoeckman/canvasParticles?tab=readme-ov-file#options
22
23
  */
23
24
  constructor(selector, options = {}) {
24
- // Find and initialize canvas
25
- if (typeof selector !== 'string') throw new TypeError('selector is not a string')
26
-
27
- this.canvas = document.querySelector(selector)
28
- if (!(this.canvas instanceof HTMLCanvasElement)) throw new Error('selector does not point to a canvas')
25
+ if (selector instanceof HTMLCanvasElement) this.canvas = selector
26
+ else {
27
+ // Find and initialize canvas
28
+ if (typeof selector !== 'string') throw new TypeError('selector is not a string and neither a HTMLCanvasElement itself')
29
29
 
30
- this.canvas.instance = this
30
+ this.canvas = document.querySelector(selector)
31
+ if (!(this.canvas instanceof HTMLCanvasElement)) throw new Error('selector does not point to a canvas')
32
+ }
33
+ this.canvas.instance = this // Circular assignment to find the instance bound to this canvas inside the 'canvasObserver'
34
+ this.canvas.inViewbox = true
31
35
 
32
36
  // Get 2d drawing functions
33
37
  this.ctx = this.canvas.getContext('2d')
34
38
 
39
+ this.enableAnimating = false
35
40
  this.animating = false
36
41
  this.particles = []
37
42
  this.setOptions(options)
@@ -48,7 +53,7 @@ export default class CanvasParticles {
48
53
 
49
54
  #setupEventHandlers() {
50
55
  const updateMousePos = event => {
51
- if (!this.animating) return
56
+ if (!this.enableAnimating) return
52
57
 
53
58
  if (event instanceof MouseEvent) {
54
59
  this.clientX = event.clientX
@@ -315,8 +320,8 @@ export default class CanvasParticles {
315
320
  * This is necessary because the rendering process involves up to [particles ** 2 / 2] lookups per frame.
316
321
  *
317
322
  * @private
318
- * @param {string} color - The base color in the format `#rrggbb`.
319
- * @returns {Object} - A lookup table mapping each alpha value (0–255) to its corresponding stroke style string in the format `#rrggbbaa`.
323
+ * @param {string} color - The base color in the format '#rrggbb'.
324
+ * @returns {Object} - A lookup table mapping each alpha value (0–255) to its corresponding stroke style string in the format '#rrggbbaa'.
320
325
  *
321
326
  * @example
322
327
  * const strokeStyleTable = this.#generateStrokeStyleTable("#abcdef");
@@ -326,7 +331,7 @@ export default class CanvasParticles {
326
331
  * Notes:
327
332
  * - This function precomputes all possible stroke styles by appending a two-character
328
333
  * hexadecimal alpha value (0x00–0xFF) to the base color.
329
- * - The table is stored in `this.strokeStyleTable` for quick lookups.
334
+ * - The table is stored in 'this.strokeStyleTable' for quick lookups.
330
335
  */
331
336
  #generateStrokeStyleTable(color) {
332
337
  const table = {}
@@ -450,22 +455,39 @@ export default class CanvasParticles {
450
455
 
451
456
  /**
452
457
  * Starts the particle animation.
453
- * Does nothing if already animating.
454
458
  *
455
- * @returns {CanvasParticles} - The current instance.
459
+ * - If the animation is already running, do nothing.
460
+ * - If the canvas is not within the viewbox and 'startOnEnter' is enabled, animation will be stopped until it enters the viewbox.
461
+ *
462
+ * @param {Object} [options] - Optional configuration for starting the animation.
463
+ * @param {boolean} [options.auto] - If true, indicates that the request comes from 'CanvasParticles.canvasObserver'.
464
+ * @returns {CanvasParticles} The current instance for method chaining.
456
465
  */
457
- start() {
458
- if (!this.animating) {
466
+ start(options) {
467
+ if (!this.animating && (!options?.auto || this.enableAnimating)) {
468
+ this.enableAnimating = true
459
469
  this.animating = true
460
470
  requestAnimationFrame(() => this.#animation())
461
471
  }
472
+
473
+ // Stop animating because it will start automatically once the canvas enters the viewbox
474
+ if (!this.canvas.inViewbox && this.options.animation.startOnEnter) this.animating = false
475
+
462
476
  return this
463
477
  }
464
478
 
465
479
  /**
466
- * Stops the particle animation and clears the canvas.
480
+ * Stops the particle animation and optionally clears the canvas.
481
+ *
482
+ * - If 'options.clear' is not strictly false, the canvas will be cleared.
483
+ *
484
+ * @param {Object} [options] - Optional configuration for stopping the animation.
485
+ * @param {boolean} [options.auto] - If true, indicates that the request comes from 'CanvasParticles.canvasObserver'.
486
+ * @param {boolean} [options.clear] - If strictly false, prevents clearing the canvas-.
487
+ * @returns {boolean} `true` when the animation is successfully stopped.
467
488
  */
468
489
  stop(options) {
490
+ if (!options?.auto) this.enableAnimating = false
469
491
  this.animating = false
470
492
  if (options?.clear !== false) this.canvas.width = this.canvas.width
471
493
 
@@ -520,12 +542,15 @@ export default class CanvasParticles {
520
542
  }
521
543
 
522
544
  /**
523
- * Set canvas background.
524
- * @param {string} background - The style of the background. Can be any CSS supported background format.
545
+ * Sets the canvas background.
546
+ *
547
+ * @param {string} background - The style of the background. Can be any CSS-supported background value.
548
+ * @throws {TypeError} If background is not a string.
525
549
  */
526
550
  setBackground(background) {
527
- if (typeof background === 'string') return (this.canvas.style.background = this.options.background = background), true
528
- return false
551
+ if (background === false) return
552
+ if (typeof background !== 'string') throw new TypeError('background is not a string')
553
+ this.canvas.style.background = this.options.background = background
529
554
  }
530
555
 
531
556
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasparticles-js",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "description": "In an HTML canvas, a bunch of interactive particles connected with lines when they approach each other.",
5
5
  "main": "canvasParticles.js",
6
6
  "module": "canvasParticles.mjs",