Skip to content

270 Degrees Interactivity Tutorial

Hi again! 👋
In this tutorial we will add some basic interactivity to your viewer, using a few of the many methods available.
We will add an interface to change the background color, camera position and get a static image.

This tutorial builds off the Basic implemenation tutorial.

Let's go!


1. Add Markup

First, let's add some basic markup for an interface, and some styling to go along with it.
Let's also add a script element for later.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My First 270 Viewer</title>
  <style>
    body {
      font-family: sans-serif;
    }
    #viewer-container {
      width: 500px;
      height: 500px;
    }
    .buttons {
        display: flex;
        gap: 1rem;
    }
    label {
      display: flex;
      gap: .25em;
      align-items: center;
    }
  </style>
</head>
<body>
  <main>
    <h1>My 270 Viewer!</h1>
    <div id="viewer-container">
      <div class="js-270viewer" data-270-model="270logo" data-270-background="#eeeeee" data-270-autorotate="true"></div>
    </div>

    <!-- the buttons -->
    <div class="buttons">
      <label>Set Background
        <button id="set-bg">Click!</button>
      </label>

      <label>Set Camera
        <button id="set-camera">Click!</button>
      </label>

      <label>Get Image
        <button id="set-image">Click!</button>
      </label>
    </div>
  </main>

  <script>window.TSDAPIKEY = 'rest-of-the-owl';</script>
  <script src="https://api.270degrees.nl/api/script/latest/viewer.js"></script>

  <script>
    // We'll use this in the next step
  </script>
</body>
</html>

2. Add the listeners

Now that that is set up, let's add the listeners to the newly created buttons.
This uses basic javascript standards. Just replace the empty script element with this:

<script>
  // store the Viewer container for later
  const $viewer = document.querySelector('.js-270viewer');

  document.querySelector('#set-bg').addEventListener('click', ev => {
    // here we will change the background
  });

  document.querySelector('#set-camera').addEventListener('click', ev => {
    // here we will change the camera position
  });

  document.querySelector('#get-image').addEventListener('click', ev => {
    // this will get the image later
  })
</script>

So far so good!


3. Add the Methods

Here is where the fun begins. We will add the appropriate methods to get our desired interactivity!
The methods we will be using are setBackground, setCameraPosition and getImage.

<script>
  // store the Viewer container for later
  const $viewer = document.querySelector('.js-270viewer');

  document.querySelector('#set-bg').addEventListener('click', ev => {
    // here we will change the background
    $viewer.setBackground('#ccccff');
  });

  document.querySelector('#set-camera').addEventListener('click', ev => {
    // here we will change the camera position
    $viewer.setCameraPosition({zoom: 0.25, phi: 75, theta: 30});
  });

  document.querySelector('#get-image').addEventListener('click', ev => {
    // this will get the image and download it
    $viewer.getImage({download: true});
  })
</script>

We have working buttons! 🔥
Click them to change the Viewer's background to a soft blue, reset the camera to a fixed position, and offer the user an image of the Viewer to download!

All methods are directly accessable through the element that was used to create the viewer, ie .js-270viewer.
While flexible, each method can be used with minimal options:

  • setBackground: takes any css valid color, like red or #ff0000.
  • setCameraPosition: changes the zoom, vertical angle and horizontal angle.
  • getImage: offers the image to the user via download: true.

4. Extra: A color picker

Let's give the user control over the background color via a color picker!
Replace

<label>Set Background
  <button id="set-bg">Click!</button>
</label>

with

<label>Set Background
  <input type="color" id="set-bg" value="#eeeeee" />
</label>

And let's update the javascript to support this new element:

document.querySelector('#set-bg').addEventListener('input', ev => {
  // here we will change the background
  $viewer.setBackground(ev.target.value);
});

Now the background will update in realtime with the user's choices!


5. End result

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My First 270 Viewer</title>
  <style>
    body {
      font-family: sans-serif;
    }
    #viewer-container {
      width: 500px;
      height: 500px;
    }
    .buttons {
        display: flex;
        gap: 1rem;
    }
    label {
      display: flex;
      gap: .25em;
      align-items: center;
    }
  </style>
</head>
<body>
  <main>
    <h1>My 270 Viewer!</h1>
    <div id="viewer-container">
      <div class="js-270viewer" data-270-model="270logo" data-270-background="#eeeeee" data-270-autorotate="true"></div>
    </div>

    <!-- the buttons -->
    <div class="buttons">
      <label>Set Background
        <button id="set-bg">Click!</button>
      </label>

      <label>Set Camera
        <button id="set-camera">Click!</button>
      </label>

      <label>Get Image
        <button id="set-image">Click!</button>
      </label>
    </div>
  </main>

  <script>window.TSDAPIKEY = 'rest-of-the-owl';</script>
  <script src="https://api.270degrees.nl/api/script/latest/viewer.js"></script>

  <script>
    // store the viewer reference
    const $viewer = document.querySelector('.js-270viewer');

    // Add event listeners
    document.querySelector('#set-bg').addEventListener('input', ev => {
      // here we will change the background
      $viewer.setBackground(ev.target.value);
    });

    document.querySelector('#set-camera').addEventListener('click', ev => {
      $viewer.setCameraPosition({ zoom: 0.25, phi: 75, theta: 30 });
    })

    document.querySelector('#get-image').addEventListener('click', ev => {
      $viewer.getImage({ download: true });
    })
  </script>
</body>
</html>

What’s Next?

We've added some fun interactions to the viewer. But it doesn't end here!
Why not experiment with some of the other available methods?