spinit-js 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/package.json +1 -1
- package/src/SpinIT.js +50 -15
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
A lightweight, high-performance JavaScript library for 360-degree image rotation. Perfect for product displays and interactive image viewers.
|
|
4
4
|
|
|
5
|
+
[**Explore the Live Demo Showcase**](https://static.billgr17.click/spinit/)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
## Features
|
|
6
10
|
|
|
7
11
|
- **No Dependencies**: No external libraries required.
|
|
@@ -62,6 +66,7 @@ const spinit = new SpinIT("#spinit-container", ["img_##.jpg", 1, 90], {
|
|
|
62
66
|
| `autoplay` | `Boolean` \| `Number` | `true` | If true, spins automatically until user interaction. If a number, auto-spins until that frame index. |
|
|
63
67
|
| `autoplaySpeed` | `Number` | `24` | Autoplay speed in Frames Per Second (FPS). |
|
|
64
68
|
| `debug` | `Boolean` | `false` | Enables debug mode. |
|
|
69
|
+
| `lazyload` | `Boolean` | `true` | Enables lazy load the SpinIT container. |
|
|
65
70
|
|
|
66
71
|
|
|
67
72
|
## License
|
package/package.json
CHANGED
package/src/SpinIT.js
CHANGED
|
@@ -30,6 +30,7 @@ export class SpinIT {
|
|
|
30
30
|
preload: options.preload ?? "all",
|
|
31
31
|
autoplay: options.autoplay ?? true,
|
|
32
32
|
autoplaySpeed: options.autoplaySpeed ?? 24,
|
|
33
|
+
lazyload: options.lazyload ?? true,
|
|
33
34
|
debug: options.debug ?? false
|
|
34
35
|
};
|
|
35
36
|
|
|
@@ -48,8 +49,32 @@ export class SpinIT {
|
|
|
48
49
|
|
|
49
50
|
this.canvas = null;
|
|
50
51
|
this.ctx = null;
|
|
52
|
+
this.observer = null;
|
|
53
|
+
this.isDestroyed = false;
|
|
51
54
|
|
|
52
|
-
this
|
|
55
|
+
if (this.options.lazyload && 'IntersectionObserver' in window) {
|
|
56
|
+
this.#setupLazyLoad(source);
|
|
57
|
+
} else {
|
|
58
|
+
this.#init(source);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#setupLazyLoad(source) {
|
|
63
|
+
this.#log("SpinIT: Setting up lazyload...");
|
|
64
|
+
|
|
65
|
+
this.observer = new IntersectionObserver((entries) => {
|
|
66
|
+
entries.forEach(entry => {
|
|
67
|
+
if (entry.isIntersecting) {
|
|
68
|
+
this.#log("SpinIT: Container is visible, initializing...");
|
|
69
|
+
this.#init(source);
|
|
70
|
+
this.observer.unobserve(this.container);
|
|
71
|
+
this.observer.disconnect();
|
|
72
|
+
this.observer = null;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}, { rootMargin: '50px' });
|
|
76
|
+
|
|
77
|
+
this.observer.observe(this.container);
|
|
53
78
|
}
|
|
54
79
|
|
|
55
80
|
#log(...args) {
|
|
@@ -62,7 +87,7 @@ export class SpinIT {
|
|
|
62
87
|
|
|
63
88
|
async #init(source) {
|
|
64
89
|
this.#log("SpinIT: Initializing with source:", source);
|
|
65
|
-
|
|
90
|
+
|
|
66
91
|
// 1. Inject styles and show loader
|
|
67
92
|
Renderer.injectStyles();
|
|
68
93
|
Renderer.showLoader(this.container);
|
|
@@ -72,10 +97,12 @@ export class SpinIT {
|
|
|
72
97
|
const preloadCount = isPreloadingAll ? 1 : Math.max(1, this.options.preload);
|
|
73
98
|
|
|
74
99
|
const preloadUrls = urls.slice(0, preloadCount);
|
|
75
|
-
|
|
100
|
+
|
|
76
101
|
// 2. Preload the specified number of images to show something immediately
|
|
77
102
|
const preloadedImages = await Loader.preloadImages(preloadUrls, this.options.debug);
|
|
78
|
-
|
|
103
|
+
|
|
104
|
+
if (this.isDestroyed) return;
|
|
105
|
+
|
|
79
106
|
if (preloadedImages.length === 0) {
|
|
80
107
|
this.#error("SpinIT Error: Could not load the initial images.");
|
|
81
108
|
Renderer.hideLoader(this.container);
|
|
@@ -85,10 +112,10 @@ export class SpinIT {
|
|
|
85
112
|
// Initialize this.images array with the correct length to allow correct math in physics
|
|
86
113
|
this.images = new Array(urls.length);
|
|
87
114
|
for (let i = 0; i < preloadedImages.length; i++) {
|
|
88
|
-
|
|
115
|
+
this.images[i] = preloadedImages[i];
|
|
89
116
|
}
|
|
90
117
|
const { width, height } = preloadedImages[0];
|
|
91
|
-
|
|
118
|
+
|
|
92
119
|
// 3. Initialize canvas
|
|
93
120
|
const { canvas, ctx } = Renderer.initCanvas(this.container, width, height, this.options.responsive);
|
|
94
121
|
this.canvas = canvas;
|
|
@@ -109,6 +136,7 @@ export class SpinIT {
|
|
|
109
136
|
this.#log("SpinIT: First frame rendered with blur. Loading remaining images...");
|
|
110
137
|
|
|
111
138
|
Loader.preloadImages(urls, this.options.debug).then(allImages => {
|
|
139
|
+
if (this.isDestroyed) return;
|
|
112
140
|
this.#log(`SpinIT: Preloaded ${allImages.length} images. Clearing loading state...`);
|
|
113
141
|
this.images = allImages;
|
|
114
142
|
Renderer.applyBlur(this.canvas, false);
|
|
@@ -128,10 +156,11 @@ export class SpinIT {
|
|
|
128
156
|
const remainingUrls = urls.slice(preloadCount);
|
|
129
157
|
const remainingPromises = remainingUrls.map((url, i) => {
|
|
130
158
|
return Loader.preloadImages([url], this.options.debug).then(([img]) => {
|
|
159
|
+
if (this.isDestroyed) return;
|
|
131
160
|
const index = preloadCount + i;
|
|
132
161
|
this.images[index] = img;
|
|
133
162
|
if (this.currentFrame === index) {
|
|
134
|
-
|
|
163
|
+
this.render();
|
|
135
164
|
}
|
|
136
165
|
});
|
|
137
166
|
});
|
|
@@ -255,11 +284,11 @@ export class SpinIT {
|
|
|
255
284
|
*/
|
|
256
285
|
render() {
|
|
257
286
|
Renderer.renderFrame(
|
|
258
|
-
this.ctx,
|
|
259
|
-
this.images[this.currentFrame],
|
|
260
|
-
this.canvas.width,
|
|
261
|
-
this.canvas.height,
|
|
262
|
-
this.options.debug,
|
|
287
|
+
this.ctx,
|
|
288
|
+
this.images[this.currentFrame],
|
|
289
|
+
this.canvas.width,
|
|
290
|
+
this.canvas.height,
|
|
291
|
+
this.options.debug,
|
|
263
292
|
this.currentFrame
|
|
264
293
|
);
|
|
265
294
|
}
|
|
@@ -268,7 +297,13 @@ export class SpinIT {
|
|
|
268
297
|
* Destroys the SpinIT instance and cleans up.
|
|
269
298
|
*/
|
|
270
299
|
destroy() {
|
|
300
|
+
this.isDestroyed = true;
|
|
271
301
|
this.#stopAutoPlay();
|
|
302
|
+
if (this.observer) {
|
|
303
|
+
this.observer.unobserve(this.container);
|
|
304
|
+
this.observer.disconnect();
|
|
305
|
+
this.observer = null;
|
|
306
|
+
}
|
|
272
307
|
if (this.resizeObserver) {
|
|
273
308
|
this.resizeObserver.disconnect();
|
|
274
309
|
}
|
|
@@ -283,9 +318,9 @@ export class SpinIT {
|
|
|
283
318
|
|
|
284
319
|
#startAutoPlay() {
|
|
285
320
|
if (this.options.autoplay === false) return;
|
|
286
|
-
|
|
321
|
+
|
|
287
322
|
this.isAutoPlaying = true;
|
|
288
|
-
|
|
323
|
+
|
|
289
324
|
let targetFrame = null;
|
|
290
325
|
if (typeof this.options.autoplay === 'number') {
|
|
291
326
|
targetFrame = this.options.autoplay;
|
|
@@ -299,7 +334,7 @@ export class SpinIT {
|
|
|
299
334
|
}
|
|
300
335
|
|
|
301
336
|
this.updateFrame(-this.options.sensitivity);
|
|
302
|
-
|
|
337
|
+
|
|
303
338
|
if (targetFrame !== null && this.currentFrame === targetFrame) {
|
|
304
339
|
this.#stopAutoPlay();
|
|
305
340
|
} else if (!this.options.loop && this.currentFrame === this.images.length - 1) {
|