Mousedown event is not getting triggered

Hi I am trying to load a glb file using threejs library which is working fine. I want to draw a rectangle on that 3D object model but due to some reason mousedown event is not getting triggered.

Here is the code sample:-

    import { Component, ViewChild, ElementRef, AfterViewInit, OnInit , NgZone} from '@angular/core';
import * as THREE from 'three';
// import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls';
import { FlexAlignStyleBuilder } from '@angular/flex-layout';

const fov = 45;
const near = 5;
const far = 100;

@Component({
  selector: 'ms-building-model-two-d-view',
  templateUrl: './building-model-two-d-view.component.html',
  styleUrls: ['./building-model-two-d-view.component.scss']
})
export class BuildingModelTwoDViewComponent implements OnInit, AfterViewInit {

  @ViewChild('viewContainer') viewContainer: ElementRef;
  // canvas: any;
  @ViewChild('canvas') canvas: ElementRef;

  view = 'front';
  scene: any;
  renderer: any;

  camera: any;

  controls: any;

  loader: any;
  dracoLoader: any;
  model: any;
  target: any;

  width: any;
  height: any;

  dragging: boolean;
  rayCaster: any;
  startPosition: any = {
    x: 0,
    y: 0
  };

  vertexSize: any;
  geometry: any;

  constructor(private zone: NgZone) {
  }

  ngOnInit(): void {
  }

  ngAfterViewInit(): void {
    // return;

    this.rayCaster = new THREE.Raycaster();
    this.geometry = new THREE.PlaneGeometry( 0, 0  );
    this.renderer = new THREE.WebGLRenderer({
      canvas: this.canvas.nativeElement
    });


    this.width = this.canvas.nativeElement.clientWidth;
    this.height = this.canvas.nativeElement.clientHeight;
    this.interactionsSetup()

    this.renderer.setSize(this.width - 20, this.height);

    this.renderer.setPixelRatio(window.devicePixelRatio);

    // this.viewContainer.nativeElement.appendChild(this.renderer.domElement);



    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color('black');

    this.cameraSetup();
    this.lightSetup();
    this.objectSetup()
  }

  onViewChanges = (event) => {
    this.view = event.value;
    this.cameraSetup()
  }

  cameraSetup() {

    const position = []

    if (this.view === 'front') {
      position.push(100, 0, 0)
    } else if (this.view === 'side') {
      position.push(0, 0, 100)
    } else if (this.view === 'top') {
      position.push(0, 100, 0)
    }

    this.camera = new THREE.OrthographicCamera(
      this.width / - 2, this.width / 2, this.height / 2, this.height / - 2, 1, 1000 )
      // 0, 0, 0, 0, near, far);
    this.camera.zoom = 10;
    this.camera.position.set(...position);
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);

    // this.prospectiveCamera = new THREE.PerspectiveCamera(fov, 0, near, far);
    // this.prospectiveCamera.position.set(10, 10, 10);
    // this.prospectiveControls = new OrbitControls(this.prospectiveCamera, this.prospectiveContainer.nativeElement);
    // this.prospectiveControls.update();
  }

  lockRotation = (event) => {

    if (event.checked) {
      this.controls.enableRotate = false;
      this.controls.enable = false;
    } else {
      this.controls.enableRotate = true;
      this.controls.enable = true;
    }
    this.controls.update();
  }

  // lightSetup() {
  //   const color = 0xFFFFFF;
  //   const intensity = 1;
  //   const light = new THREE.DirectionalLight(color, intensity);
  //   light.position.set(0, 10, 0);
  //   light.target.position.set(-5, 0, 0);
  //   this.scene.add(light);
  //   this.scene.add(light.target);
  // }

  lightSetup = () => {
    this.addAmbientLight();
    this.addSpotLight();
    this.addRectLight();
    this.addPointLight(0xfff000, { x: 0, y: 10, z: -100 });
    this.addPointLight(0x79573e, { x: 100, y: 10, z: 0 });
    this.addPointLight(0xc27439, { x: 20, y: 5, z: 20 });
  }

  addAmbientLight = () => {
    const light = new THREE.AmbientLight("#ffffff", 1);

    this.scene.add(light);
  }

  addSpotLight = () => {
    const light = new THREE.SpotLight("#ca6631", 1, 10000);

    light.position.set(-5, 100, -5);
    // light.shadowMap = new THREE.Vector2(4096, 4096);
    light.shadowBias = 0.001;
    light.castShadow = true;

    this.scene.add(light);
  }

  addRectLight = () => {
    const light = new THREE.RectAreaLight("#341212", 1, 2000, 2000);

    light.position.set(5, 50, 50);
    light.lookAt(0, 0, 0);

    this.scene.add(light);
  }

  addPointLight = (color, position) => {
    const light = new THREE.PointLight(color, 1, 1000, 1);

    light.position.set(position.x, position.y, position.z);

    this.scene.add(light);
  }

  objectSetup = () => {
    // const cubeSize = 4;
    // const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
    // const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
    // const mesh = new THREE.Mesh(cubeGeo, cubeMat);
    // mesh.position.set(0, 0, 0);
    // this.scene.add(mesh);

    /*
          * Create a Rectangle
          */
    this.geometry.vertices.push(new THREE.Vector3(-this.vertexSize, this.vertexSize, 0.0));
    this.geometry.vertices.push(new THREE.Vector3(this.vertexSize, this.vertexSize, 0.0));
    this.geometry.vertices.push(new THREE.Vector3(this.vertexSize, -this.vertexSize, 0.0));
    this.geometry.vertices.push(new THREE.Vector3(-this.vertexSize, -this.vertexSize, 0.0));
    this.geometry.faces.push(new THREE.Face3(0, 1, 2));
    this.geometry.faces.push(new THREE.Face3(0, 2, 3));

    const material = new THREE.MeshBasicMaterial({
      color: 0xDB1E1E,
      wireframe: true,
      side: THREE.DoubleSide
    });

    const mesh = new THREE.Mesh(this.geometry, material);
    mesh.rotation.x = Math.PI / 2;
    this.scene.add(mesh);


    this.loader = new GLTFLoader();

    this.dracoLoader = new DRACOLoader();
    this.dracoLoader.setDecoderPath("three/examples/js/libs/draco/");
    this.loader.setDRACOLoader(this.dracoLoader);

    this.loader.load('../../../../assets/model/blender_optimize.glb', (gltf) => {

      const box = new THREE.Box3().setFromObject(gltf.scene);
      const center = new THREE.Vector3();
      box.getCenter(center);

      gltf.scene.position.sub( center ); // center the model
      gltf.scene.rotation.y = Math.PI;
      // gltf.scene.position.x += gltf.scene.position.x - center.x;
      // gltf.scene.position.y += gltf.scene.position.y - center.y;
      // gltf.scene.position.z += gltf.scene.position.z - center.z;
      this.scene.add(gltf.scene);
      // gltf.scene.matrixAutoUpdate = false;
      // gltf.scene.updateMatrix()

      // new TrackballControls( this.camera , this.renderer.domElement);

      this.render()
      // this.canvasSetup();
    }, (xhr) => {

      console.log((xhr.loaded / xhr.total * 100) + '% loaded');

    },
      // called when loading has errors
      (error) => {

        console.log('An error happened');

      });

  }

  interactionsSetup = () => {
    // this.canvas = this.renderer.domElement;
    // console.log(this.canvas)
    this.canvas.nativeElement.addEventListener('mousedown',
    this.logThis.bind(this))
    // this.canvas.nativeElement.onmousemove = this.onDrag.bind(this);
    // this.canvas.nativeElement.onmouseup = this.onMouseUp.bind(this);
  }

  get3DPosition = (event) => {
    const offset = this.canvas.nativeElement.getBoundingClientRect();
    const position = {
      x: ((event.clientX - offset.left) / this.canvas.nativeElement.clientWidth) * 2 - 1,
      y: -((event.clientY - offset.top) / this.canvas.nativeElement.clientHeight) * 2 + 1
    };
    this.rayCaster.setFromCamera(position, this.camera);
    const intersects = this.rayCaster.intersectObjects(this.scene.children, true);
    if (intersects.length > 0) {
      return intersects[0].point;
    }
  }

  onMouseDown = (e) => {
    // debugger;
    console.log('Mouse Down')

    const relative = this.get3DPosition(e);
    if (!relative) {
      return;
    }
    this.dragging = true;
    this.startPosition.x = e.pageX;
    this.startPosition.y = e.pageY;
    this.scene.children[1].position.set(relative.x + this.vertexSize, relative.y, relative.z);
    // this.controls.enabled = false;
  }

  onDrag = (e) => {
    if (this.dragging) {
      const clientX = (e.pageX - this.startPosition.x) / 10;
      const clientY = (e.pageY - this.startPosition.y) / 10;
      const vertices = this.geometry.vertices;
      vertices[1].x = -clientX * -1;
      vertices[2].x = -clientX * -1;
      vertices[2].y = -clientY * -1;
      vertices[3].y = -clientY * -1;
      this.geometry.verticesNeedUpdate = true;
    }
  }

  onMouseUp = () => {
    this.dragging = false;
  }

  startAnimationLoop = () => {
    // this.target.x = (1 - this.mouse.x) * 0.001;
    // this.target.y = (1 - this.mouse.y) * 0.001;
    // this.renderer.render(this.scene, this.camera);
    window.requestAnimationFrame(this.startAnimationLoop);
  }

  render() {

    this.resizeRendererToDisplaySize();

    // turn on the scissor
    // this.renderer.setScissorTest(true);

    this.scene.background.set(0xffffff);

    // render from the 1st camera
    // const elementViewSize = this.setScissorForElement(this.viewContainer.nativeElement);

    const canvasRect = this.canvas.nativeElement.getBoundingClientRect();
    const elementViewSize = {
      width: canvasRect.width,
      height: canvasRect.height
    }

    // adjust the camera for this aspect
    this.camera.left = elementViewSize.width / -2;
    this.camera.right = elementViewSize.width / 2;
    this.camera.top = elementViewSize.height / 2;
    this.camera.bottom = elementViewSize.height / -2;
    this.camera.updateProjectionMatrix();
    this.renderer.render(this.scene, this.camera);

    // elementViewSize = this.setScissorForElement(this.prospectiveContainer.nativeElement);
    // // adjust the camera for this aspect
    // this.prospectiveCamera.aspect = elementViewSize.width / elementViewSize.height;
    // this.prospectiveCamera.updateProjectionMatrix();
    // // render
    // this.renderer.render(this.scene, this.prospectiveCamera);

    window.requestAnimationFrame(this.render.bind(this));
  }

  resizeRendererToDisplaySize() {
    // this.canvas = this.renderer.domElement;
    const width = this.canvas.nativeElement.clientWidth;
    const height = this.canvas.nativeElement.clientHeight;
    const needResize = this.canvas.nativeElement.width !== width || this.canvas.nativeElement.height !== height;
    if (needResize) {
      this.renderer.setSize(width - 20, height, false);
    }
    return needResize;
  }

  // setScissorForElement (elem) {
  //   const canvasRect = this.canvas.getBoundingClientRect();
  //   const elemRect = elem.getBoundingClientRect();

  //   // compute a canvas relative rectangle
  //   const right = Math.min(elemRect.right, canvasRect.right) - canvasRect.left;
  //   const left = Math.max(0, elemRect.left - canvasRect.left);
  //   const bottom = Math.min(elemRect.bottom, canvasRect.bottom) - canvasRect.top;
  //   const top = Math.max(0, elemRect.top - canvasRect.top);

  //   const width = Math.min(canvasRect.width, right - left);
  //   const height = Math.min(canvasRect.height, bottom - top);

  //   // setup the scissor to only render to that part of the canvas
  //   const positiveYUpBottom = canvasRect.height - bottom;
  //   // const x = top
  //   this.renderer.setScissor(left, top, width, height);
  //   this.renderer.setViewport(left, top, width, height);

  //   // return the aspect
  //   return {
  //     width: width,
  //     height: height
  //   };
  // }

  logThis() {
    alert('clicked')
  }
}

Check interactionsSetup method, There I am trying to add an eventListener which mousedown to the canvas, But its not working.
I should be able to click on the canvas and when I do, it should alert “Clicked”.

Please try it with the pointerdown event instead. Since r120, OrbitControls uses Pointer Events which requires the app to use Poiner Events, too.

4 Likes

Thank you, It really helped.