Threejs for Ionic4 possible?

Hi there,

Is using ThreeJS in Ionic4 possible?
I see that Ionic4 now only supports TypeScript and ThreeJS is javascript based library.

Do you think I can import ThreeJS and use it in a .js file to implement a ThreeJS scene and render within Ionic4??

Does anybody has tried it before?

Hello,
I never used threejs, but any common js library should work with typescript too ( in the end all is transpiled into js). What sometime is difficult, is how to install and import the library. But luckily https://threejs.org/docs/index.html#manual/en/introduction/Import-via-modules shows how to do it with npm and use it as es 6 module.

Best regards, anna-liebt

2 Likes

I have tried it but it only renders for a split second and then just returns a white blank screen… Any help on this will be much appreciated?


home.page.ts:

import { Component } from '@angular/core';
import * as THREE from 'three';


@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  constructor() {
    var camera, scene, renderer;
var geometry, material, mesh;
 
init();
animate();
 
function init() {
 
    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
    camera.position.z = 1;
 
    scene = new THREE.Scene();
 
    geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
    material = new THREE.MeshNormalMaterial();
 
    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );
 
    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
 
}
 
function animate() {
 
    requestAnimationFrame( animate );
 
    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.02;
 
    renderer.render( scene, camera );
 
}
  }

  }


index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>Ionic App</title>

  <base href="/" />

  <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <meta name="format-detection" content="telephone=no" />
  <meta name="msapplication-tap-highlight" content="no" />

  <link rel="icon" type="image/png" href="assets/icon/favicon.png" />


  <!-- add to homescreen for ios -->
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black" />

  <script src="cordova.js"></script>
  <script src="three.min.js"></script>
</head>

<body>
  <app-root>
  </app-root>
</body>

</html>


app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}


home.page.html

<ion-header>
  <ion-toolbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
<script>
var camera, scene, renderer;
var geometry, material, mesh;
 
init();
animate();
 
function init() {
 
    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
    camera.position.z = 1;
 
    scene = new THREE.Scene();
 
    geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
    material = new THREE.MeshNormalMaterial();
 
    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );
 
    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
 
}
 
function animate() {
 
    requestAnimationFrame( animate );
 
    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.02;
 
    renderer.render( scene, camera );
 
}
  </script>
</ion-content>

i have the same problem.pls help me

I see at least two generic issues:

Using function keyword and trying to do ui in the constructor.

Ditch the function declaration (not needed anyway and not to be used in any way in angular context- unless u know why you can) and put all other code in ngOnInit

Minor issue: using var instead of let or const

Regards

Tom

Will try and get back to you ASAP. Thanks for the help Tom.

Ok so I tried it and I still got the same error (which is where the object is being rendered for a split second and then disappears). I tried making everything original apart from home.page.ts, which is where the issue arises. I checked the console and the only popups that comes up “[WDS] Disconnected” , Angluar is running in developer mode, Native: tried calling Statusbar.styledefault & SplashScreen.hide, and finally “THREE.WebGLRenderer 106”

No idea what to do next… Please help me.

Hi! Hope it is not too late!

Yes it is possible. What you are seeing is that the canvas of the 3D is appended to the body instead of showing inside your ion-content.

To change that, just change this line:

    document.body.appendChild( renderer.domElement );

for:

    this.container.appendChild( this.renderer.domElement );

and in your constructor or in the ngOnInit function add:

    this.container = document.getElementById( 'canvas' );

finally your html template content should look something like this:

<ion-content>
  <div id="canvas"></div>
</ion-content>

Hope this helps!

2 Likes