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 :
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...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 this.renderer.forceContextLoss() this.renderer.dispose();
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 :
classe BohrModel.js :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 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"; });
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 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); }; } }
Partager