frame academy

Learn how to create immersive, cross-platform webxr sites.

project 4: creating a webxr photosphere gallery with javascript

part 4: modifying your scene with javascript

I hope you took a crack at the challenge for Part 3! The skills you practice in the challenges are the same ones you will use to build your own VR gallery.

Remember that if you have questions or anything you want to share, please post on our online community or on Twitter with the hashtag #frameacademy

our first function

In the last part of this project, we saw how to register our disappear component, how to make the component log some variables to the console, and how to attach the component to an entity. Then, we could load our page and saw that it worked by checking the console to see our logs. These logs happened as soon as the site loaded - no clicks needed.

Now, let's actually make it so that our component has the effect I want: when I click on something in my scene with the disappear component on it, I want it to disappear. We know from Part 2 of this project that we can "click" on things either with the mouse, a tap on mobile, or VR controllers.

To make this disappearing happen, we have to write a JavaScript function. Whereas a JavaScript variable is a way to store information, a JavaScript function usually performs some action - it does something. Hence it's name: function. There are plenty of ways to write functions in JavaScript, and I'm going to teach you one of them here.  We're going to break down this code piece by piece, so don't worry if it looks really strange. I put this function inside the init section of my disappear.js component, in the same place where I defined my variables before:

let disappearfunc = () => {
this.el.setAttribute("visible", false);
};

With let disappearfunc = , we're giving the function the name disappearfunc. This will look familiar from before when we used let mynumber to name a variable mynumber. The () after the first = sign is where you put things called function parameters. As you can see because these parentheses are blank, our function doesn't have any of these, so we don't have to worry about parameters right now. Then, we've got => followed by curly braces. In between these curly braces is where you put the code that the function will run, or execute. Inside our curly braces, we've got:

this.el.setAttribute("visible", false);

Let's break it down.

This

this is a special word in JavaScript, and it's very powerful. In this context, this lets you reference whatever HTML entity the component is attached to! Let's say we had a box in our code with our disappear component:

<a-box position="0 0 -3" disappear></a-box>

Here, the this in our disappear component would reference the box!

Let's say you had two shapes in your scene that each had the disappear component, like here:

<a-box position="0 0 -3" disappear></a-box>
<a-sphere position="2 0 -3" disappear></a-sphere>


On the box, the this in your disappear code will reference the box, and on the sphere, the this will reference the sphere. Because of this, you can put the disappear component on any entity you want, and it will still work! Your components can use this to reference whatever entity the component happens to be attached to in your HTML.

So, that covers this. The .el after this lets us directly access this's HTML element so that we can modify its attributes with a very common function that we're going to see a lot of in future projects: .setAttribute

.setAttribute

.setAttribute is a bit of JavaScript that lets you modify or add attributes to your HTML elements dynamically. You can use it to configure or add A-Frame components to your entities, because as you might remember, A-Frame components are attached to HTML entities with HTML attributes. Inside the parentheses after .setAttribute, you put the name of the component in quotes, a comma, and then the value you want to set for the component. Remember that I want the function to make whatever entity is clicked disappear. One way I can do this is by using .setAttribute to set the visible component to false. Visible is a component that comes with A-Frame, and it can only be one of two things: true or false.

Here's the code for the disappearfunc function again. Hopefully it's starting to make just a little more sense to you. We'll go through plenty more examples.

let disappearfunc = () => {
this.el.setAttribute("visible", false);
};

All of the code in my public/js/disappear.js component now looks like this:

AFRAME.registerComponent('disappear', {    
  init: function () {  
       
      let disappearfunc = () => {      
      this.el.setAttribute("visible", false);    

      };        
    });

listen for clicks

Our disappearfunc is defined nicely, but just because a function is defined doesn't mean that it will run. When we define a variable or a function, that's all we're doing - defining it. In order to actually run the function so that its code runs, we have to call the function. In our case, we want to call the function whenever an entity in our scene is clicked on.

JavaScript gives us a handy way to call a function whenever something is clicked. You can "listen" for a click event on something and then run any function you want.

Take a look at how we can use .addEventListener to call our disappearfunc function whenever the click event happens on this:

this.el.addEventListener('click', disappearfunc);

this.el
again? Yep, because we want to add the listener to whatever element our disappear component is attached to. For that, this is perfect (review the this section above if you'd like).

.addEventListener is a ready-made JavaScript function, and you'll see it all over the place. In the parentheses after it, it takes two things. First is the name of the event you're listening for, in this case: "click". Then, after a comma, you can put the name of the function that you want to call as soon as the click happens

Now, the code in my public/js/disappear.js file looks like this:

AFRAME.registerComponent('disappear', {    

   init: function () {        

      let disappearfunc = () => {      
      this.el.setAttribute("visible", false);    
      };        

      this.el.addEventListener('click', disappearfunc);      
      }  
});

To recap what this code is doing. When the disappear component loads, we make a function called disappearfunc that uses .setAttribute to set the visible component to false on this - and this refers to whatever entity has our disappear component on it in your HTML.

Then, we add an EventListener to this with .addEventListener that listens for a click and, once detected, will call, or run, our disappearfunc function.

Let's test it out. Before, when we were testing out logging our variables to the console, we attached the disappear component to the scene element. That's not what we want anymore. In this project, I've removed the disappear component from the scene HTML element and instead added it to the elements for the floor and walls. Click on the floor and walls to try it out!

challenge #4: bring it together

Sometimes you'll find with coding that there are tons of ways to achieve the same thing. You've seen how to define number and string variables, you've seen how to do console.log() to log values to the console, and you've seen how to define and then call a function based on a click event in our disappear.js component. Either in that same component or a separate one, make it so that when you click on the floor, the console log will show "I did challenge #4!"

Do feel free to copy and paste and edit from one component to another if that's helpful. It can be hard to remember things like .addEventListener (it's case sensitive), so I generally just copy and paste it around in my code. Please give a shout in the online community if you need any help with this - I know we are venturing into some more advanced territory!

< go back to part #3
Diving into javascript
move on to part #5 >
create a photosphere gallery