Typescript无法访问对象属性,即使它们在那里

时间:2018-01-24 00:01:48

标签: javascript typescript properties

我在访问属性方面遇到了麻烦,即使它们存在于对象中,但是打字稿告诉我他们没有。我创建了一个粒子对象,它包含形状的几何形状和材质。我需要能够访问粒子的几何顶点,但是当我尝试时,typescript会抛出一个拟合。例如,this.particles.geometry.vertices.length应该返回我的顶点的长度,但是typescript表示顶点在几何体中实际存在时不存在。

我的问题发生在加载图像,创建顶点之后,然后我需要将它们移动到那里的目标索引,但是它说this.particles.geometry.vertices不存在。

这是我的粒子对象,它包含几何体,几何体内部是一个属性,它是包含我所有顶点的顶点,但我无法按照我显示的方式访问它们。 enter image description here

这是我的完整源代码。 drawImage方法将绘制所有顶点正确,并将顶点对象推入我的几何对象。然后,一旦完成,我将几何体添加到粒子,它工作正常,我将它添加到场景,并显示所有我的顶点。问题是我无法访问我的顶点来操纵它们。所以我的粒子对象,drawImage和包含my循环的render方法就是这一切发生的地方。在我的渲染方法中,它只是说(TS)属性'顶点'在类型'几何|中不存在缓冲几何'。它确实存在,我用图像表明我的粒子对象是一个点对象,它包含我的几何体,并且该几何体内部有一个属性,它的所有顶点都称为顶点。

import { Component, AfterViewInit, ElementRef, Input, ViewChild, HostListener} from '@angular/core';
import { TweenLite } from 'gsap';
import * as THREE from 'three';
declare const require: (moduleId: string) => any;
var OrbitControls = require('three-orbit-controls')(THREE);

@Component({
    selector: 'shared-background-scene',
    templateUrl: './backgroundScene.component.html',
    styleUrls: ['./backgroundScene.component.scss']
})

export class BackgroundSceneComponent {

    public scene: THREE.Scene;
    private renderer: THREE.WebGLRenderer;
    private camera: THREE.PerspectiveCamera;
    private cameraTarget: THREE.Vector3;
    public controls: THREE.OrbitControls;

    public fieldOfView: number = 60;
    public nearClippingPane: number = 1;
    public farClippingPane: number = 1100;

    @ViewChild('canvas')
    private canvasRef: ElementRef;

    public particles: THREE.Points;
    public imageData: any;
    public geometry = new THREE.Geometry();
    public material = new THREE.PointsMaterial({
                size: 3,
                color: 0x313742,
                sizeAttenuation: false
    });
    public loadImage() {
        //load texture, which is the image, and then get the imagedata, and draw image.
        var texture = new THREE.TextureLoader().load("assets/img/example-clouds.png", () => { console.log(texture); this.imageData = this.getImageData(texture.image); this.drawImage(); this.startRendering(); })
    }

    public getImageData(image: any) {
        console.log(image);
        // Create canvas for the image
        let canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.width;

        // Make sure context is 2d
        let context = canvas.getContext("2d");
        context!.drawImage(image, 0, 0);

        //return the context to be saved to the imageData.
        return context!.getImageData(0, 0, image.width, image.height);
    }

    public drawImage() {

        // Create vertices to draw the image.
        for (var y = 0, y2 = this.imageData.height; y < y2; y += 2) {
            for (var x = 0, x2 = this.imageData.width; x < x2; x += 2) {
                if (this.imageData.data[(x * 4 + y * 4 * this.imageData.width) + 3] > 128) {

                    let vertex:any = new THREE.Vector3();
                    vertex.x = Math.random() * 1000 - 500;
                    vertex.y = Math.random() * 1000 - 500;
                    vertex.z = -Math.random() * 500;

                    vertex.destination = {
                        x: x - this.imageData.width / 2,
                        y: -y + this.imageData.height / 2,
                        z: 0
                    };

                    vertex.speed = Math.random() / 200 + 0.015;

                    this.geometry.vertices.push(vertex);
                }
            }
        }

        console.log(this.geometry);
        this.particles = new THREE.Points(this.geometry, this.material);
        this.scene.add(this.particles);
        console.log(this.particles);
        requestAnimationFrame(this.render);
    }

    constructor() {
        this.render = this.render.bind(this);
    }

    private get canvas(): HTMLCanvasElement {
        return this.canvasRef.nativeElement;
    }

    private createScene() {
        this.scene = new THREE.Scene();
    }

    private createCamera() {
        let aspectRatio = this.getAspectRatio();
        this.camera = new THREE.PerspectiveCamera(
            this.fieldOfView,
            aspectRatio,
            this.nearClippingPane,
            this.farClippingPane
        );

        // Set position and look at
        this.camera.position.x = 10;
        this.camera.position.y = 10;
        this.camera.position.z = 100;
    }

    private getAspectRatio(): number {
        let height = this.canvas.clientHeight;
        if (height === 0) {
            return 0;
        }
        return this.canvas.clientWidth / this.canvas.clientHeight;
    }

    private startRendering() {
        this.renderer = new THREE.WebGLRenderer({
            canvas: this.canvas,
            antialias: true
        });
        this.renderer.setPixelRatio(devicePixelRatio);
        this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);

        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.renderer.setClearColor(0xffffff, 1);
        this.renderer.autoClear = true;

        let component: BackgroundSceneComponent = this;

        (function render() {
            requestAnimationFrame(render);
            component.render();
        }());
    }

    public render() {
        this.renderer.render(this.scene, this.camera);

        for (var i = 0, j = this.particles.geometry.vertices; i < j; i++) {
            var particle = this.particles.geometry.vertices[i];
            particle.x += (particle.destination.x - particle.x) * particle.speed;
            particle.y += (particle.destination.y - particle.y) * particle.speed;
            particle.z += (particle.destination.z - particle.z) * particle.speed;
        }
        this.particles.geometry.verticesneedupdate = true;
    }

    public addControls() {
        this.controls = new OrbitControls(this.camera);
        this.controls.rotateSpeed = 1.0;
        this.controls.zoomSpeed = 1.2;
        this.controls.addEventListener('change', this.render);

    }

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

    /* Events */
   private onResize(event: Event) {
        this.canvas.style.width = "100%";
        this.canvas.style.height = "100vh";
        //console.log("onResize: " + this.canvas.clientWidth + ", " + this.canvas.clientHeight);

        this.camera.aspect = this.getAspectRatio();
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
        this.render();
    }

    /* LIFECYCLE */
   ngAfterViewInit() {
        this.createScene();
        this.createCamera();
        this.loadImage(); // rendering starts here
        this.loadCubeModel();
        this.addControls();
    }
}

使用console.log的快速示例(this.particles.geometry.vertices.length);并获得正确的输出,但它仍然说它不存在。 enter image description here

2 个答案:

答案 0 :(得分:1)

原因是,当我们使用THREE.Points时,TypeScript无法知道我们将它们与Geometry还是BufferGeometry一起使用。我只需在您的render()方法中添加以下行:

const geometry = this.particles.geometry as Geometry

,并在以下代码中使用geometry代替this.particles.geometry。这实际上将告诉TypeScript“我知道,它将永远是Geometry,请相信我。”

答案 1 :(得分:0)

我改变了我的公共粒子= THREE.Points; - &GT;公共粒子:any = THREE.Points;

这为我修好了,但我只是没有类型,那很糟糕,但如果你知道你在改变什么,那么你应该没事。

固定代码:

import { Component, AfterViewInit, ElementRef, Input, ViewChild, HostListener} from '@angular/core';
import { TweenLite } from 'gsap';
import * as THREE from 'three';
declare const require: (moduleId: string) => any;
var OrbitControls = require('three-orbit-controls')(THREE);

@Component({
    selector: 'shared-background-scene',
    templateUrl: './backgroundScene.component.html',
    styleUrls: ['./backgroundScene.component.scss']
})

export class BackgroundSceneComponent {

    public scene: THREE.Scene;
    private renderer: THREE.WebGLRenderer;
    private camera: THREE.PerspectiveCamera;
    private cameraTarget: THREE.Vector3;
    public controls: THREE.OrbitControls;

    public fieldOfView: number = 60;
    public nearClippingPane: number = 1;
    public farClippingPane: number = 1100;

    @ViewChild('canvas')
    private canvasRef: ElementRef;

    public particles:any = THREE.Points;
    public imageData: any;
    public geometry = new THREE.Geometry();
    public material = new THREE.PointsMaterial({
                size: 3,
                color: 0x313742,
                sizeAttenuation: false
    });
    public loadImage() {
        //load texture, which is the image, and then get the imagedata, and draw image.
        var texture = new THREE.TextureLoader().load("assets/img/transparentMap.png", () => { console.log(texture); this.imageData = this.getImageData(texture.image); this.drawImage(); this.startRendering(); })
    }

    public getImageData(image: any) {
        console.log(image);
        // Create canvas for the image
        let canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.width;

        // Make sure context is 2d
        let context = canvas.getContext("2d");
        context!.drawImage(image, 0, 0);

        //return the context to be saved to the imageData.
        return context!.getImageData(0, 0, image.width, image.height);
    }

    public drawImage() {

        // Create vertices to draw the image.
        for (var y = 0, y2 = this.imageData.height; y < y2; y += 2) {
            for (var x = 0, x2 = this.imageData.width; x < x2; x += 2) {
                if (this.imageData.data[(x * 4 + y * 4 * this.imageData.width) + 3] > 128) {

                    let vertex:any = new THREE.Vector3();
                    vertex.x = Math.random() * 1000 - 500;
                    vertex.y = Math.random() * 1000 - 500;
                    vertex.z = -Math.random() * 500;

                    vertex.destination = {
                        x: x - this.imageData.width / 2,
                        y: -y + this.imageData.height / 2,
                        z: 0
                    };

                    vertex.speed = Math.random() / 200 + 0.015;

                    this.geometry.vertices.push(vertex);
                }
            }
        }
        this.particles = new THREE.Points(this.geometry, this.material);
        this.scene.add(this.particles);

        requestAnimationFrame(this.render);
    }

    constructor() {
        this.render = this.render.bind(this);
    }

    private get canvas(): HTMLCanvasElement {
        return this.canvasRef.nativeElement;
    }

    private createScene() {
        this.scene = new THREE.Scene();
    }

    private createCamera() {
        let aspectRatio = this.getAspectRatio();
        this.camera = new THREE.PerspectiveCamera(
            this.fieldOfView,
            aspectRatio,
            this.nearClippingPane,
            this.farClippingPane
        );

        // Set position and look at
        this.camera.position.x = 10;
        this.camera.position.y = 10;
        this.camera.position.z = 100;
    }

    private getAspectRatio(): number {
        let height = this.canvas.clientHeight;
        if (height === 0) {
            return 0;
        }
        return this.canvas.clientWidth / this.canvas.clientHeight;
    }

    private startRendering() {
        this.renderer = new THREE.WebGLRenderer({
            canvas: this.canvas,
            antialias: true
        });
        this.renderer.setPixelRatio(devicePixelRatio);
        this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);

        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.renderer.setClearColor(0xffffff, 1);
        this.renderer.autoClear = true;

        let component: BackgroundSceneComponent = this;

        (function render() {
            requestAnimationFrame(render);
            component.render();
        }());
    }

    public render() {
        this.renderer.render(this.scene, this.camera);

        // Draw image to screen
        for (var i = 0, j = this.particles.geometry.vertices.length; i < j; i++) {
            var particle:any = this.particles.geometry.vertices[i];
            particle.x += (particle.destination.x - particle.x) * particle.speed;
            particle.y += (particle.destination.y - particle.y) * particle.speed;
            particle.z += (particle.destination.z - particle.z) * particle.speed;
        }
        this.particles.geometry.verticesNeedUpdate = true;
    }

    public addControls() {
        this.controls = new OrbitControls(this.camera);
        this.controls.rotateSpeed = 1.0;
        this.controls.zoomSpeed = 1.2;
        this.controls.addEventListener('change', this.render);

    }

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

    /* Events */
   private onResize(event: Event) {
        this.canvas.style.width = "100%";
        this.canvas.style.height = "100vh";
        //console.log("onResize: " + this.canvas.clientWidth + ", " + this.canvas.clientHeight);

        this.camera.aspect = this.getAspectRatio();
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
        this.render();
    }

    /* LIFECYCLE */
   ngAfterViewInit() {
        this.createScene();
        this.createCamera();
        this.loadImage(); // rendering starts here
        this.loadCubeModel();
        this.addControls();
    }
}