All files / app/assets/javascripts/blob/3d_viewer index.js

0% Statements 0/49
100% Branches 0/0
0% Functions 0/11
0% Lines 0/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115                                                                                                                                                                                                                                     
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader';
import * as THREE from 'three';
import MeshObject from './mesh_object';
 
export default class Renderer {
  constructor(container) {
    this.renderWrapper = this.render.bind(this);
    this.objects = [];
 
    this.container = container;
    this.width = this.container.offsetWidth;
    this.height = 500;
 
    this.loader = new STLLoader();
 
    this.fov = 45;
    this.camera = new THREE.PerspectiveCamera(this.fov, this.width / this.height, 1, 1000);
 
    this.scene = new THREE.Scene();
 
    this.scene.add(this.camera);
 
    // Set up the viewer
    this.setupRenderer();
    this.setupGrid();
    this.setupLight();
 
    // Set up OrbitControls
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.controls.minDistance = 5;
    this.controls.maxDistance = 30;
    this.controls.enableKeys = false;
 
    this.loadFile();
  }
 
  setupRenderer() {
    this.renderer = new THREE.WebGLRenderer({
      antialias: true,
    });
 
    this.renderer.setClearColor(0xffffff);
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(this.width, this.height);
  }
 
  setupLight() {
    // Point light illuminates the object
    const pointLight = new THREE.PointLight(0xffffff, 2, 0);
 
    pointLight.castShadow = true;
 
    this.camera.add(pointLight);
 
    // Ambient light illuminates the scene
    const ambientLight = new THREE.AmbientLight(0xffffff, 1);
    this.scene.add(ambientLight);
  }
 
  setupGrid() {
    this.grid = new THREE.GridHelper(20, 20, 0x000000, 0x000000);
 
    this.scene.add(this.grid);
  }
 
  loadFile() {
    this.loader.load(this.container.dataset.endpoint, (geo) => {
      const obj = new MeshObject(geo);
 
      this.objects.push(obj);
      this.scene.add(obj);
 
      this.start();
      this.setDefaultCameraPosition();
    });
  }
 
  start() {
    // Empty the container first
    this.container.innerHTML = '';
 
    // Add to DOM
    this.container.appendChild(this.renderer.domElement);
 
    // Make controls visible
    this.container.parentNode.classList.remove('is-stl-loading');
 
    this.render();
  }
 
  render() {
    this.renderer.render(this.scene, this.camera);
 
    requestAnimationFrame(this.renderWrapper);
  }
 
  changeObjectMaterials(material) {
    this.objects.forEach((obj) => {
      obj.changeMaterial(material);
    });
  }
 
  setDefaultCameraPosition() {
    const obj = this.objects[0];
    const radius = obj.geometry.boundingSphere.radius / 1.5;
    const dist = radius / Math.sin((this.fov * (Math.PI / 180)) / 2);
 
    this.camera.position.set(0, dist + 1, dist);
 
    this.camera.lookAt(this.grid);
    this.controls.update();
  }
}