1

I'm loading object like this demo, where I want to show tooltip / infobox on mouse over that particular part. (Like on clicking button top, I want to show tooltip on top of the box). I tried these examples, but not working with my obj.

Example 1 Example 2

I tried like

 cube.name = "top cube";
  cube.getObjectbyname = "top cube obj";
  scene.add(cube); // add cube to the scene

I'm new to three.js and angular material. So I don't know how to add tooltip. How can I fix it? I don't know how to link my button and object top / left / right.

halfer
  • 19,824
  • 17
  • 99
  • 186
G.L.P
  • 7,119
  • 5
  • 25
  • 41
  • I might be misunderstanding your question, but I think this has already been answered here: https://stackoverflow.com/questions/47297794/how-to-overlay-html-text-buttons-on-three-js – TomBonynge Feb 17 '21 at 12:29
  • @TomBonynge: This is different, i need tooltip on box, not popup.. but thanks i got idea from this :-) – G.L.P Feb 18 '21 at 06:25

1 Answers1

2

This example features tooltips via the CSS2DRenderer module, but they are always-on and synced to objects' positions.

If you want them to only appear on hover, you will have to selectively toggle them via a Raycaster (sample code included in docs).

Below is an example of the combined techniques (Codesandbox) with a single, shared label that moves and updates to hovered elements in your scene:

body {
  margin: 0;
}

canvas {
  cursor: grab;
  display: block;
}

canvas:active {
  cursor: grabbing;
}

.hovered {
  cursor: help;
}

.label {
  color: #fff;
  font-family: sans-serif;
  padding: 2px;
  background: rgba(0, 0, 0, 0.6);
}
<script type="module">
  import {
    WebGLRenderer,
    PerspectiveCamera,
    Scene,
    BoxGeometry,
    MeshNormalMaterial,
    Mesh,
    Vector3,
    Box3,
    Raycaster,
    Vector2,
  } from 'https://unpkg.com/three@0.125.2/build/three.module.js';
  import { OrbitControls } from 'https://unpkg.com/three@0.125.2/examples/jsm/controls/OrbitControls.js';
  import {
    CSS2DRenderer,
    CSS2DObject,
  } from 'https://unpkg.com/three@0.125.2/examples/jsm/renderers/CSS2DRenderer.js';

  // Boilerplate
  const { innerWidth, innerHeight } = window;

  const renderer = new WebGLRenderer({ alpha: true, antialias: true });
  renderer.setSize(innerWidth, innerHeight);
  renderer.setPixelRatio(2);
  document.body.appendChild(renderer.domElement);

  const camera = new PerspectiveCamera(70, innerWidth / innerHeight, 0.1, 10);
  camera.position.z = 1;

  const controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;

  const scene = new Scene();

  const geometry = new BoxGeometry(0.2, 0.2, 0.2);
  const material = new MeshNormalMaterial();
  const mesh = new Mesh(geometry, material);
  mesh.name = 'mesh';
  scene.add(mesh);

  // Setup labels
  const labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(innerWidth, innerHeight);
  labelRenderer.domElement.style.position = 'absolute';
  labelRenderer.domElement.style.top = '0px';
  labelRenderer.domElement.style.pointerEvents = 'none';
  document.body.appendChild(labelRenderer.domElement);

  const labelDiv = document.createElement('div');
  labelDiv.className = 'label';
  labelDiv.style.marginTop = '-1em';
  const label = new CSS2DObject(labelDiv);
  label.visible = false;
  scene.add(label);

  // Track mouse movement to pick objects
  const raycaster = new Raycaster();
  const mouse = new Vector2();

  window.addEventListener('mousemove', ({ clientX, clientY }) => {
    const { innerWidth, innerHeight } = window;

    mouse.x = (clientX / innerWidth) * 2 - 1;
    mouse.y = -(clientY / innerHeight) * 2 + 1;
  });

  // Handle window resize
  window.addEventListener('resize', () => {
    const { innerWidth, innerHeight } = window;

    renderer.setSize(innerWidth, innerHeight);
    camera.aspect = innerWidth / innerHeight;
    camera.updateProjectionMatrix();
  });

  renderer.setAnimationLoop(() => {
    controls.update();

    // Pick objects from view using normalized mouse coordinates
    raycaster.setFromCamera(mouse, camera);

    const [hovered] = raycaster.intersectObjects(scene.children);

    if (hovered) {
      // Setup label
      renderer.domElement.className = 'hovered';
      label.visible = true;
      labelDiv.textContent = hovered.object.name;

      // Get offset from object's dimensions
      const offset = new Vector3();
      new Box3().setFromObject(hovered.object).getSize(offset);

      // Move label over hovered element
      label.position.set(
        hovered.object.position.x,
        offset.y / 2,
        hovered.object.position.z
      );
    } else {
      // Reset label
      renderer.domElement.className = '';
      label.visible = false;
      labelDiv.textContent = '';
    }

    // Render scene
    renderer.render(scene, camera);

    // Render labels
    labelRenderer.render(scene, camera);
  });
</script>
Moritz Ringler
  • 9,772
  • 9
  • 21
  • 34
Cody Bennett
  • 766
  • 5
  • 10