HTML overlay always gets clipped when it is larger than the canvas in react-three-fiber

Viewed 116

I am trying to display a tooltip or a HTML overlay on the instances in an instanced mesh in three.js via react-three-fiber. However I am facing an issue in the sense that if the content is large, which is often the case, the content gets clipped vertically.

enter image description here

As you can see here, the HTML overlay div gets clipped vertically. No scrolling bar appears. I can change the width if I specify it in terms of vw, but nothing seems to work for height. Moreover the idea is that it should automatically adapt to the size of the display or a predetermined max size.

I feel that it is getting "sucked in" or constrained by the canvas size. Perhaps this issue would not arise if it was on top or somehow detached from it.

The code that I have so far is -

Steps to setup -

npx create-react-app demo
cd demo
npm install three
npm i @react-three/fiber
npm i @react-three/drei

App.jsx

import React from 'react'
import { Suspense } from "react";
import { OrbitControls, Html } from "@react-three/drei";
import Spheres from "./IScatter";
import * as THREE from "three";
import { Canvas, extend, useThree, useFrame } from '@react-three/fiber'


function App() {
  return (
   <div>
      <Canvas style={{width:"100%",height:"100vh"}}>
        <OrbitControls enableZoom={true} />
        <ambientLight intensity={0.5} />
        <pointLight position={[10, 10, 10]}/>
        <Suspense fallback={null}>
        <primitive object={new THREE.AxesHelper(1.5)} />
        <Spheres />
        </Suspense>
      </Canvas>
      </div>
  );
}

export default App;

Tooltip.jsx

import React, {useState, useEffect, useLayoutEffect, useRef} from "react";

function Tooltip( {title, story, author, emotions} ){

    return (
        <div style={{display: "inline-block", width: "50vw", height: "30vh"}}>
            <h6 class="title is-6">{ title }</h6>
            <p>{story}</p>
            {/* <br /> */}
            <span class="is-pulled-right">-{author}</span><br/>
        </div>
    )
}

export default Tooltip;

IScatter.jsx

import * as THREE from "three";
import React, { useRef, useState, useMemo, useLayoutEffect } from "react";
import { OrbitControls, Stats, Html } from "@react-three/drei";
import { useEffect } from "react";
import { DoubleSide } from "three";
import data from "./story.json";
import Tooltip from "./Tooltip";

const points = [ [1, 0, -1], [0, 1, -0.5], [0.5, 0.5, 0.5], [1,0.25,-1], [1,0,1], [0,1,0.5] ];
const colors = [0,0,0,5,5,5];
const tempColor = new THREE.Color();
const tempSphere = new THREE.Object3D();

const Spheres = () => {
  const material = new THREE.MeshLambertMaterial({ opacity: 0.5, side: THREE.DoubleSide, transparent: true,});
  const spheresGeometry = new THREE.SphereBufferGeometry(0.25, 15, 15);

  const ref = useRef();
  const prevRef = useRef();
  const [hovered, set] = useState();

  useEffect(() => {
    points.map(function (val, row) {
        tempSphere.position.set(val[0], val[1], val[2]);
        tempSphere.updateMatrix();
        ref.current.setMatrixAt(row, tempSphere.matrix);
        ref.current.setColorAt(row, new THREE.Color(`hsl(${colors[row]*100}, 100%, 50%)`));
       
      });
      if (hovered !== prevRef.current) {
        ref.current.setColorAt(hovered, new THREE.Color("hsl(43, 100%, 50%)"));
        ref.current.instanceColor.needsUpdate = true;
      }
    ref.current.instanceMatrix.needsUpdate = true;
  },[hovered]);

  return (
        <instancedMesh 
        onPointerOver={(e) => (e.stopPropagation(), set(e.instanceId))}
        onPointerOut={(e) => set(undefined)}
        ref={ref} rotation={[0,30,0]} args={[spheresGeometry, material, 15]}>
        <Html distanceFactor={5}>
          <Tooltip title={data.title} story={data.story} author={data.author}></Tooltip>
      </Html>
      </instancedMesh>
  );
};

export default Spheres;

Please take the story.json file from this gist.

What is the best way to ensure that I can also display custom HTML on mouseover and that the contents of the display are fully visible?

1 Answers

I have not been able to figure out why this happens but R3F for some reason adds overflow: hide to the divs. When I manually supply the style overflow: visible to the HTML overlay along with some predefined width, the tooltip works as expected. I found this out experimentally, I don't really know why things would work this way.

I will wait for a better answer for this.

Related