Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 41

Gestion des événements souris sur les meshes JSX

Recommended resources

Bonjour !

Dans la leçon précédente, nous avons appris à sculpter la lumière de nos scènes avec le composant <Lightformer>, nous transformant en véritables directeurs de la photographie virtuelle. Nos créations sont maintenant belles et bien éclairées, mais elles restent statiques. Il est temps de leur donner vie !

Aujourd'hui, nous allons franchir une étape décisive en rendant nos objets 3D interactifs. L'objectif de cette leçon est d'apprendre à gérer les événements de la souris comme onClick et onPointerOver directement sur les meshes JSX. C'est l'une des fonctionnalités les plus puissantes de React Three Fiber, car elle nous permet d'utiliser la logique événementielle de React, que vous connaissez peut-être déjà du développement web, dans un contexte 3D. Fini le raycasting manuel complexe de Three.js ; place à l'interactivité déclarative !

Mouse Events with R3F Lesson Thumbnail
Cette image illustre parfaitement notre sujet du jour : faire réagir les objets 3D à la souris.

1. Les bases des événements dans R3F

Si vous avez déjà utilisé des événements comme onClick sur un bouton en HTML/React, la transition vers React Three Fiber (R3F) va vous sembler naturelle. R3F mappe des gestionnaires d'événements similaires directement sur les objets de votre scène 3D.

Les événements les plus courants sont :

  • onClick : Se déclenche lors d'un clic complet (pression + relâchement) sur l'objet.
  • onPointerOver / onPointerEnter : Se déclenche lorsque le pointeur de la souris entre dans la zone de l'objet.
  • onPointerOut / onPointerLeave : Se déclenche lorsque le pointeur quitte la zone de l'objet.
  • onPointerDown : Se déclenche dès que le bouton de la souris est pressé sur l'objet.
  • onPointerUp : Se déclenche dès que le bouton de la souris est relâché.
  • onPointerMove : Se déclenche lorsque le pointeur se déplace au-dessus de l'objet.

La manière la plus simple de les utiliser est de les combiner avec le hook useState de React pour suivre l'état d'interaction d'un objet (par exemple, "est survolé" ou "est cliqué") et de modifier ses propriétés en conséquence.

Pour illustrer ce principe, l'exemple fondamental de la documentation de R3F est idéal.

R3F - Introduction - React Three Fiber

La documentation officielle de React Three Fiber présente un exemple parfait pour commencer. Il montre un composant Box réutilisable qui réagit au survol et au clic.

Analysez l'exemple de code JavaScript du composant Box. Repérez les gestionnaires d'événements onClick, onPointerOver et onPointerOut. Observez comment les hooks useState (pour les états hovered et active) sont utilisés pour stocker l'état de l'interaction, et comment cet état modifie directement les props du mesh (scale, color).

Ce que cet exemple démontre est au cœur de l'interactivité avec R3F :

  1. Déclarer un état : const [hovered, setHover] = useState(false) crée une variable d'état pour savoir si la souris survole l'objet.
  2. Mettre à jour l'état : Les callbacks onPointerOver={() => setHover(true)} et onPointerOut={() => setHover(false)} modifient cet état.
  3. Réagir au changement d'état : Les propriétés du mesh sont liées à cet état. Par exemple, <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} /> change la couleur de l'objet de manière conditionnelle.

C'est un flux de données unidirectionnel classique de React, mais appliqué à des objets 3D.


2. Explorer l'objet événement et sa propagation

Comme pour les événements du DOM, chaque gestionnaire d'événement dans R3F reçoit un objet événement (souvent nommé e ou event). Cet objet est une mine d'informations sur l'interaction qui vient de se produire.

Pour vous familiariser avec les données que vous pouvez extraire, la ressource suivante est une excellente référence.

r3f-fundamentals - LobeHub

Maintenant que nous savons comment intercepter un événement, voyons quelles informations il nous fournit. Le guide 'r3f-fundamentals' offre une excellente liste détaillée des propriétés de l'objet événement.

Dans la section 'Event Handling', examinez le code de l'exemple InteractiveBox. Focalisez-vous sur la partie à l'intérieur de onClick. L'auteur y liste en console.log de nombreuses propriétés utiles comme e.point (le point d'intersection exact dans l'espace 3D), e.distance (la distance à la caméra), e.object (l'objet THREE.js lui-même), etc. Lisez cette liste pour vous familiariser avec les données disponibles.

Parmi les propriétés les plus utiles, on trouve :

  • event.object : L'objet Three.js qui a été intersecté.
  • event.point : Un Vector3 représentant le point exact de l'intersection sur la surface de l'objet.
  • event.distance : La distance entre la caméra et le point d'intersection.
  • event.stopPropagation() : Une fonction pour arrêter la propagation de l'événement.

La propagation des événements (bubbling)

Ce dernier point, stopPropagation(), est crucial. En tant que développeur web, vous connaissez probablement le "bubbling" : un événement sur un élément enfant "remonte" vers ses parents. Dans R3F, le principe est identique mais appliqué à la hiérarchie de la scène. Si vous avez un <mesh> à l'intérieur d'un <group>, un clic sur le mesh déclenchera aussi l'événement onClick du groupe.

Il est souvent souhaitable d'empêcher ce comportement pour ne traiter l'événement que sur l'objet le plus proche.

r3f-fundamentals - LobeHub

Il est souvent nécessaire d'arrêter la propagation des événements pour éviter des interactions non désirées avec les objets parents dans la scène.

Lisez la courte section 'Event Propagation'. Elle montre un exemple très clair d'un mesh à l'intérieur d'un group, et comment e.stopPropagation() sur le mesh empêche l'événement onClick d'atteindre le groupe parent.


3. Atelier pratique : Créer un cube interactif

Mettons tout cela en pratique. Nous allons créer un composant InteractiveCube qui change de couleur au survol et qui affiche des informations dans la console lors d'un clic.

  1. Créez un nouveau composant InteractiveCube.js dans votre projet.
  2. Structurez le composant avec un état pour le survol et les gestionnaires d'événements.
import React, { useState } from 'react';
import { useFrame } from '@react-three/fiber';

function InteractiveCube(props) {
  // State pour gérer l'état de survol
  const [hovered, setHover] = useState(false);
  
  // State pour gérer l'état de clic
  const [active, setActive] = useState(false);

  return (
    <mesh
      {...props} // Applique les props passées (comme la position)
      scale={active ? 1.5 : 1} // Grossit le cube s'il est actif
      onClick={(event) => {
        // Arrête la propagation pour ne pas affecter d'autres objets
        event.stopPropagation();
        setActive(!active);
        console.log(`Objet cliqué : ${event.object.name}`);
        console.log(`Distance de la caméra : ${event.distance.toFixed(2)}`);
        console.log(`Point d'intersection :`, event.point);
      }}
      onPointerOver={(event) => {
        event.stopPropagation();
        setHover(true);
      }}
      onPointerOut={(event) => setHover(false)}
    >
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
    </mesh>
  );
}

export default InteractiveCube;
  1. Intégrez-le dans votre scène principale :
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
import InteractiveCube from './InteractiveCube';

function Scene() {
  return (
    <Canvas camera={{ position: [0, 0, 5] }}>
      <ambientLight intensity={0.5} />
      <spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
      
      <InteractiveCube position={[-1.5, 0, 0]} name="Cube Gauche" />
      <InteractiveCube position={[1.5, 0, 0]} name="Cube Droit" />

      <OrbitControls />
    </Canvas>
  );
}

Maintenant, lancez votre application. Vous devriez pouvoir survoler les cubes pour changer leur couleur, et cliquer dessus pour voir leur échelle changer et des informations s'afficher dans la console du navigateur.

Pour une démonstration plus dynamique de ces concepts dans un projet réel, la vidéo suivante est très instructive.

Build a 3D Book Slider Landing Page with Three.js & React

Pour voir ces concepts en action dans un projet concret, regardons un extrait de ce tutoriel. L'auteur ajoute de l'interactivité à des pages d'un livre 3D, ce qui illustre parfaitement l'utilisation combinée des états et des événements.

Regardez de 38:58 à 41:34. Observez comment l'auteur : Ajoute les gestionnaires onPointerEnter, onPointerLeave et onClick à un <group>. Utilise e.stopPropagation() pour isoler l'interaction. Gère un état highlighted avec useState. Introduit le hook useCursor de drei pour changer le curseur au survol (une excellente pratique pour l'expérience utilisateur !). Modifie une propriété de matériau (emissiveIntensity) pour créer un effet de surbrillance fluide.


Conclusion

Félicitations ! Vous venez de débloquer une dimension essentielle du développement 3D avec React : l'interactivité. Vous pouvez maintenant créer des expériences où l'utilisateur n'est plus un simple spectateur, mais un acteur dans la scène.

Points clés à retenir :

  • React Three Fiber expose des props d'événements (onClick, onPointerOver, etc.) directement sur les composants de mesh, de la même manière que React le fait pour les éléments du DOM.
  • Le hook useState est l'outil principal pour gérer les états d'interaction (survolé, cliqué, etc.).
  • Ces états peuvent être utilisés pour modifier conditionnellement n'importe quelle propriété de vos objets 3D (couleur, échelle, position...).
  • L'objet event fourni par les callbacks contient des informations précieuses sur l'interaction (point d'impact, distance, etc.).
  • event.stopPropagation() permet de contrôler la propagation des événements dans la hiérarchie de la scène, un concept familier du développement web.

Aperçu de la prochaine leçon :
Nous savons maintenant détecter les clics et les survols. Dans la prochaine leçon, nous irons plus loin en apprenant à piloter des animations ou des propriétés visuelles à partir de l'état global d'un composant React. Nous verrons comment un clic peut déclencher une animation complexe au lieu d'un simple changement de couleur, rendant nos scènes encore plus dynamiques et vivantes.