Skip to content

Compatibility issue between hoverer and highlighter #753

@Saigesp

Description

@Saigesp

Describe the bug 📝

I've encountered this error, and I don't understand why it appears on my laptop but not on my desktop:

It turns out that the hoverer cannot be enabled before the highlighter has been triggered.

If I activate both the highlighter and the hoverer at the same time in a viewer, neither of them works. If I activate only the highlighter and then activate the hoverer before clicking on any element, nothing works either. However, if I only have the highlighter activated, click on an element, and then activate the hoverer, both work fine.

No error is shown in anywhere :/

I'm working with the versions:

@thatopen/components: 3.4.6
@thatopen/components-front: 3.4.3
@thatopen/fragments: 3.4.5

Reproduction ▶️

No response

Steps to reproduce 🔢

I've wrapped the code in a class so it can be loaded externally:

import * as OBC from '@thatopen/components';
import * as OBCF from '@thatopen/components-front';
import * as FRAGS from '@thatopen/fragments';
import * as THREE from 'three';

export default class {
  /**
   * Construct new class instance
   * @param {string} containerId html container ID
   */
  constructor(containerId) {
    this.containerId = containerId;
  }

  /**
   * Init viewer
   */
  async init() {
    const container = document.getElementById(this.containerId);
    const components = new OBC.Components();
    components.init();

    this.world = components.get(OBC.Worlds).create();
    this.world.scene = new OBC.SimpleScene(components);
    this.world.renderer = new OBCF.PostproductionRenderer(components, container, {
      preserveDrawingBuffer: true,
    });

    this.world.camera = new OBC.OrthoPerspectiveCamera(components);
    this.world.scene.setup();
    this.world.scene.three.background = '#000000';

    // Fragments
    const workerUrl = await FRAGS.FragmentsModels.getWorker();
    this.fragments = components.get(OBC.FragmentsManager);
    this.fragments.init(workerUrl);
    this.world.camera.controls.addEventListener('update', () => {
      this.fragments.core.update(true);
    });
    this.world.onCameraChanged.add((camera) => {
      for (const [, model] of this.fragments.list) {
        model.useCamera(camera.three);
      }
      this.fragments.core.update(true);
    });
    this.fragments.list.onItemSet.add(({ value: model }) => {
      model.useCamera(this.world.camera.three);
      this.world.scene.three.add(model.object);
    });

    this.world.camera.updateAspect();

    // Raycaster (import before highlighter)
    this.raycaster = components.get(OBC.Raycasters).get(this.world);

    // Highlighter
    this.highlighter = components.get(OBCF.Highlighter);
    this.highlighter.setup({
      world: this.world,
      selectMaterialDefinition: {
        opacity: 0.9,
        transparent: true,
        color: new THREE.Color(0x2dd9a9),
        depthTest: false, // avoid z-fighting
      },
    });
    this.highlighter.enabled = true;

    // Hoverer
    this.hoverer = components.get(OBCF.Hoverer);
    this.hoverer.world = this.world;
    this.hoverer.material = new THREE.MeshBasicMaterial({
      opacity: 0.9,
      transparent: true,
      color: new THREE.Color(0x2dd9a9),
      depthTest: false, // avoid z-fighting
    });
    this.hoverer.enabled = false;
  }

  /**
   * Read IFC files
   * @param {string} filePath path to the IFC file
   */
  static readFileFromPath(filePath) {
    return new Promise((resolve) => {
      fetch(filePath).then((file) => file.arrayBuffer().then((data) => {
        resolve(new Uint8Array(data));
      }));
    });
  };

  /**
   * Load a fragments (.frag) file
   * @param {ArrayBuffer|Uint8Array} buffer Fragments file buffer
   * @param {string} modelId unique model ID
   * @returns {Promise<FragmentsModel>} resolves with the loaded model
   */
  load(buffer, modelId) {
    return this.fragments.core.load(buffer, { modelId, raw: false });
  }

  /**
   * Set the visibility of the hoverer
   * @param {boolean} visible visibility state to apply
   */
  setHovererVisibility(visible) {
    this.hoverer.enabled = Boolean(visible);
  }
}

Then, on your js environment, execute:

import Viewer from 'path/to/the/class';

viewer = Viewer('#your-container-id')
viewer.init()

// to enable the hoverer at demand:
viewer.setHovererVisibility(true);

System Info 💻

System:
    OS: Linux 7.0 Ubuntu 26.04 LTS 26.04 (Resolute Raccoon)
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
    Memory: 5.72 GB / 14.92 GB
    Container: Yes
    Shell: 5.3.9 - /bin/bash
  Binaries:
    Node: 24.15.0 - /home/saigesp/.nvm/versions/node/v24.15.0/bin/node
    npm: 11.12.1 - /home/saigesp/.nvm/versions/node/v24.15.0/bin/npm
  Browsers:
    Chrome: 148.0.7778.96
    Firefox: 151.0.2
    Firefox Developer Edition: 151.0.2

Used Package Manager 📦

npm

Error Trace/Logs 📃

No error is shown in the console

Validations ✅

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • Make sure this is a repository issue and not a framework-specific issue. For example, if it's a THREE.js related bug, it should likely be reported to mrdoob/threejs instead.
  • Check that this is a concrete bug. For Q&A join our Community.
  • The provided reproduction is a minimal reproducible example of the bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions