How to configure equirectangular tile images in photo sphere viewer 360 load

Summary

The issue described is a blank panorama in Photo Sphere Viewer v5.14.1 despite correct JSON and tile URL accessibility. This postmortem identifies the root cause as a dynamic path resolution failure combined with potential CORS and MIME type restrictions inherent in ASP.NET Framework environments serving ES modules and textures. The viewer initializes, but the rendering pipeline fails to fetch or compile the tile resources.

Root Cause

The failure stems from a mismatch between the base path of the module imports and the absolute URLs used for data and tile fetching within the ASP.NET application context.

  • Absolute Path Misinterpretation: The Viewer constructor receives panorama.json and tileUrl callbacks returning paths starting with / (e.g., /virtualtour/19/data.json). While this works for standard HTTP requests, the ES module loader and Three.js texture loader often resolve relative to the current document or the module’s origin. If the application is hosted in a virtual directory or a sub-path, these absolute root paths can fail to resolve correctly relative to the expected context.
  • CORS Policy Blocking: ASP.NET Framework (IIS) enforces strict CORS policies. While the browser can fetch HTML and JS from the CDN, fetching textures (JPG) and data (JSON) from the same origin but different virtual paths often triggers CORS pre-flight checks. Without explicit Access-Control-Allow-Origin headers, the browser blocks the texture load.
  • MIME Type Configuration: IIS often serves .json files with incorrect MIME types (or blocks them entirely) unless explicitly configured in web.config. If data.json is served as text/plain or application/octet-stream, the Fetch API might reject the response or fail to parse it, halting the initialization of the tile adapter.

Why This Happens in Real Systems

  • Virtual Directory Complexity: ASP.NET MVC applications are frequently deployed to virtual directories (e.g., https://localhost/virtualtour/). Hardcoded absolute paths (/virtualtour/...) assume the application is at the root, causing 404s when the application is nested.
  • ES Module Strictness: Browsers treat ES modules fetched via CDN with strict origin policies. Texture loaders in Three.js (used by Photo Sphere Viewer) perform asynchronous fetches. If the server responds with a CORS error or an unsupported MIME type, the TextureLoader fails silently or logs a console error that isn’t immediately obvious in production debugging.
  • IIS Static File Handling: By default, IIS is configured to serve common static files (images, CSS) but often restricts .json files or maps them to handlers that require specific verbs (GET/POST). This causes the data.json fetch to return a 404 or 403 error despite the file existing physically on the disk.

Real-World Impact

  • Broken User Experience: End-users see an empty container, rendering the virtual tour useless.
  • Silent Failures: The application loads without JavaScript syntax errors, making debugging difficult. Developers must inspect the Network tab to identify blocked requests.
  • Performance Degradation: If CORS is partially configured, the browser may retry failed requests or hang on pending connections, slowing down the page load.

Example or Code

To fix the ASP.NET configuration, you must update web.config to allow JSON MIME types and configure CORS headers.

Web.config (MIME Types & Headers):


  
    
      
    
    
      
        
      
    
    
      
      
    
  

Corrected JavaScript (Dynamic Path Resolution):
Instead of hardcoded absolute paths, use the browser’s location object to construct dynamic paths relative to the current page.

import { Viewer } from 'https://cdn.jsdelivr.net/npm/@photo-sphere-viewer/core@5.14.1/index.module.min.js';
import { EquirectangularTilesAdapter } from 'https://cdn.jsdelivr.net/npm/@photo-sphere-viewer/equirectangular-tiles-adapter@5.14.1/index.module.min.js';

// Construct dynamic base path to handle virtual directories
const basePath = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/'));
const jsonPath = `${basePath}/data.json`;
const tilePrefix = `${basePath}/tiles`;

const viewer = new Viewer({
    container: document.getElementById('viewer'),
    adapter: EquirectangularTilesAdapter,
    panorama: {
        json: jsonPath,
        tileUrl: (level, col, row) => `${tilePrefix}/${level}/${row}_${col}.jpg`
    }
});

How Senior Engineers Fix It

Senior engineers approach this by isolating the request chain and environment configuration:

  1. Verify Network Requests: Use Chrome DevTools Network tab to inspect the data.json and tile requests. Look for CORS errors (red text in console) or MIME type mismatches.
  2. Standardize Paths: Replace absolute paths (/path/...) with relative paths computed at runtime. This ensures the application works regardless of whether it is hosted at the root or in a virtual directory.
  3. Configure the Server: Explicitly define MIME types in web.config (for .NET Framework) and ensure GET verbs are allowed for static file extensions. If necessary, implement a HttpModule or middleware to inject CORS headers dynamically.
  4. Isolate the Adapter: Ensure the EquirectangularTilesAdapter is imported correctly and that the three dependency matches the version expected by the viewer (using importmap).

Why Juniors Miss It

Junior developers often lack experience with server-level configuration and module scoping:

  • Focus on Syntax Only: They assume that if the JavaScript loads without syntax errors, it will execute correctly. They often miss runtime errors caused by network requests (404, CORS, 403).
  • Ignoring Server Configuration: They assume the web server (IIS) serves all file types by default. They rarely check web.config for MIME type restrictions or CORS policies.
  • Hardcoded Paths: They often use paths that work on their local development environment (usually root-based) without considering deployment variations (virtual directories), leading to “it works on my machine” syndrome.
  • Misunderstanding ES Modules: They may not realize that ES modules have stricter security policies (CORS) than traditional <script> tags, causing silent failures when loading textures from the same origin.