How to include THREE.JS with OrbitControls.js and OBJLoader.js into elgg ?

Hello,

I have general issue with my lack of understanding of including multiple, mutually dependent javascripts into a plugin. So some help, examples or tutorial about that would be great to have and learn. 

As I am not sure whom to address this question I also announced it in Beginning development group.

At the moment I try to include three.js into my plugin and I succeeded.

But when I try to include another javascript from the same bundle which are related through GLOBAL object "THREE" I receive error message in the web browser (undefined object "THREE").

Here is my code in short:

start.php

...

init(){

...

elgg_define_js('three', [

'src' => elgg_get_simplecache_url('three.js'),

'exports' => 'THREE',

]); 
elgg_define_js('OrbitControls', [

'src' => elgg_get_simplecache_url('OrbitControls.js'),

// 'deps' => ['THREE'],

// 'exports' => 'THREE.OrbitControls',

]); 


elgg_define_js('OBJLoader', [

'src' => elgg_get_simplecache_url('OBJLoader.js'),

// 'deps' => ['THREE'],

]); 

...

}

...

my_plugin/view.php

...

elgg_require_js("my_plugin/three_my_app");

...

my_plugin/views/default/js/my_plugin/three_my_app.js

define(function(require) {

    var elgg = require("elgg");

    var $ = require("jquery");

    var THREE = require("three");

window.THREE = THREE; 

require('OBJLoader');

require('OrbitControls'); 



// these need to be accessed inside more than one function so we'll declare them first

let container;

let camera;

let controls;

let renderer;

let scene;



const mixers = [];

const clock = new THREE.Clock();



function init() {



  container = document.querySelector( '#container' );



  scene = new THREE.Scene();

  scene.background = new THREE.Color( 0x8FBCD4 );



  initCamera();

  initControls();

  initLights();

  loadModels();

  initRenderer();



  renderer.setAnimationLoop( () => {



    update();

    render();



  } );



}



function initCamera() {

  camera = new THREE.PerspectiveCamera( 35, container.clientWidth / container.clientHeight, 1, 1000 );

  camera.position.set( -50, 50, 150 );

}



function initControls() {

  controls = new THREE.OrbitControls( camera, container );



}

....

....

});
I copied three javascript files I need into my plugin vendors folder and gave them reference through views.php :
 
<?php


return [

    'default' => [

'/' => [

__DIR__ . '/vendors/three-js/build/',

__DIR__ . '/vendors/three-js/loaders/',

__DIR__ . '/vendors/three-js/libs/',

__DIR__ . '/vendors/three-js/controls/',

],

    ],

];
 
The Three files I use are on following links:
 
 
 
The issue is that in any of dependent js files there is definition of object based on global THREE object (for example line 27 in OrbitControls.js : THREE.OrbitControls = function ( object, domElement, localElement ) {
) which is not visible in dependent javascript file and the web browser raise error message THREE in not defined . 
 
I have two questions.
 
1. Can someone explain how to include multiply dependent javascript files in own plugin based on this case ?
 

I found on the internet the solution for regular web developers but I don't know how to include that into elgg.

2. And Maybe someone can explain where and how to properly include the following code: 

define('three', ['three.js'], function ( THREE ) {

window.THREE = THREE;

return THREE;

});
Thanks,
Vlad
 

 

  • 1. You don't need to define OrbitControls.js and OBJLoader.js but three.js only because these scripts calls with main build.

    2. elgg_get_simplecache_url('three.js') assume that your JS is located at root path.

    So recommend to register a view name in views.php of your plugin, or use the full view name.

    For example, make

    /mod/your_awesome_plugin/vendor/

    Download the latest release and unzip it in

    /mod/your_awesome_plugin/vendor/three

    Now define your JS as:

    elgg_define_js('three', [
        'src' => '/mod/your_awesome_plugin/vendor/three/three.js',
        'exports' => 'THREE',
    ]);

    If you want to use the simple cache then add this view name in views.php of your plugin:

    return [
        'default' => [
            'js/' => __DIR__ . '/vendor',
        ],
    ];

    With it you can use this:

    elgg_define_js('three', [
        'src' => elgg_get_simplecache_url('three/three.js'),
        'exports' => 'THREE',
    ]);

    3. We've fixed the same issues with global/document and global/window functions in another plugins.

    Create in /mod/your_awesome_plugin/vendor/ new folder global with 2 files:

    //document.js
    define(['global/window'], function (window) {
        return window.document;
    });
    
    //window.js
    define([], function () {
        return window;
    });

    Define these scripts in start.php:

    elgg_define_js('global/window', [
        'src' => elgg_get_simplecache_url('js/global/window.js'),
    ]);
       
    elgg_define_js('global/document', [
        'src' => elgg_get_simplecache_url('js/global/document.js'),
    ]);

    In your three_my_app.js use:

    define(['jquery', 'elgg', 'global/window', 'three'], function ($, elgg, window, THREE) {
    
    ....

    4. You don't need to duplicate the same pages/discussion on community.

  • Thank you RvR for your help.

     

    I would like to get working the same code as written in this tutorial:

    https://codesandbox.io/s/github/looeee/discoverthree.com-examples/tree/master/1-first-steps/5-camera-controls?from-embed

    It uses Three.js & OrbitControls.js only and with it I would be happy to understand how to setup it in elgg.

     

    Regarding your advices... when I do everything you wrote I receive error message:

    "Uncaught TypeError: THREE.OrbitControls is not a constructor"

    in file: "my_plugin/views/default/js/my_plugin/three_my_app.js" 

    - at the line:

      controls = new THREE.OrbitControls( camera, container );

    ..............................................................................................................

    Alternatively if I try to include javascript file OrbitControls.js from "..\vendors\three\examples\js\controls\" - path with: require('OrbitControls'); - in three_my_app.js I receive another error message:

    Uncaught Error: Module name "OrbitControls" has not been loaded yet for context: _. Use require([])
    https://requirejs.org/docs/errors.html#notloaded
        at makeError (require.js:168)
        at Object.localRequire [as require] (require.js:1436)
        at requirejs (require.js:1797)

    In this scenario I defined OrbitControls in start.php init() with : elgg_define_js(...);.

     

    Please look at three.js bundle.

    Three.js is located in three\build\ folder , not in root.

    Then OrbitControls.js is in three\examples\js\controls\ folder.

    Many guys even out of elgg community has issues to put OrbitControls.js to work.

    Thus the Three developers started to develop another OrbitControls.js in "three\examples\jsm" folder.

    The isuue with this javascript file is "import" key word in OrbitControls.js.

    Do you have idea what to do?

    BR,

    V

     

     

  • As a reminder, I just showed a way and methods but not the solution.

    However, I spent the time to answer your question.

Navigation