Bonjour à tous,

Je m'arrache les cheveux depuis plusieurs jours concernant la mise à jour d'un objet canvas avec THREEJS :

Il s'agît d'une représentation 3d du modèle Bohr des atomes, après l'appui sur un bouton de la table périodique d'un élément s'ouvre une modale représentant l'atome et ses électrons gravitant autour du noyau en 3d...

Tout fonctionne bien au niveau de la représentation et rendering sauf que la scene ne s'actualise pas sauf en rafraichissant manuellement la page !

J'ai tout essayé : placer l'init de ma classe dans l'eventListener de la modale, ne créer l'objet 'BohrModel' qu'à ce moment là, rien n'y fait...
Soit la scene ne s'actualise pas complétement, soit plusieurs instances de celle-ci se rajoutent au fur et à mesure dans la modale...

J'ai tenté aussi :

  this.renderer.forceContextLoss()
   this.renderer.dispose();

Je pensais qu'il existait un moyen de réinitialiser l'objet à chaque fois que la modale ou l'action d'un bouton était demandé mais apparemment la scène le canvas et le render persistent en mémoire...

Je vois dans les forum énormément de questions du même ordre qui ne sont même pas répondues ...

Quelle serait la bonne méthode svp ?

Modale :

app.js :

import { Atoms } from "./Atoms.js";
import { BohrModel } from "./BohrModel.js";
const bohrModel = new BohrModel();
console.log(window.screen.width)
const btnClose = document.querySelector(".btn-close");
const modaleAtome = document.querySelector(".modale__atome");
const btnAjouter = document.querySelector(".btn__ajouter");
const cardAtome = document.querySelector(".card__atome");
const atomSymbol = document.querySelector(".atom__symbol");
const nomAtome = document.querySelector(".nom__atome");
const qteAtome = document.querySelector(".qte__atome");
const atoms = new Atoms();

//Afficher la liste de boutons pour chaque atome en asynchrone
await atoms.getAtomsList();

const atomsButtons = document.querySelectorAll(".btn__atome");
//Ecouteur sur le bouton d'atomes

atomsButtons.forEach((btn) => {
  btn.addEventListener("click", (e) => {
    showAtomModal(e);
  });
});
//Affiche la modale de l'atome choisi
const showAtomModal = (e) => {
  modaleAtome.style.display = "flex";

  nomAtome.innerHTML = "";
  nomAtome.innerText = e.currentTarget.dataset.atomName;
  atomSymbol.innerText = e.currentTarget.dataset.atomSymbol;

  bohrModel.init();
  let electronsLayers = "";
  electronsLayers = e.currentTarget.dataset.electronConfiguration;

  //Extrait la configuration électronique de l'atome actif
  let atomConfig = atoms.getElectronConfig(electronsLayers);
  console.log("tbl config = ", atomConfig);

  //Calcul du nombre d'orbites représentant les couches électroniques
  let atomOrbits = 0;
  atomOrbits = atomConfig.length;
  console.log("orbits =", atomOrbits);

  //Crée les orbites pour l'atome actif
  bohrModel.createOrbits(atomOrbits);
  //Crée le noyau de l'atome actif

  //Place les electrons sur les orbites
  for (let i = 0; i < atomConfig.length; i++) {
    bohrModel.placeElectrons(atomConfig[i], i + 1);
    console.log(`orbite ${i + 1} nbrElectrons =${atomConfig[i]}`);
  }
};

//Traitement bouton ajouter
btnAjouter.addEventListener("click", () => {
  modaleAtome.style.display = "none";
});
//Traitement incrémentation clavier
document.addEventListener("keyup", (e) => {
  let keyName = e.key;
  console.log("control cliqué");
  if (keyName === "+" && this.qteAtome.value >= 1) {
    this.qteAtome.value++;
  }
  if (keyName === "-" && this.qteAtome.value > 1) {
    this.qteAtome.value--;
  }
});

//Fermeture modale atome
btnClose.addEventListener("click", () => {
  modaleAtome.style.display = "none";
});

classe BohrModel.js :

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

export class BohrModel {
  constructor() {
    //Données et distance de séparation par rapport au nucleus
    this.distFromNucleus = 1;
    this.orbits = [];   
  }

  init() {
    if (this.canvas) {
      this.canvas="";
    }
    if (this.renderer) {
      this.renderer.forceContextLoss()
      this.renderer.dispose();
    }
    // if (this.scene) {
    //   this.scene='';
    // }

    this.createCanvas();
    this.createScene();
    this.createRenderer();
    this.createCamera();
    this.createSpot();
    this.createNucleus();
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.light = new THREE.DirectionalLight(0xffffff);
    this.scene.add(this.light);
    this.createAnimations();
    this.animate();
  }

  createCanvas() {
    //Données canvas
    this.canvas = document.querySelector("#bohr-model");
    this.canvasWidth = 200;
    this.canvasHeight = 200;
  }

  createScene() {
    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color("lightsmoke");
  }
  createCamera() {
    this.camera = new THREE.PerspectiveCamera(
      75,
      this.canvasWidth / this.canvasHeight,
      0.1,
      1000
    );
    this.camera.position.z = 15;
  }
  createRenderer() {
    this.renderer = new THREE.WebGLRenderer({
      antialias: true,
    });
    this.renderer.setSize(this.canvasWidth, this.canvasHeight);
    this.renderer.setClearColor(0x000, 1.0);
    this.canvas.appendChild(this.renderer.domElement);
  }
  createSpot() {
    const spot1 = new THREE.SpotLight(0xffffff);
    spot1.position.set(100, 100, 150);
    this.scene.add(spot1);
  }
  createNucleus() {
    this.nucleusRadius = 1;
    this.nucleusGeo = new THREE.SphereGeometry(this.nucleusRadius, 32, 32);
    this.nucleusMat = new THREE.MeshPhongMaterial({ color: "lightblue" });
    this.nucleus = new THREE.Mesh(this.nucleusGeo, this.nucleusMat);
    this.scene.add(this.nucleus);
  }

  //Création de chaque orbite représentant les couches électroniques
  createOrbits(nbrOrbits) {
    //On retire de la scène tous les éléments (orbits) anciens
    if (this.orbits.length > 0) {
      for (let i = 0; i < this.orbits.length; i++) {
        this.scene.remove(this.orbits[i]);
      }
    }

    this.innerOrbitRadius = this.nucleusRadius + this.distFromNucleus;
    this.outerOrbitRadius = this.innerOrbitRadius + 0.02;

    const orbitMat = new THREE.MeshBasicMaterial({
      color: "lightgray",
      side: THREE.DoubleSide,
    });

    for (let i = 0; i < nbrOrbits; i++) {
      const orbitGeo = new THREE.RingGeometry(
        this.innerOrbitRadius,
        this.outerOrbitRadius,
        50
      );
      this.orbits[i] = new THREE.Mesh(orbitGeo, orbitMat);

      this.orbits.push(this.orbits[i]);
      this.scene.add(this.orbits[i]);

      this.innerOrbitRadius++;
      this.outerOrbitRadius++;
    }
    return this.orbits;
  }

  //calcul des positions et placement d'électrons sur une orbite:
  placeElectrons(nbrElectrons, targetedOrbit) {
    const maxRadius = targetedOrbit + 1;
    const sphereGeo = new THREE.SphereGeometry(0.2, 16, 16);
    let sphereMat = new THREE.MeshPhongMaterial({ color: "white" });

    for (let i = 0; i < nbrElectrons + 1; i++) {
      if (this.orbits.length - 1 === targetedOrbit) {
        sphereMat = new THREE.MeshPhongMaterial({ color: "red" });
      }
      const sphere = new THREE.Mesh(sphereGeo, sphereMat);
      //Calculs répartition des sphères sur orbites par angles
      const angle = i * ((2 * Math.PI) / nbrElectrons);
      const x = maxRadius * Math.cos(angle);
      const y = maxRadius * Math.sin(angle);

      sphere.position.x = x;
      sphere.position.y = y;
      this.orbits[targetedOrbit].add(sphere);
    }
  }
  createAnimations() {
    this.animate = () => {
      this.nucleus.rotateY(0.004);
      for (let i = 0; i < this.orbits.length; i++) {
        this.orbits[i].rotation.z += -0.001;
      }
      this.controls.update();
      this.renderer.render(this.scene, this.camera);
      requestAnimationFrame(this.animate);
    };
  }
}

Aucune réponse