Angular Три JS | Как правильно создать собственный холст - PullRequest
0 голосов
/ 29 января 2020

Я пытаюсь правильно настроить очень простой c пример с тремя JS и Angular 8.

Когда я пытаюсь изменить размер моего холста, чтобы удалить полосы прокрутки, я получаю ошибка "Невозможно прочитать свойство 'width' of null" .

Это из-за холста, но я не знаю почему.

Компонент. html:

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

Компонент. 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();
    })
  }
}

Я почти уверен, что что-то не понимаю, но не знаю, что.

1 Ответ

1 голос
/ 26 марта 2020

Я не думаю, что это лучший способ для реализации трех js в angular.

  • Так что по моему совету сначала вы можете использовать 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);
          });
      }
    <canvas #rendererCanvas></canvas>
...