npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

Readme

Classic Thumb Viewer

npm version npm downloads license

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-viewer

CDN

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 V360ClassicThumbViewer instance
  • Multiple elements: Returns an array of V360ClassicThumbViewer instances
// 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 instances

API 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

  1. Initial State: The component displays a still image from stillUrl
  2. On Hover: When the user hovers over the image, the 360° viewer is initialized
  3. Interactive: User can then drag to rotate the diamond in 360°
  4. 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 dev

Build

# Build for production
npm run build

# Output will be in the dist/ directory

Architecture

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

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support

For issues and questions, please open an issue on GitHub.