Hosting a spinner¶
Warning
Online spinner publishing is only available to PRO subscription plan users.
Overview¶
This page describes how to host the Maverick Excelsior Spinner component on your own website for embedding interactive 360° product views.
Self-hosting the spinner is the preferred method if you wish to:
- Embed spinners directly in your website.
- Have full control over the spinner's branding, appearance and behavior.
- Avoid CORS restrictions and improve loading performance.
A perfect example of this can be found in our Jewelry Catalog Showcase:
Jewelry Catalog Showcase - Gemstones
Advantages of self-hosting¶
| Advantage | Explanation |
|---|---|
| True embedding | The spinner becomes part of your page, not an external frame. |
| No CORS issues | Hosting everything on your domain avoids cross-origin problems. |
| Customization | Full control over styling and integration with your site. |
| Performance | Faster loading when spinner and images are on the same domain. |
Step-by-step guide¶
1. Include the spinner library¶
Add to your webpage the spinner JavaScript library from the CDN link below:
<script src="https://cdn.jsdelivr.net/gh/randomcontrol/webex-spinner@latest/webex-spinner.min.js"></script>
2. Create the HTML structure¶
Add a canvas element where the spinner will be rendered:
<div class="spinner-container">
<canvas id="product-spinner" width="800" height="800"></canvas>
<div class="spinner-loading">Loading...</div>
</div>
3. Add CSS styling¶
.spinner-container {
position: relative;
max-width: 800px;
margin: 0 auto;
}
.spinner-container canvas {
width: 100%;
height: auto;
display: block;
cursor: grab;
}
.spinner-container canvas:active {
cursor: grabbing;
}
.spinner-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.7);
color: white;
padding: 10px 20px;
border-radius: 5px;
}
4. Initialize the spinner¶
document.addEventListener('DOMContentLoaded', function() {
const spinner = new webex_spinner_c(
document.getElementById('product-spinner'),
{
images: [
'/products/ring/atlas_0000.jpg',
'/products/ring/atlas_0001.jpg',
'/products/ring/atlas_0002.jpg',
// ... add all your atlas images.
],
poster: '/products/ring/poster.jpg',
nx: 4, // tiles per row.
ny: 1, // tiles per column.
fps: 30,
autoplay: true,
draggable: true,
loop: true,
preload_amount: 15,
on_full_preload_finished: function() {
document.querySelector('.spinner-loading').style.display = 'none';
}
}
);
});
5. Advanced configuration¶
Generating image arrays dynamically¶
Instead of listing each image manually, you can generate the array:
// Generate image array for 135 frames.
const frameCount = 135;
const imagePath = '/products/ring/';
const images = Array.from({length: frameCount}, (_, i) => {
const frameNumber = String(i).padStart(4, '0');
return `${imagePath}atlas_${frameNumber}.jpg`;
});
Multiple spinners on one page¶
const spinner_1 = new webex_spinner_c(
document.getElementById('spinner-1'),
{
images: generateImageArray('/products/ring/', 135),
poster: '/products/ring/poster.jpg',
// ... other options.
}
);
const spinner_2 = new webex_spinner_c(
document.getElementById('spinner-2'),
{
images: generateImageArray('/products/bracelet/', 120),
poster: '/products/bracelet/poster.jpg',
// ... other options.
}
);
Creating a product gallery¶
Here's an example of how to create a gallery with multiple spinners:
<div class="product-gallery">
<div class="product-item" data-spinner-path="/products/ring/" data-frames="135">
<canvas id="spinner-ring" width="400" height="400"></canvas>
<h3>Diamond Ring</h3>
</div>
<div class="product-item" data-spinner-path="/products/necklace/" data-frames="120">
<canvas id="spinner-necklace" width="400" height="400"></canvas>
<h3>Pearl Necklace</h3>
</div>
</div>
<script>
document.querySelectorAll('.product-item').forEach(item => {
const canvas = item.querySelector('canvas');
const path = item.dataset.spinnerPath;
const frames = parseInt(item.dataset.frames);
// Generate image array.
const images = Array.from({length: frames}, (_, i) => {
return `${path}atlas_${String(i).padStart(4, '0')}.jpg`;
});
// Initialize spinner.
new webex_spinner_c(canvas, {
images: images,
poster: `${path}poster.jpg`,
nx: 4,
ny: 1,
autoplay: false, // Don't autoplay in gallery.
draggable: true
});
});
</script>
API reference¶
Constructor options¶
| Option | Type | Default | Description |
|---|---|---|---|
images | Array | required | Array of atlas image URLs |
poster | String | false | URL of poster image |
nx | Number | 4 | Tiles per row in atlas |
ny | Number | 1 | Tiles per column in atlas |
fps | Number | 30 | Frames per second |
autoplay | Boolean | true | Start spinning automatically |
draggable | Boolean | true | Enable mouse/touch drag |
loop | Boolean | true | Loop the animation |
preload_amount | Number | 0 | Frames to preload before starting |
Methods¶
// Control playback.
spinner.play();
spinner.stop();
// Set options.
spinner.set_reverse(true); // Reverse playback direction.
spinner.set_option('fps', 60); // Change frame rate.
// Get information.
const currentFrame = spinner.get_current_frame();
const totalFrames = spinner.get_total_frames();
const isRunning = spinner.is_running();
// Destroy spinner.
spinner.destroy();
Events¶
The spinner dispatches custom events you can listen to:
canvas.addEventListener('webex-spinner:loading-progress', (e) => {
console.log(`Loading: ${e.detail.progress * 100}%`);
});
canvas.addEventListener('webex-spinner:full-preload-finished', () => {
console.log('All frames loaded');
});
Troubleshooting¶
Common issues¶
- CORS errors: Ensure images are served from the same domain or have proper CORS headers.
- Performance issues: Reduce frame count or image quality for smoother playback.
- Mobile touch not working: Ensure the canvas has
touch-action: noneCSS property.
Tip
For production use, always test your spinners on various devices and connection speeds to ensure optimal performance for all users.