All files / apps/web/src/components/graph3d ring.js

0% Statements 0/23
0% Branches 0/7
0% Functions 0/1
0% Lines 0/22

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                                                                                                               
/**
 * Sprite « anneau » — équivalent 3D du contour de sélection du graphe 2D
 * (`strokeWidth 2.5`, couleur slate-900) et du repère de pivot de la caméra.
 *
 * Rendu dans un canvas hors écran, comme les libellés, pour rester testable
 * sans WebGL.
 */
import * as THREE from 'three';
 
const TEXTURE_SIZE = 128;
 
/**
 * @param {string} [color] couleur du trait (hex)
 * @param {{ opacity?: number, thickness?: number, scale?: number }} [options]
 *   `scale` = diamètre du sprite en unités monde
 * @returns {THREE.Sprite|null}
 */
export function makeRingSprite(
  color = '#0f172a',
  { opacity = 0.95, thickness = 5, scale = 12 } = {},
) {
  try {
    const canvas = document.createElement('canvas');
    canvas.width = canvas.height = TEXTURE_SIZE;
    const ctx = canvas.getContext('2d');
    if (!ctx) return null;
 
    const half = TEXTURE_SIZE / 2;
    const radius = half - thickness - 2;
    ctx.strokeStyle = color;
    ctx.globalAlpha = opacity;
    ctx.lineWidth = thickness;
    ctx.beginPath();
    ctx.arc(half, half, radius, 0, 2 * Math.PI);
    ctx.stroke();
 
    const texture = new THREE.CanvasTexture(canvas);
    texture.colorSpace = THREE.SRGBColorSpace;
    texture.needsUpdate = true;
 
    const sprite = new THREE.Sprite(
      new THREE.SpriteMaterial({
        map: texture,
        transparent: true,
        depthTest: false,
        depthWrite: false,
      }),
    );
    sprite.scale.set(scale, scale, 1);
    sprite.renderOrder = 2;
    return sprite;
  } catch {
    return null;
  }
}