├── package.json
├── example
└── index.html
├── dist
├── index.html
├── index.js
├── src.7ed060e2.js
└── src.7ed060e2.js.map
├── LICENSE
├── .gitignore
├── README.md
└── src
└── index.js
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-mouse-dragndrop-component",
3 | "version": "1.1.0",
4 | "description": "Drag-n-drop entites using mouse cursor.",
5 | "keywords": [
6 | "aframe",
7 | "drag-n-drop",
8 | "aframe-vr",
9 | "webvr",
10 | "aframe-component"
11 | ],
12 | "homepage": "https://github.com/extraymond/aframe-mouse-dragndrop",
13 | "repository": "extraymond/aframe-mouse-dragndrop",
14 | "main": "src/index.js",
15 | "scripts": {
16 | "test": "parcel example/index.html",
17 | "build": "parcel build src/index.js --no-source-maps"
18 | },
19 | "author": "Raymond Yeh ",
20 | "license": "MIT",
21 | "dependencies": {},
22 | "devDependencies": {
23 | "aframe": "^0.9.2"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 extraymond
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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
63 | .cache/
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.com/package/aframe-mouse-dragndrop-component)
2 | [](https://cdn.jsdelivr.net/npm/aframe-mouse-dragndrop-component@1.0.4/dist/index.js)
3 |
4 | # aframe-mouse-dragndrop
5 |
6 | Drag-n-drop entites using mouse cursor.
7 |
8 | ## implementation
9 |
10 | There's a new parameter in cursor component that we can use to monitor mouse interaction.
11 |
12 | ```html
13 |
14 | ```
15 |
16 | Based on this feature, we can intercept the event data emitting by the cursor component. [read more about cursor component](https://aframe.io/docs/0.9.0/components/cursor.html#intersection-data)
17 |
18 | I've sperated this module into two sepearte component, **track-cursor** and **dragndrop**. And use dependencies to chain component startup. [read more about component dependencies](https://aframe.io/docs/0.9.0/core/component.html#dependencies)
19 | So you can add features like animation or hovering effects before draggin it.
20 |
21 | When a draggable component is being hovered by the cursor, it will make the entity into tracking state. You can check it with
22 |
23 | ```js
24 | if (this.el.is("tracking")) {
25 | ...
26 | }
27 | ```
28 |
29 | If a draggable component is being pressed, it will enter the dragging state. Likewise you can check it with:
30 |
31 | ```js
32 | if (this.el.is("dragging")) {
33 | ...
34 | }
35 | ```
36 |
37 | If you want to do some startup/cleanup before entering/exiting these two states, be sure to listener to "stateadded"/"stateremoved" events.
38 |
39 | ## usage
40 |
41 | ```html
42 |
43 | ```
44 |
45 | After adding the component, you can drag and drop it with mouse click.
46 |
47 | ## additional features
48 |
49 | 1. When dragging the entity, look-controls on the camera will be temporary disabled.
50 | 2. You can use mousewheel to send it further/closer when dragging.
51 |
52 | Check out the live demo: [link](https://sassy-piper.glitch.me)
53 |
54 | Appreciate any suggestions or feedback.
55 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | if (window.AFRAME == null) {
2 | console.error("aframe not found, please import it before this component.")
3 | }
4 |
5 | AFRAME.registerSystem("track-cursor", {
6 | init: function() {
7 | this.el.setAttribute("cursor", { rayOrigin: "mouse" });
8 | }
9 | });
10 |
11 | AFRAME.registerComponent("track-cursor", {
12 | init: function() {
13 | this.el.addEventListener("mousedown", e => {
14 | if (this.el.is("cursor-hovered")) {
15 | this.el.sceneEl.camera.el.setAttribute("look-controls", {
16 | enabled: false
17 | });
18 | this.el.addState("dragging");
19 | }
20 | })
21 | this.el.addEventListener("click", e => {
22 | if (this.el.is("dragging")) {
23 | this.el.sceneEl.camera.el.setAttribute("look-controls", {
24 | enabled: true
25 | });
26 | this.el.removeState("dragging");
27 | }
28 | })
29 | },
30 | });
31 |
32 | AFRAME.registerComponent("dragndrop", {
33 | dependencies: ["track-cursor"],
34 | init: function() {
35 | this.range = 0;
36 | this.dist = 0;
37 |
38 | this.el.addEventListener("stateadded", e => {
39 | if (e.detail == "dragging") {
40 | this.range = 0;
41 | this.dist = this.el.object3D.position
42 | .clone()
43 | .sub(this.el.sceneEl.camera.el.object3D.position)
44 | .length();
45 | }
46 | })
47 |
48 | this.direction = new AFRAME.THREE.Vector3();
49 | this.target = new AFRAME.THREE.Vector3();
50 | document.addEventListener("wheel", e => {
51 | if (e.deltaY < 0) {
52 | this.range += 0.1;
53 | } else {
54 | this.range -= 0.1;
55 | }
56 | });
57 | },
58 | updateDirection: function() {
59 | this.direction.copy(this.el.sceneEl.getAttribute("raycaster").direction);
60 | },
61 | updateTarget: function() {
62 | let camera = this.el.sceneEl.camera.el
63 | this.target.copy(
64 | camera.object3D.position
65 | .clone()
66 | .add(this.direction.clone().multiplyScalar(this.dist + this.range))
67 | );
68 | },
69 | tick: function() {
70 | if (this.el.is("dragging")) {
71 | this.updateDirection();
72 | this.updateTarget();
73 | this.el.object3D.position.copy(this.target);
74 | }
75 | }
76 | });
77 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c numeric require
5 | //
6 | // anything defined in a previous bundle is accessed via the
7 | // orig method which is the require for previous bundles
8 | parcelRequire = (function (modules, cache, entry, globalName) {
9 | // Save the require from previous bundle to this closure if any
10 | var previousRequire = typeof parcelRequire === 'function' && parcelRequire;
11 | var nodeRequire = typeof require === 'function' && require;
12 |
13 | function newRequire(name, jumped) {
14 | if (!cache[name]) {
15 | if (!modules[name]) {
16 | // if we cannot find the module within our internal map or
17 | // cache jump to the current global require ie. the last bundle
18 | // that was added to the page.
19 | var currentRequire = typeof parcelRequire === 'function' && parcelRequire;
20 | if (!jumped && currentRequire) {
21 | return currentRequire(name, true);
22 | }
23 |
24 | // If there are other bundles on this page the require from the
25 | // previous one is saved to 'previousRequire'. Repeat this as
26 | // many times as there are bundles until the module is found or
27 | // we exhaust the require chain.
28 | if (previousRequire) {
29 | return previousRequire(name, true);
30 | }
31 |
32 | // Try the node require function if it exists.
33 | if (nodeRequire && typeof name === 'string') {
34 | return nodeRequire(name);
35 | }
36 |
37 | var err = new Error('Cannot find module \'' + name + '\'');
38 | err.code = 'MODULE_NOT_FOUND';
39 | throw err;
40 | }
41 |
42 | localRequire.resolve = resolve;
43 | localRequire.cache = {};
44 |
45 | var module = cache[name] = new newRequire.Module(name);
46 |
47 | modules[name][0].call(module.exports, localRequire, module, module.exports, this);
48 | }
49 |
50 | return cache[name].exports;
51 |
52 | function localRequire(x){
53 | return newRequire(localRequire.resolve(x));
54 | }
55 |
56 | function resolve(x){
57 | return modules[name][1][x] || x;
58 | }
59 | }
60 |
61 | function Module(moduleName) {
62 | this.id = moduleName;
63 | this.bundle = newRequire;
64 | this.exports = {};
65 | }
66 |
67 | newRequire.isParcelRequire = true;
68 | newRequire.Module = Module;
69 | newRequire.modules = modules;
70 | newRequire.cache = cache;
71 | newRequire.parent = previousRequire;
72 | newRequire.register = function (id, exports) {
73 | modules[id] = [function (require, module) {
74 | module.exports = exports;
75 | }, {}];
76 | };
77 |
78 | var error;
79 | for (var i = 0; i < entry.length; i++) {
80 | try {
81 | newRequire(entry[i]);
82 | } catch (e) {
83 | // Save first error but execute all entries
84 | if (!error) {
85 | error = e;
86 | }
87 | }
88 | }
89 |
90 | if (entry.length) {
91 | // Expose entry point to Node, AMD or browser globals
92 | // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
93 | var mainExports = newRequire(entry[entry.length - 1]);
94 |
95 | // CommonJS
96 | if (typeof exports === "object" && typeof module !== "undefined") {
97 | module.exports = mainExports;
98 |
99 | // RequireJS
100 | } else if (typeof define === "function" && define.amd) {
101 | define(function () {
102 | return mainExports;
103 | });
104 |
105 | //