Search code examples
javascriptaframe

How to add a close button to this JavaScript in aframe


Essentially I have a modal window in aframe that I am trying to add a close button to via javascript but I haven't been able to figure it out.

Link to the project below:

https://andrewmc1994.github.io/Image-Link-Test/

If you highlight the compass icon you will see what I mean.

This is for a university project, i've looked at various methods online but none of them seem to work so that's why I have come here.

        <a-entity ui-modal="triggerElement:#selection;" visible="false">

         <a-image src="#submenu" scale="3.5 3.5 0" position="0 -0.25 2" src-fit></a-image>

            <a-image position="-1 -0.25 2.1" class="clickable" src="#tqicon" scale="0.7 0.7 0" link="href:location1.html; on: click; visualAspectEnabled: false" src-fit></a-image>

             <a-image position="0 -0.25 2.1" class="clickable" src="#acicon" scale="0.7 0.7 0" link="href:location3.html; on: click; visualAspectEnabled: false" src-fit></a-image>

             <a-image position="1 -0.25 2.1" class="clickable" src="#bchicon" scale="0.7 0.7 0" link="href:location2.html; on: click; visualAspectEnabled: false" src-fit></a-image>

            <a-image position="1.4 0 2.1" class="clickable" src="#close" scale="0.1 0.1 0" id="close" src-fit></a-image>

        </a-entity>

/******/ (function(modules) { // webpackBootstrap
/******/    // The module cache
/******/    var installedModules = {};

/******/    // The require function
/******/    function __webpack_require__(moduleId) {

/******/        // Check if module is in cache
/******/        if(installedModules[moduleId])
/******/            return installedModules[moduleId].exports;

/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            exports: {},
/******/            id: moduleId,
/******/            loaded: false
/******/        };

/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/        // Flag the module as loaded
/******/        module.loaded = true;

/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }


/******/    // expose the modules object (__webpack_modules__)
/******/    __webpack_require__.m = modules;

/******/    // expose the module cache
/******/    __webpack_require__.c = installedModules;

/******/    // __webpack_public_path__
/******/    __webpack_require__.p = "";

/******/    // Load entry module and return exports
/******/    return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports) {

    /**
     * UI modal component for A-Frame.
     */

    if (typeof AFRAME === 'undefined') {
      throw new Error('Component attempted to register before AFRAME was available.');
    }

    AFRAME.registerComponent('ui-modal', {

        schema: {
            trigger: {
                default: 'click'
            },
            triggerElement: {
              default: '',
            },
            zpos: {
                default: -4
            }
        },

        init: function() { 

            document.querySelector(this.data.triggerElement).addEventListener(this.data.trigger, this.eventHandler.bind(this));

            this.cameraEl = document.querySelector('a-entity[camera]');

            this.yaxis = new THREE.Vector3(0, 0, 0);
            this.zaxis = new THREE.Vector3(0, 0, 0);

            this.pivot = new THREE.Object3D();
            this.el.object3D.position.set(0, this.cameraEl.object3D.getWorldPosition().y, this.data.zpos);

            this.el.sceneEl.object3D.add(this.pivot);
            this.pivot.add(this.el.object3D);

        },


        eventHandler: function(evt) {

            if (this.el.getAttribute('visible') === false) {

                var direction = this.zaxis.clone();
                direction.applyQuaternion(this.cameraEl.object3D.quaternion);
                var ycomponent = this.yaxis.clone().multiplyScalar(direction.dot(this.yaxis));
                direction.sub(ycomponent);
                direction.normalize();

                this.pivot.quaternion.setFromUnitVectors(this.zaxis, direction);
                this.pivot.position.copy(this.cameraEl.object3D.getWorldPosition());

                this.el.setAttribute('visible', true);

            } else if (this.el.getAttribute('visible') === true) {

                this.el.setAttribute('visible', false);
            }

        },

        update: function (oldData) {},

        remove: function() {}

    });




/***/ }
/******/ ]);

So the expected result is for the user to open the modal window and then have the ability to close it with a simple button.

Any help is greatly appreciated.


Solution

  • You just need to add any functionality to the existing close button. Your eventHandler already contains logic for showing / hiding the UI, so just add a listener to the close button:

    let closeBtn = document.getElementById("close") one close button
    closeBtn.addEventListener(this.data.trigger, this.eventHandler.bind(this))
    

    When clicked - it will hide the UI.

    However, there are more elements with the ui-modal component, and their eventHandler trigger the setAttribute("visible", "") part.

    The easiest way to deal with this would be

    closeBtn.addEventListener(this.data.trigger, e => {
      this.el.setAttribute("visible", "false")
    })
    

    let the close button hide the element, nothing more to be done here.


    As for Axel's concerns, you don't really have to do much comparing. You can treat them as booleans:

    This is valid:

    if (this.el.getAttribute("visible") {
      // hide
    } else {
      // show
    } 
    

    as well as this:

    // toggle visibility
    this.el.setAttribute("visible", !this.el.getAttribute("visible")
    

    You can check it out in this fiddle.