Search code examples
javascriptreactjsnext.jsphotosphereviewer

Using Markers with photo-sphere-viewer in React/Next JS


I'm struggling to find out how to use Markers in my Next JS app.

I have got a basic panorama going with this code...

import React, { useEffect } from "react";
import Head from "next/head";

import { Viewer } from "photo-sphere-viewer";

export default function Home() {
  const sphereElementRef = React.createRef();

  useEffect(() => {
    const shperePlayerInstance = new Viewer({
      container: sphereElementRef.current,
      panorama: "/images/pano2.jpg",
    });

    // unmount component instructions
    return () => {
      shperePlayerInstance.destroy();
    };
  }, []);
  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />

        <link
          rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/photo-sphere-viewer@4/dist/photo-sphere-viewer.min.css"
        />
      </Head>

      <main>
        <div ref={sphereElementRef}></div>
      </main>
    </div>
  );
}

So that's all well and good but I don't know how the Markers come into it. I've tried exactly like in the markers docs with

plugins: [
[PhotoSphereViewer.MarkersPlugin, {
  markers: [ 
    {
      id: 'new-marker',
      longitude: '45deg',
      latitude: '0deg',
      image: 'assets/pin-red.png',
    },
  ],
}], 

],

But get PSVError: Un undefined value was given for plugins.

and also just using

markers: [
{
  id: 'image',
  longitude: 0.2,
  latitude: -0.13770,
  ....
},

But I just get PSVError: Unknown option markers

Any ideas would be a great help


Solution

  • Here's my full viewer after working out how to do everything

    import { Viewer } from "photo-sphere-viewer";
    import { MarkersPlugin } from "photo-sphere-viewer/dist/plugins/markers";
    import "photo-sphere-viewer/dist/plugins/markers.css";
    
    import { GyroscopePlugin } from "photo-sphere-viewer/dist/plugins/gyroscope";
    
    import { VisibleRangePlugin } from "photo-sphere-viewer/dist/plugins/visible-range";
    import StereoPlugin from "photo-sphere-viewer/dist/plugins/stereo";
    
    export default function Home() {
      const sphereElementRef = React.createRef();
    
      useEffect(() => {
        const shperePlayerInstance = new Viewer({
          container: sphereElementRef.current,
          panorama: "/images/pano2.jpg",
          plugins: [
            [
              VisibleRangePlugin,
              {
                longitudeRange: [null],
                latitudeRange: [-Math.PI / 2, Math.PI / 4], //Restrict range so you can't see the top of the pano
              },
            ],
            [GyroscopePlugin, StereoPlugin],
            [
              MarkersPlugin,
              {
                markers: [
                  {
                    id: "image",
                    longitude: 0.32,
                    latitude: 0.11,
                    image: "/images/pin-red.png",
                    width: 50,
                    height: 50,
                    anchor: "bottom center",
                    tooltip: "A image marker.",
                  },
                ],
              },
            ],
          ],
        });
    
        const gyroPlugin = shperePlayerInstance.getPlugin(GyroscopePlugin);
        const markersPlugin = shperePlayerInstance.getPlugin(MarkersPlugin);
    
        markersPlugin.on("select-marker", (e, marker) => {
          markersPlugin.updateMarker({
            id: marker.id,
          });
        });
    
        if (gyroPlugin && typeof gyroPlugin.isEnabled !== "function") {
          console.log("plugin issue");
        }
    
        if (gyroPlugin.isEnabled()) {
          gyroPlugin.stop();
        } else {
          gyroPlugin
            .start()
            .then(() => {
              const { latitude } = shperePlayerInstance.getPosition();
              const { heading } = getCompassHeadingExtra();
    
              shperePlayerInstance.rotate({
                longitude: heading * (Math.PI / 180),
                latitude,
              });
            })
            .catch(handleGyroEnableError);
        }
    
        // unmount component instructions
        return () => {
          shperePlayerInstance.destroy();
        };
      }, []); // will only be called when the src prop gets updated