Angular ThreeJS |如何正确创建自定义画布

Posted

技术标签:

【中文标题】Angular ThreeJS |如何正确创建自定义画布【英文标题】:Angular ThreeJS | How do I correctly create a custom canvas 【发布时间】:2020-05-14 19:02:35 【问题描述】:

我正在尝试使用 ThreeJS 和 Angular 8 正确设置一个非常基本的示例。

当我尝试修改画布的大小以移除滚动条时,我收到错误“无法读取 null 的属性 'width'”

这是因为画布,但我不知道为什么。

Component.html:

<canvas id="myCanvas"></canvas>

Component.css:

body  
    margin: 0; 


canvas  
    width: 100vw; 
    height: 100vh; 
    display: block; 

Component.ts:

export class Scene3dComponent implements OnInit 

  scene = new THREE.Scene()

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

  canvas = document.querySelector("canvas")
  renderer = new THREE.WebGLRenderer(antialias: true, canvas: this.canvas)

  constructor()  

  ngOnInit() 
    this.startScene();
  

  startScene() 
    this.renderer.setClearColor('#E5E5E5')
    this.renderer.setSize(window.innerWidth, window.innerHeight)
    this.renderer.render(this.scene, this.camera)

    document.body.appendChild(this.renderer.domElement)

    window.addEventListener('resize', () => 
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      this.camera.aspect = window.innerWidth / innerHeight
      this.camera.updateProjectionMatrix();
    )
  

我很确定我没有理解某些东西,但我不知道是什么。

【问题讨论】:

我在您发布的代码中看不到任何会产生错误“无法读取 null 的属性'width'”的地方......但我确实看到this.camera.aspect = window.innerWidth / innerHeight 可能应该是@987654325 @ 【参考方案1】:

我认为这不是在 angular 中实现threejs 的最佳方式。

所以在我的建议中,您首先可以使用 ElementRef 和 @ViewChild 来获取画布

创建包含您的功能的服务(创建场景、动画...)

import Component, ElementRef, OnInit, ViewChild from '@angular/core';

/**
 * Engine 3D
 */
@Component(
  selector: 'app-engine-frame',
  templateUrl: './engine-frame.component.html',
  styleUrls: ['./engine-frame.component.css'],
)
export class EngineFrameComponent implements OnInit 
  @ViewChild('rendererCanvas', static: true)
  public rendererCanvas: ElementRef<HTMLCanvasElement>;
  /**
   * Contructor
   * @param engService
   */
  constructor(private engService: EngineFrameService) 
  

  ngOnInit(): void 
    this.engService.createScene(this.rendererCanvas);
    this.engService.animate();
  


/**
* Engine service
*/
import * as THREE from 'three';
import ElementRef, Inject, Injectable, NgZone, OnDestroy from '@angular/core';
@Injectable(
  providedIn: 'root'
)
export class EngineFrameService implements OnDestroy 
  canvas: HTMLCanvasElement;
  renderer: THREE.WebGLRenderer;
  scene: THREE.Scene;
  frameId: number = null;
  constructor(private ngZone: NgZone, private rendererService: RendererService ) 
  

  public ngOnDestroy(): void 
  
  createScene(canvas: ElementRef<HTMLCanvasElement>): void 
    this.scene = new THREE.Scene(); 
    this.canvas = canvas.nativeElement;
    this.renderer = this.rendererService.create(this.canvas); // Create service for renderer
    // create your camera
  
public animate(): void 
    this.ngZone.runOutsideAngular(() => 
      window.addEventListener('resize', () => 
        this.resize();
      );
  
  public render(): void 
    this.frameId = requestAnimationFrame(() => 
      this.render();
    );
    this.renderer.render(this.scene, this.camera);
  

  public resize(): void 
      this.ngZone.runOutsideAngular(() => 
        const width = this.canvas.offsetWidth;
        const height = this.canvas.offsetHeight;
        this.renderer.setSize(width, height);
      );
  
&lt;canvas #rendererCanvas&gt;&lt;/canvas&gt;

【讨论】:

以上是关于Angular ThreeJS |如何正确创建自定义画布的主要内容,如果未能解决你的问题,请参考以下文章

使用 Angular 和 Express 登录用户的正确方法是啥?

Leanback 创建不同的自定义行视图

Threejs 创建一个虚拟城市三维场景

百度地图threejs相关

Angle Threejs Collada

使用JSONLoader在threejs上导入3d对象