10

I am using an Angular 7 and I want to add Three JS Thee JS with my project, but It's turned out not quite really works. I am not sure that I did it correctly. Please guy me the way

This is my code

    ngAfterViewInit(): void {
    let script = this._renderer2.createElement('script');
    script.type = `text/javascript`;
    script.text = `
    {

        $(document).ready(function () {
          var SEPARATION = 100, AMOUNTX = 50, AMOUNTY = 50;


    var container, stats;
    var camera, scene, renderer;

    var particles, count = 0;

    var mouseX = 0, mouseY = 0;

    var windowHalfX = window.innerWidth / 2;
    var windowHalfY = window.innerHeight / 2;
    mouseX = 635 - windowHalfX;
    mouseY = 27 - windowHalfY;

    init();
    animate();

    function init() {

        container = document.createElement('div');
        document.body.appendChild(container);

        camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
        camera.position.z = 1000;

        scene = new THREE.Scene();

        //

        var numParticles = AMOUNTX * AMOUNTY;

        var positions = new Float32Array(numParticles * 3);
        var scales = new Float32Array(numParticles);

        var i = 0, j = 0;

        for (var ix = 0; ix < AMOUNTX; ix++) {

            for (var iy = 0; iy < AMOUNTY; iy++) {

                positions[i] = ix * SEPARATION - ((AMOUNTX * SEPARATION) / 2); // x
                positions[i + 1] = 0; // y
                positions[i + 2] = iy * SEPARATION - ((AMOUNTY * SEPARATION) / 2); // z

                scales[j] = 1;

                i += 3;
                j++;

            }

        }

        var geometry = new THREE.BufferGeometry();
        geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        geometry.setAttribute('scale', new THREE.BufferAttribute(scales, 1));

        var material = new THREE.ShaderMaterial({

            uniforms: {
                color: { value: new THREE.Color(0xffffff) },
            },
            vertexShader: document.getElementById('vertexshader').textContent,
            fragmentShader: document.getElementById('fragmentshader').textContent

        });

        //

        particles = new THREE.Points(geometry, material);
        scene.add(particles);

        //

        renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        //renderer = new THREE.CanvasRenderer({alpha: true});
        renderer.setClearColor(0x83d3ec, 0);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild(renderer.domElement);

        stats = new Stats();
        container.appendChild(stats.dom);

        document.addEventListener('mousemove', onDocumentMouseMove, false);
        document.addEventListener('touchstart', onDocumentTouchStart, false);
        document.addEventListener('touchmove', onDocumentTouchMove, false);

        //

        window.addEventListener('resize', onWindowResize, false);

    }

    function onWindowResize() {

        windowHalfX = window.innerWidth / 2;
        //windowHalfY = window.innerHeight / 2;

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    //

    function onDocumentMouseMove(event) {

        mouseX = event.clientX - windowHalfX;
        // mouseY = event.clientY - windowHalfY;

    }

    function onDocumentTouchStart(event) {

        if (event.touches.length === 1) {

            event.preventDefault();

            mouseX = event.touches[0].pageX - windowHalfX;
            //mouseY = event.touches[0].pageY - windowHalfY;

        }

    }

    function onDocumentTouchMove(event) {

        if (event.touches.length === 1) {

            event.preventDefault();

            mouseX = event.touches[0].pageX - windowHalfX;
            //mouseY = event.touches[0].pageY - windowHalfY;

        }

    }

    //

    function animate() {

        requestAnimationFrame(animate);

        render();
        stats.update();

    }

    function render() {

        camera.position.x += (mouseX - camera.position.x) * .05;
        camera.position.y += (- mouseY - camera.position.y) * .05;
        camera.lookAt(scene.position);

        var positions = particles.geometry.attributes.position.array;
        var scales = particles.geometry.attributes.scale.array;

        var i = 0, j = 0;

        for (var ix = 0; ix < AMOUNTX; ix++) {

            for (var iy = 0; iy < AMOUNTY; iy++) {

                positions[i + 1] = (Math.sin((ix + count) * 0.3) * 50) +
                    (Math.sin((iy + count) * 0.5) * 50);

                scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 8 +
                    (Math.sin((iy + count) * 0.5) + 1) * 8;

                i += 3;
                j++;

            }

        }

        particles.geometry.attributes.position.needsUpdate = true;
        particles.geometry.attributes.scale.needsUpdate = true;

        renderer.render(scene, camera);

        count += 0.1;

       }

        });
       }
     `;
     this._renderer2.appendChild(this._document.body, script);
    }

I have imported the needed modules but still doesn't work and It's show an error like "THREE is not a function" or somthing else.

1
  • 2
    this is a pretty broad question but the approach here is completely off. you just want to install the three lib and it's typings and import it normally and use it. use angular provided tools to do this stuff, use ViewChild to get the container, host listeners to do the events, and so on and so forth. if you ever find yourself building a script tag in an angular component, you're going wrong Commented Dec 3, 2019 at 2:09

2 Answers 2

19

First install three.js using npm

npm i three

Then in component import it like bellow

import * as THREE from 'three';

Now you could use it from your component like bellow code. Note: This is only for example

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

var animate = function () {
  requestAnimationFrame( animate );

  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  renderer.render( scene, camera );
};

animate();

in package.json file update the typescript to latest version (3.7.2)

"devDependencies": {
    ...
    "typescript": "3.7.2"
  }

Since you are using Angular 7 in tsconfig.json file disable the TypeScript version Check. If you are using the latest Angular version no need to do this one.

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "es2015",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  },
   "angularCompilerOptions": {
    "disableTypeScriptVersionCheck": true,
  }
 }

Working DEMO is here

Sign up to request clarification or add additional context in comments.

9 Comments

When I try to do like your example it's not working and show a banches on error in vs code terminal ERROR in node_modules/three/src/core/BufferAttribute.d.ts(21,6): error TS1086: An accessor cannot be declared in an ambient context. node_modules/three/src/renderers/WebGLRenderer.d.ts(35,31): error TS2304: Cannot find name 'OffscreenCanvas'. node_modules/three/src/renderers/webgl/WebGLAttributes.d.ts(6,43): error TS2304: Cannot find name 'WebGL2RenderingContext'. node_modules/three/src/renderers/webgl/WebGLUtils.d.ts(3,43): error TS2304: Cannot find name 'WebGL2RenderingContext'
your tsconfig.json file should looks like this { "compileOnSave": false, "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", "sourceMap": true, "declaration": false, "module": "es2015", "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "typeRoots": [ "node_modules/@types" ], "lib": [ "es2018", "dom" ] } } ?
Yes exactly it is
have to update the typescript to "typescript": "3.7.2" and also to tsconfig.json add this line "angularCompilerOptions": { "disableTypeScriptVersionCheck": true, }
I'm using angular 9 and is working, new project copy paste on the constructor and everything is ok. BUT I would use a more Angular way using the ngAfterViewInit hook and a component not adding directly to the body. BUT for the purpose of the question is 100% valid! Thanks!!!
|
1

If it's not necessary to include, threejs in angular component. You can include threejs script in index.html below Code Demo is here ThreeJS Angular Demo

    <body>
      <app-root></app-root>
      <script src="https://threejs.org/build/three.js"></script>
      <script>
         <!--  Your threejs script that creates and animates the scene --->
         <!--  Note: skip the import threejs module import statement --->

        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera( 75, 
        window.innerWidth/window.innerHeight, 0.1, 1000 );

        var renderer = new THREE.WebGLRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );

        var geometry = new THREE.BoxGeometry( 1, 1, 1 );
        var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
        var cube = new THREE.Mesh( geometry, material );
        scene.add( cube );

         camera.position.z = 5;

         var animate = function () {
         requestAnimationFrame( animate );

         cube.rotation.x += 0.01;
         cube.rotation.y += 0.01;

         renderer.render( scene, camera );
       };

       animate();

      </script>
    
    </body>

1 Comment

Appreciate your answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.