bottletechltd / react-marzipano

React component for Marzipano (https://www.marzipano.net/)
16 stars 4 forks source link

Associate hotspots with different scenes #9

Open brudolph opened 3 years ago

brudolph commented 3 years ago

I can't seem to figure out how one would associate different hotspots with different scenes. Is this possible? The docs say "An array of hotspot elements for the hotspots to instantiate within the current scene." But if you have multiple scenes how do you associate certain hotspots with multiple scenes? Thanks!

louisbottle commented 3 years ago

Hi there! It's been many months so I'm not sure whether I thought about this case or not.

Does simply including multiple scenes as well as the hotspots specification not work?

So anything like the below: (I just frankensteined the multiple scenes example with the hotspots example, haven't the time to test this properly yet)

const loadPrague = (tile) => {
  const prefix = 'https://www.marzipano.net/media/prague'
  if (tile.z === 0) {
    const mapY = 'lfrbud'.indexOf(tile.face) / 6
    return { url: `${prefix}/preview.jpg`, rect: { x: 0, y: mapY, width: 1, height: 1 / 6 } }
  }
  return {
    url: `${prefix}/l${tile.z}/${tile.face}/${tile.y + 1}/${tile.x + 1}.jpg`
  }
}

const defaultCoords = { yaw: 0, pitch: 0, radius: 1000 }
const defaultRotation = { x: 0, y: 0, z: 0 }
const defaultTransform = { coords: defaultCoords, rotation: defaultRotation }

const defaultStyle = { background: 'red', width: 40, height: 40 }

const clickable = (onClick, text, style, transform) => <div onClick={onClick} style={style} transform={transform}>{text}</div>

export const MultipleSceneProps = () => {
  const [currentId, setId] = useState(0)

  const scenes = [
    {
      current: currentId === 0,
      imageUrl: 'https://www.marzipano.net/media/equirect/angra.jpg',
      type: 'equirect'
    },
    {
      current: currentId === 1,
      imageUrl: 'https://www.marzipano.net/media/cubemap/{f}.jpg',
      type: 'cubemap',
      levels: [{ tileSize: 1024, size: 1024 }]
    },
    {
      current: currentId === 2,
      imageUrl: loadPrague,
      type: 'cubemap',
      levels: [
        { tileSize: 256, size: 256, fallbackOnly: true },
        { tileSize: 512, size: 512 },
        { tileSize: 512, size: 1024 },
        { tileSize: 512, size: 2048 },
        { tileSize: 512, size: 4096 },
        { tileSize: 512, size: 8192 },
        { tileSize: 512, size: 16384 },
        { tileSize: 512, size: 32768 },
        { tileSize: 512, size: 65536 }
      ]
    }
  ]

  const [active, setActive] = useState(0)
  const activeStyle = { background: 'blue' }
  const getStyle = index => index === active ? { ...defaultStyle, ...activeStyle } : defaultStyle

  return (
    <div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column' }}>
      <SceneSwitcher sceneIds={[0, 1, 2]} onSwitchId={id => setId(id)} />
      <Marzipano scenes={scenes} hotspots={[
      clickable(() => setActive(0), 'Nothing', getStyle(0), defaultTransform),
      clickable(() => setActive(1), 'Two', getStyle(1), { rotation: defaultRotation, coords: { yaw: -0.1, pitch: 0, radius: 1000 } }),
      clickable(() => setActive(2), 'Three', getStyle(2), { rotation: defaultRotation, coords: { yaw: 0, pitch: 0.1, radius: 1000 } })
    ]} />
    </div>
  )
}
brudolph commented 3 years ago

Thanks for replying @louisbottle. I tried the example you put together above (before seeing your example) and when switching scenes receive the following error.

image

Sorry for the lack of an example. I am putting one together now from the Marzipano Tool.

brudolph commented 3 years ago

Okay, have a working example for you. https://codesandbox.io/s/github/brudolph/marzipano-multiple-hotspots

The idea is to use the hotspot as if you are traveling down the highway in the first scene/pano. Then in the second scene/pano you can use the hotspot there to go back to the first scene.

I was thinking maybe it could be possible to pass props for each scene hotspot like so:

const scenes = [
{
  current: currentId === 0,
  imageUrl: `./tiles/0/{z}/{f}/{y}/{x}.jpg`,
  type: 'cubemap',
  levels: [
    { tileSize: 256, size: 256, fallbackOnly: true },
    { tileSize: 512, size: 512 },
    { tileSize: 512, size: 1024 },
    { tileSize: 512, size: 2048 }
  ],
  hotspots: [
    { coords: { yaw: Math.PI / 4, pitch: 0, radius: 800 }, rotation: { x: Math.PI / 4, y: 0, z: 0 } },
    { coords: { yaw: Math.PI / 8, pitch: Math.PI / 8, radius: 500 }, rotation: { x: 0, y: 0, y: 0 } },
  ]
},
{
  current: currentId === 1,
  imageUrl: `./tiles/1/{z}/{f}/{y}/{x}.jpg`,
  type: 'cubemap',
  levels: [
    { tileSize: 256, size: 256, fallbackOnly: true },
    { tileSize: 512, size: 512 },
    { tileSize: 512, size: 1024 },
    { tileSize: 512, size: 2048 }
  ],
 hotspots: [
    { coords: { yaw: Math.PI / 4, pitch: 0, radius: 800 }, rotation: { x: Math.PI / 4, y: 0, z: 0 } },
    { coords: { yaw: Math.PI / 8, pitch: Math.PI / 8, radius: 500 }, rotation: { x: 0, y: 0, y: 0 } },
  ]
}
];
louisbottle commented 3 years ago

I see, the idea is to have hotspots be children of scenes, rather there be no real relationship between them?

brudolph commented 3 years ago

Yes, exactly.

louisbottle commented 3 years ago

It does sound like a good idea so I'll try implementing it.