@v360-tech/v360-classic-thumb-viewer
v1.3.1
Published
A lightweight ESM-based web component for Vision360 thumbnail viewer with hover-activated 360° diamond viewing
Downloads
18
Maintainers
Readme
Classic Thumb Viewer
A lightweight JavaScript wrapper for the Vision360 small viewer. This component provides a thumbnail-style viewer that shows a still image initially and activates the 360-degree viewer on hover.
Features
- 🖼️ Thumbnail Mode: Shows still image initially, activates on hover
- 360° Interactive Viewing: Smooth rotation on mouse interaction
- ⚡ Lazy Loading: Only loads 360° viewer when user hovers
- 🎨 Customizable: Control rotation speed, direction, and autoplay
- 📦 Self-contained: All dependencies bundled (jQuery, Vision360)
- 💪 Plain JavaScript API: Simple programmatic initialization
- 🚀 Lightweight: Minimal overhead, optimized for performance
- 🤖 Smart Initialization: Automatically handles single or multiple elements
- 📝 Fully Data-Driven: All options can be configured via data attributes for 100% declarative HTML setup
Installation
NPM
npm install @v360-tech/v360-classic-thumb-viewerCDN
ES Module (Recommended)
<script type="module">
import "@v360-tech/v360-classic-thumb-viewer";
</script>Or use unpkg:
<script
type="module"
src="https://unpkg.com/@v360-tech/v360-classic-thumb-viewer/dist/v360-classic-thumb-viewer.js"
></script>UMD (Browser Global)
<script src="https://unpkg.com/@v360-tech/v360-classic-thumb-viewer/dist/v360-classic-thumb-viewer.browser.js"></script>Usage
Basic Example
<!DOCTYPE html>
<html>
<head>
<script type="module">
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
// Initialize when DOM is ready
document.addEventListener("DOMContentLoaded", () => {
const viewer = new V360ClassicThumbViewer({
container: "#viewer-container",
assetName: "Beautiful Diamond",
path: "https://your-cdn.com/360-images/",
width: "500",
minHeight: "400",
});
});
</script>
</head>
<body>
<div id="viewer-container"></div>
</body>
</html>Using data-name Attribute
You can also specify the asset name using the data-name attribute on the container:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
document.addEventListener("DOMContentLoaded", () => {
// assetName taken from data-name attribute
const viewer = new V360ClassicThumbViewer({
container: "#viewer-container",
path: "https://your-cdn.com/360-images/",
width: "500",
minHeight: "400",
});
});
</script>
</head>
<body>
<div id="viewer-container" data-name="Beautiful Diamond"></div>
</body>
</html>Using Data Attributes (HTML-Driven)
For a completely HTML-driven approach, all options can be specified as data attributes:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
document.addEventListener("DOMContentLoaded", () => {
// All configuration from data attributes
const viewer = new V360ClassicThumbViewer({
container: "#viewer-container",
});
});
</script>
</head>
<body>
<div
id="viewer-container"
data-name="Beautiful Diamond"
data-path="https://your-cdn.com/360-images/"
data-width="500"
data-min-height="400"
data-autoplay="1"
data-anticlock-rotation="0"
></div>
</body>
</html>Available Data Attributes:
data-name- Asset name (required if not in options)data-path- Path to asset folder (required if not in options)data-still-url- Custom still image URL (optional)data-width- Width of viewer (optional, default: 200)data-min-height- Minimum height in pixels (optional, default: 128)data-autoplay- Auto rotation: 0 = off, 1 = on (optional, default: 0)data-anticlock-rotation- Rotation direction: 0 = clockwise, 1 = counterclockwise (optional, default: 0)
Using Class Selector
The container can be targeted using class selectors. If the selector matches a single element, a single instance is returned. If it matches multiple elements, all are automatically initialized:
<div class="diamond-viewer" data-name="Premium Diamond"></div>
<script type="module">
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
// Single element - returns single instance
const viewer = new V360ClassicThumbViewer({
container: ".diamond-viewer",
path: "https://your-cdn.com/360-images/",
});
</script>Multiple Instances with Same Class
When a selector matches multiple elements, the component automatically initializes all of them and returns an array of instances:
<div class="diamond-viewer" data-name="Diamond 1"></div>
<div class="diamond-viewer" data-name="Diamond 2"></div>
<div class="diamond-viewer" data-name="Diamond 3"></div>
<script type="module">
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
// Automatically initializes all elements with class "diamond-viewer"
const viewers = new V360ClassicThumbViewer({
container: ".diamond-viewer",
path: "https://your-cdn.com/360-images/",
});
// viewers is now an array of instances
</script>Fully HTML-Driven Multiple Instances
For maximum flexibility, use data attributes for all configuration:
<div
class="diamond-viewer"
data-name="Diamond 1"
data-path="https://cdn.example.com/diamonds/1/"
data-width="300"
data-autoplay="1"
></div>
<div
class="diamond-viewer"
data-name="Diamond 2"
data-path="https://cdn.example.com/diamonds/2/"
data-width="400"
data-min-height="300"
></div>
<div
class="diamond-viewer"
data-name="Diamond 3"
data-path="https://cdn.example.com/diamonds/3/"
data-width="350"
data-autoplay="1"
data-anticlock-rotation="1"
></div>
<script type="module">
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
// One line initialization - all config from HTML!
const viewers = new V360ClassicThumbViewer({
container: ".diamond-viewer",
});
</script>Advanced Example
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
const viewer = new V360ClassicThumbViewer({
container: document.getElementById("viewer-container"), // or CSS selector
assetName: "Premium Diamond",
path: "https://cdn.example.com/diamonds/premium/",
width: "600",
minHeight: "500",
autoPlay: 1,
antiClockRotation: 0,
// stillUrl: "https://cdn.example.com/diamonds/premium/custom-still.jpg", // Optional: defaults to {path}/imaged/{assetName}/still.jpg
});
// Later, clean up when done
// viewer.destroy();Multiple Viewers
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
// Create multiple viewers
const viewer1 = new V360ClassicThumbViewer({
container: "#viewer-1",
assetName: "Diamond 1",
path: "https://example.com/diamonds/1/",
});
const viewer2 = new V360ClassicThumbViewer({
container: "#viewer-2",
assetName: "Diamond 2",
path: "https://example.com/diamonds/2/",
stillUrl: "https://example.com/diamonds/2/custom-still.jpg", // Optional: custom still image
});Configuration Options
| Option | Type | Required | Default | Data Attribute | Description |
| ------------------- | ----------------- | -------- | ------------------------------------- | ------------------------- | --------------------------------------------------------------------------------------------- |
| container | String | Element | Yes | - | - | CSS selector or DOM element. If selector matches multiple elements, all are initialized |
| assetName | String | No | From data attribute | data-name | Name of the asset. Can be provided as option or data attribute |
| path | String | No | From data attribute | data-path | Path to the asset folder containing 360° image frames. Can be provided as option or data attr |
| stillUrl | String | No | {path}/imaged/{assetName}/still.jpg | data-still-url | URL to the still preview image. Auto-generated if not provided |
| width | Number | String | No | 200 | data-width | Width of the viewer (e.g., 500 or "500px") |
| minHeight | Number | No | 128 | data-min-height | Minimum height of the viewer in pixels |
| autoPlay | Number | No | 0 | data-autoplay | Whether to autoplay rotation (0 = off, 1 = on) |
| antiClockRotation | Number | No | 0 | data-anticlock-rotation | Rotation direction (0 = clockwise, 1 = counterclockwise) |
Return Value
The constructor returns different values based on the number of matching elements:
- Single element: Returns a single
V360ClassicThumbViewerinstance - Multiple elements: Returns an array of
V360ClassicThumbViewerinstances
// Single instance
const viewer = new V360ClassicThumbViewer({
container: "#viewer",
path: "/assets/360",
});
// viewer is a V360ClassicThumbViewer instance
// Multiple instances
const viewers = new V360ClassicThumbViewer({
container: ".diamond-viewer",
path: "/assets/360",
});
// viewers is an array of V360ClassicThumbViewer instancesAPI Methods
destroy()
Cleans up the viewer and removes all event listeners.
const viewer = new V360ClassicThumbViewer({
container: "#viewer",
// ... options
});
// Clean up when done
viewer.destroy();
// For multiple instances
const viewers = new V360ClassicThumbViewer({
container: ".viewers",
// ... options
});
// Clean up all
viewers.forEach((v) => v.destroy());How It Works
- Initial State: The component displays a still image from
stillUrl - On Hover: When the user hovers over the image, the 360° viewer is initialized
- Interactive: User can then drag to rotate the diamond in 360°
- Lazy Loading: The full 360° image set is only loaded when needed, improving initial page load
Technical Details
- Built with vanilla JavaScript (no framework dependencies)
- Plain JavaScript class with programmatic initialization
- Smart initialization: Automatically handles single or multiple elements
- Bundles jQuery 1.8.3 internally
- ESM and UMD builds available
- Dynamic script loading for lazy initialization
- No Web Components - pure JavaScript class for maximum compatibility
Development
Prerequisites
- Node.js 16+
- npm or yarn
Setup
# Clone the repository
git clone https://github.com/v360tech/classic-thumb-viewer.git
cd classic-thumb-viewer
# Install dependencies
npm install
# Start development server
npm run devBuild
# Build for production
npm run build
# Output will be in the dist/ directoryArchitecture
This component is a plain JavaScript class that:
- Direct DOM Manipulation: Creates container elements and injects styles into document head
- Global Styles: Styles are injected globally (required for Vision360)
- jQuery Integration: Vision360 jQuery plugin requires jQuery for direct DOM access
- Async Script Loading: Dynamically loads jQuery and Vision360 plugin on initialization
- Simple Lifecycle: Initializes viewer when scripts load and DOM is ready
Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Any modern browser with ES6+ support
Framework Examples
React
import { useEffect, useRef } from "react";
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
function App() {
const viewerRef = useRef(null);
const viewerInstanceRef = useRef(null);
useEffect(() => {
if (viewerRef.current && !viewerInstanceRef.current) {
viewerInstanceRef.current = new V360ClassicThumbViewer({
container: viewerRef.current,
assetName: "Beautiful Diamond",
path: "https://example.com/diamonds/",
width: 500,
minHeight: 400,
});
}
return () => {
if (viewerInstanceRef.current) {
viewerInstanceRef.current.destroy();
viewerInstanceRef.current = null;
}
};
}, []);
return <div ref={viewerRef}></div>;
}Vue
<template>
<div ref="viewerContainer"></div>
</template>
<script>
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
export default {
name: "DiamondViewer",
mounted() {
this.viewer = new V360ClassicThumbViewer({
container: this.$refs.viewerContainer,
assetName: "Beautiful Diamond",
path: "https://example.com/diamonds/",
width: 500,
minHeight: 400,
});
},
beforeUnmount() {
if (this.viewer) {
this.viewer.destroy();
}
},
};
</script>Angular
import {
Component,
ElementRef,
ViewChild,
AfterViewInit,
OnDestroy,
} from "@angular/core";
import V360ClassicThumbViewer from "@v360-tech/v360-classic-thumb-viewer";
@Component({
selector: "app-diamond-viewer",
template: "<div #viewerContainer></div>",
})
export class DiamondViewerComponent implements AfterViewInit, OnDestroy {
@ViewChild("viewerContainer") viewerContainer!: ElementRef;
private viewer: any;
ngAfterViewInit() {
this.viewer = new V360ClassicThumbViewer({
container: this.viewerContainer.nativeElement,
assetName: "Beautiful Diamond",
path: "https://example.com/diamonds/",
width: 500,
minHeight: 400,
});
}
ngOnDestroy() {
if (this.viewer) {
this.viewer.destroy();
}
}
}Technical Notes
Plain JavaScript Implementation
This component is implemented as a plain JavaScript class (not Web Components):
class V360ClassicThumbViewer {
constructor(options) {
// Initialize with options
}
}Why Plain JavaScript?
- Vision360 is a legacy jQuery plugin that requires direct DOM access
- Maximum compatibility across all browsers and frameworks
- No framework dependencies or polyfills needed
- Simple, straightforward API
- Easy to integrate with any JavaScript framework
Benefits:
- ✅ Universal compatibility - works everywhere
- ✅ No polyfills required
- ✅ Framework-agnostic design
- ✅ Full Vision360 functionality
- ✅ Lightweight and maintainable
Multiple Instances
This component supports multiple instances on the same page with smart automatic initialization:
- Automatic detection: If a selector matches multiple elements, all are initialized automatically
- Single call: No need for loops or manual iteration
- Each instance manages its own viewer independently
- Global styles and scripts are loaded once and shared
- Unique IDs prevent conflicts between instances
- Returns array when multiple, single instance when one element
License
MIT License - see LICENSE file for details
Author
ymkapuriya (Yogesh Kapuriya)
Links
- NPM Package: @v360-tech/v360-classic-thumb-viewer
- GitHub Repository: v360tech/classic-thumb-viewer
- Issues: Report a bug or request a feature
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support
For issues and questions, please open an issue on GitHub.
