🌀 How to Build an SPFx Web Part for 360° Image Viewing Using Photo Sphere Viewer v5
In this tutorial, you’ll learn how to create a React-based SPFx Web Part that displays equirectangular 360° images in SharePoint Online using the Photo Sphere Viewer (PSV) library, version v5+.
By the end, you’ll have a working Web Part named Image360Viewer with support for rotation, zoom, and fullscreen inside SharePoint.
✅ Requirements
- Node.js (v16+ recommended)
- SharePoint Framework (SPFx v1.13+)
- Gulp CLI
- Basic knowledge of React + TypeScript
- A 2:1 equirectangular image (e.g.
.jpgor.png)
🔧 Technical Steps
1. Create the SPFx Web Part
yo @microsoft/sharepoint
Choose:
- Solution Name:
Image360Viewer - Web Part Name:
Image360Viewer - Framework: React
- Online Workbench: Yes
2. Install Required Packages
npm install photo-sphere-viewer three
⚠️ Note: Even if your
package.jsonsays4.8.1, Webpack may resolve tov5+. The v5 API usesdefaultLong,defaultLat, andfov.
3. Create the React Component
Path: src/webparts/image360Viewer/components/Image360Viewer.tsx
import * as React from 'react';
import { useRef, useEffect } from 'react';
import styles from './Image360Viewer.module.scss';
import type { IImage360ViewerProps } from './IImage360ViewerProps';
import { Viewer } from 'photo-sphere-viewer';
import 'photo-sphere-viewer/dist/photo-sphere-viewer.css';
import * as THREE from 'three';
// PSV v5 requires THREE to be globally available
(window as any).THREE = THREE;
const Image360Viewer: React.FC<IImage360ViewerProps> = (props) => {
const containerRef = useRef<HTMLDivElement>(null);
const viewerRef = useRef<any>(null);
useEffect(() => {
if (!containerRef.current || !props.imageUrl) return;
if (viewerRef.current) {
viewerRef.current.destroy();
viewerRef.current = null;
}
viewerRef.current = new Viewer({
container: containerRef.current,
panorama: props.imageUrl,
caption: props.caption || '',
defaultLong: Number(props.defaultYaw) || 0,
defaultLat: Number(props.defaultPitch) || 0,
fov: props.defaultFov || 70,
mousewheel: props.mouseWheel !== false,
touchmoveTwoFingers: true,
minFov: 30,
maxFov: 90,
autorotateDelay: props.autorotate ? 1000 : undefined,
autorotateSpeed: props.autorotate ? '1rpm' : 0,
navbar: [
...(props.showZoom ? ['zoom'] : []),
...(props.showAutorotate ? ['autorotate'] : []),
...(props.showFullscreen ? ['fullscreen'] : [])
]
});
return () => {
viewerRef.current?.destroy();
viewerRef.current = null;
};
}, [props]);
return (
<div
ref={containerRef}
className={styles.viewer}
style={{
width: props.width || '100%',
height: props.height || '480px'
}}
/>
);
};
export default Image360Viewer;
4. Define the Props Interface
Path: src/webparts/image360Viewer/components/IImage360ViewerProps.ts
export interface IImage360ViewerProps {
imageUrl: string;
caption?: string;
defaultYaw?: string;
defaultPitch?: string;
defaultFov?: number;
mouseWheel?: boolean;
autorotate?: boolean;
showZoom?: boolean;
showAutorotate?: boolean;
showFullscreen?: boolean;
width?: string;
height?: string;
}
5. Style the Component
Path: src/webparts/image360Viewer/components/Image360Viewer.module.scss
.viewer {
border-radius: 8px;
overflow: hidden;
}
6. Run the Web Part
gulp clean
gulp build
gulp serve
Then open:
https://localhost:4321/temp/workbench.html
Add the Web Part, set a valid 360 image URL (like /sites/yoursite/SiteAssets/pano.jpg), and you’re done.
🎯 Final Notes
- Use the properties
defaultLong,defaultLat,fov— notdefaultYaw,defaultPitch, ordefaultFov(they belong to older versions). - If you see errors like
"Unknown option defaultYaw", you’re definitely running on PSV v5+. - The Web Part is fully functional in both local workbench and SharePoint Online.
🧭 Bonus: Common Radian Values for Orientation
| Direction | Radian Value |
|---|---|
| North | 0 |
| East | 1.57 |
| South | 3.14 |
| West | 4.71 |
| Up | 0.17 |
| Down | -0.17 |
