├── package.json ├── LICENSE ├── dist ├── aframe-ui-modal-component.min.js └── aframe-ui-modal-component.js ├── README.md └── index.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aframe-ui-modal-component", 3 | "version": "1.0.2", 4 | "description": "Create a modal dialog or floating menu in A-Frame.", 5 | "main": "index.js", 6 | "directories": { 7 | "example": "examples" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/IdeaSpaceVR/aframe-ui-modal-component.git" 15 | }, 16 | "keywords": [ 17 | "ideaspace", 18 | "ideaspacevr", 19 | "webvr", 20 | "aframe-vr", 21 | "aframe-component", 22 | "aframe", 23 | "mozvr", 24 | "vr" 25 | ], 26 | "author": "IdeaSpace (https://www.ideaspacevr.org)", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/IdeaSpaceVR/aframe-ui-modal-component/issues" 30 | }, 31 | "homepage": "https://github.com/IdeaSpaceVR/aframe-ui-modal-component#readme", 32 | "devDependencies": { 33 | "aframe": "^0.5.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 IdeaSpaceVR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /dist/aframe-ui-modal-component.min.js: -------------------------------------------------------------------------------- 1 | !function(t){function e(o){if(i[o])return i[o].exports;var s=i[o]={exports:{},id:o,loaded:!1};return t[o].call(s.exports,s,s.exports,e),s.loaded=!0,s.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e){if("undefined"==typeof AFRAME)throw new Error("Component attempted to register before AFRAME was available.");AFRAME.registerComponent("ui-modal",{schema:{trigger:{"default":"click"},triggerElement:{"default":"a-scene"},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,1,0),this.zaxis=new THREE.Vector3(0,0,1),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(t){if(this.el.getAttribute("visible")===!1){var e=this.zaxis.clone();e.applyQuaternion(this.cameraEl.object3D.quaternion);var i=this.yaxis.clone().multiplyScalar(e.dot(this.yaxis));e.sub(i),e.normalize(),this.pivot.quaternion.setFromUnitVectors(this.zaxis,e),this.pivot.position.copy(this.cameraEl.object3D.getWorldPosition()),this.el.setAttribute("visible",!0)}else this.el.getAttribute("visible")===!0&&this.el.setAttribute("visible",!1)},update:function(t){},remove:function(){}})}]); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aframe-ui-modal-component 2 | 3 | Create a modal dialog or floating menu in A-Frame. 4 | 5 | ### Properties 6 | 7 | | Property | Description | Default Value | 8 | | ---------------- | ----------- | ------------- | 9 | | trigger | Event to make dialog or menu visible. | `click` | 10 | | triggerElement | Element to which the trigger event listener will be applied. | `a-scene` | 11 | | zpos | Position the dialog or menu on the z-axis. In meters. | -4 | 12 | 13 | ### Usage 14 | 15 | #### Browser Installation 16 | 17 | Install and use by directly including the [browser files](dist): 18 | 19 | ```html 20 | 21 | My A-Frame Scene 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ``` 42 | 43 | ### Examples 44 | 45 | - http://ideaspacevr.github.io/aframe-ui-modal-component 46 | - https://www.ideaspacevr.org/themes/ideaspace-360 47 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * UI modal component for A-Frame. 3 | */ 4 | 5 | if (typeof AFRAME === 'undefined') { 6 | throw new Error('Component attempted to register before AFRAME was available.'); 7 | } 8 | 9 | AFRAME.registerComponent('ui-modal', { 10 | 11 | schema: { 12 | trigger: { 13 | default: 'click' 14 | }, 15 | triggerElement: { 16 | default: 'a-scene', 17 | }, 18 | zpos: { 19 | default: -4 20 | } 21 | }, 22 | 23 | init: function() { 24 | 25 | document.querySelector(this.data.triggerElement).addEventListener(this.data.trigger, this.eventHandler.bind(this)); 26 | 27 | this.cameraEl = document.querySelector('a-entity[camera]'); 28 | 29 | this.yaxis = new THREE.Vector3(0, 1, 0); 30 | this.zaxis = new THREE.Vector3(0, 0, 1); 31 | 32 | this.pivot = new THREE.Object3D(); 33 | this.el.object3D.position.set(0, this.cameraEl.object3D.getWorldPosition().y, this.data.zpos); 34 | 35 | this.el.sceneEl.object3D.add(this.pivot); 36 | this.pivot.add(this.el.object3D); 37 | 38 | }, 39 | 40 | eventHandler: function(evt) { 41 | 42 | if (this.el.getAttribute('visible') === false) { 43 | 44 | var direction = this.zaxis.clone(); 45 | direction.applyQuaternion(this.cameraEl.object3D.quaternion); 46 | var ycomponent = this.yaxis.clone().multiplyScalar(direction.dot(this.yaxis)); 47 | direction.sub(ycomponent); 48 | direction.normalize(); 49 | 50 | this.pivot.quaternion.setFromUnitVectors(this.zaxis, direction); 51 | this.pivot.position.copy(this.cameraEl.object3D.getWorldPosition()); 52 | 53 | this.el.setAttribute('visible', true); 54 | 55 | } else if (this.el.getAttribute('visible') === true) { 56 | 57 | this.el.setAttribute('visible', false); 58 | } 59 | 60 | }, 61 | 62 | update: function (oldData) {}, 63 | 64 | remove: function() {} 65 | 66 | }); 67 | 68 | 69 | -------------------------------------------------------------------------------- /dist/aframe-ui-modal-component.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports) { 46 | 47 | /** 48 | * UI modal component for A-Frame. 49 | */ 50 | 51 | if (typeof AFRAME === 'undefined') { 52 | throw new Error('Component attempted to register before AFRAME was available.'); 53 | } 54 | 55 | AFRAME.registerComponent('ui-modal', { 56 | 57 | schema: { 58 | trigger: { 59 | default: 'click' 60 | }, 61 | triggerElement: { 62 | default: 'a-scene', 63 | }, 64 | zpos: { 65 | default: -4 66 | } 67 | }, 68 | 69 | init: function() { 70 | 71 | document.querySelector(this.data.triggerElement).addEventListener(this.data.trigger, this.eventHandler.bind(this)); 72 | 73 | this.cameraEl = document.querySelector('a-entity[camera]'); 74 | 75 | this.yaxis = new THREE.Vector3(0, 1, 0); 76 | this.zaxis = new THREE.Vector3(0, 0, 1); 77 | 78 | this.pivot = new THREE.Object3D(); 79 | this.el.object3D.position.set(0, this.cameraEl.object3D.getWorldPosition().y, this.data.zpos); 80 | 81 | this.el.sceneEl.object3D.add(this.pivot); 82 | this.pivot.add(this.el.object3D); 83 | 84 | }, 85 | 86 | eventHandler: function(evt) { 87 | 88 | if (this.el.getAttribute('visible') === false) { 89 | 90 | var direction = this.zaxis.clone(); 91 | direction.applyQuaternion(this.cameraEl.object3D.quaternion); 92 | var ycomponent = this.yaxis.clone().multiplyScalar(direction.dot(this.yaxis)); 93 | direction.sub(ycomponent); 94 | direction.normalize(); 95 | 96 | this.pivot.quaternion.setFromUnitVectors(this.zaxis, direction); 97 | this.pivot.position.copy(this.cameraEl.object3D.getWorldPosition()); 98 | 99 | this.el.setAttribute('visible', true); 100 | 101 | } else if (this.el.getAttribute('visible') === true) { 102 | 103 | this.el.setAttribute('visible', false); 104 | } 105 | 106 | }, 107 | 108 | update: function (oldData) {}, 109 | 110 | remove: function() {} 111 | 112 | }); 113 | 114 | 115 | 116 | 117 | /***/ } 118 | /******/ ]); --------------------------------------------------------------------------------