diff --git a/cryptide_project/package-lock.json b/cryptide_project/package-lock.json
index 1a71877..90baa0c 100644
--- a/cryptide_project/package-lock.json
+++ b/cryptide_project/package-lock.json
@@ -20,6 +20,7 @@
"react-router-dom": "^6.18.0",
"react-scripts": "5.0.1",
"typescript": "^5.2.2",
+ "vis-network": "^9.1.9",
"web-vitals": "^2.1.4"
}
},
@@ -16827,6 +16828,23 @@
"node": ">= 0.8"
}
},
+ "node_modules/vis-network": {
+ "version": "9.1.9",
+ "resolved": "https://registry.npmjs.org/vis-network/-/vis-network-9.1.9.tgz",
+ "integrity": "sha512-Ft+hLBVyiLstVYSb69Q1OIQeh3FeUxHJn0WdFcq+BFPqs+Vq1ibMi2sb//cxgq1CP7PH4yOXnHxEH/B2VzpZYA==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/visjs"
+ },
+ "peerDependencies": {
+ "@egjs/hammerjs": "^2.0.0",
+ "component-emitter": "^1.3.0",
+ "keycharm": "^0.2.0 || ^0.3.0 || ^0.4.0",
+ "uuid": "^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
+ "vis-data": "^6.3.0 || ^7.0.0",
+ "vis-util": "^5.0.1"
+ }
+ },
"node_modules/w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
diff --git a/cryptide_project/package.json b/cryptide_project/package.json
index b5867f3..089abf8 100644
--- a/cryptide_project/package.json
+++ b/cryptide_project/package.json
@@ -14,6 +14,7 @@
"react-router-dom": "^6.18.0",
"react-scripts": "5.0.1",
"typescript": "^5.2.2",
+ "vis-network": "^9.1.9",
"web-vitals": "^2.1.4"
},
"scripts": {
diff --git a/cryptide_project/src/App.tsx b/cryptide_project/src/App.tsx
index a71ebf0..5299a83 100644
--- a/cryptide_project/src/App.tsx
+++ b/cryptide_project/src/App.tsx
@@ -9,6 +9,7 @@ import Login from './Pages/LoginForm';
import SignUp from './Pages/SignUpForm';
import Play from './Pages/Play';
import Lobby from './Pages/Lobby';
+import InGame from './Pages/InGame';
/* Component */
import AppNavbar from './Components/NavBar';
@@ -62,6 +63,7 @@ function App() {
} />
} />
} />
+ } />
diff --git a/cryptide_project/src/Components/GraphContainer.css b/cryptide_project/src/Components/GraphContainer.css
new file mode 100644
index 0000000..245cfc6
--- /dev/null
+++ b/cryptide_project/src/Components/GraphContainer.css
@@ -0,0 +1,10 @@
+#graph-container {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background-color: #f5f5f5;
+ padding: 20px;
+ box-sizing: border-box;
+}
\ No newline at end of file
diff --git a/cryptide_project/src/Components/GraphContainer.tsx b/cryptide_project/src/Components/GraphContainer.tsx
new file mode 100644
index 0000000..3e4d06f
--- /dev/null
+++ b/cryptide_project/src/Components/GraphContainer.tsx
@@ -0,0 +1,237 @@
+import React, { useEffect } from "react";
+import { DataSet, Network} from "vis-network/standalone/esm/vis-network";
+import "./GraphContainer.css";
+
+const NB_SPORTS = 3;
+const MIN_AGE = 20;
+const MAX_AGE = 100;
+const COLORS = ["blanc", "noir", "jaune", "chocolat"];
+const SPORTS = ["foot", "tennis", "rugby", "basket"];
+const NAMES = ["Fabien", "Mélyssa", "Kéké", "David", "Elisa", "Karina", "Fatima", "Pintrand", "Pif", "Nathan", "Thomas", "Carreau", "Léo", "Hélicoptère", "Tank"]
+
+class Person {
+ id: number = 0;
+ name: string;
+ age: number;
+ color: string;
+ sport: string[];
+ friends: Person[] = [];
+
+ constructor(name: string, age: number, color: string, sport: string[]) {
+ this.name = name;
+ this.age = age;
+ this.color = color;
+ this.sport = sport || [];
+ }
+
+ getAge() {
+ return this.age;
+ }
+
+ setAge(age: number) {
+ this.age = age;
+ }
+
+ addFriend(person: Person) {
+ // Si la personne n'est pas déjà dans la liste d'amis
+ // et qu'il a pas déjà 5 amis ou plus
+ // alors on l'ajoute
+ if (!this.friends.includes(person) && this.friends.length < 5 && person.friends.length < 5) {
+ this.friends.push(person);
+ person.addFriend(this);
+ }
+ }
+
+ getFriends() {
+ return this.friends;
+ }
+
+ equals(person: Person) {
+ return this.age === person.age &&
+ this.color === person.color &&
+ this.sportsEquals(person);
+ }
+
+ sportsEquals(person:Person) {
+ return this.sport.length === person.sport.length &&
+ this.sport.every(sport => person.sport.includes(sport));
+ }
+
+ toString() {
+ return `Person(id = ${this.id}, age=${this.age}, color=${this.color}, sport=${this.sport}, friends=${this.friends.length})`;
+ }
+}
+
+// Génère un élément aléatoire d'un tableau
+function getRandomElement(array: any[]) {
+ return array[Math.floor(Math.random() * array.length)];
+}
+
+// Génère un nombre aléatoire entre min et max
+function getRandomNumber(min: number, max: number) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+// Génère une personne avec un age, une couleur et une liste de sports
+function generatePerson(possibleNames: string[], possibleSports: string[], existingPeople: Person[]) {
+ // Génère un age entre 20 et 100 ans
+ const age = getRandomNumber(MIN_AGE, MAX_AGE);
+ const color = getRandomElement(COLORS);
+ const sports = [];
+ let name = "";
+
+ // Génère un nombre de sports entre 1 et NB_SPORTS
+ const nbSports = getRandomNumber(1, NB_SPORTS);
+
+ for (let i = 0; i < nbSports; i++) {
+ // Gestion des sports
+ // Si il n'y a plus de sports possibles, on reprend la liste de base
+ if (possibleSports.length === 0) {
+ possibleSports = SPORTS.slice();
+ }
+
+ // Génère un sport aléatoire
+ // Si le sport est déjà dans la liste, on recommence
+ const sport = getRandomElement(possibleSports);
+ if (sports.indexOf(sport) === -1) {
+ possibleSports.splice(possibleSports.indexOf(sport), 1);
+ sports.push(sport);
+ } else {
+ i--;
+ }
+
+ // Gestion des prénoms
+ // Si il n'y a plus de prénoms possibles, on reprend la liste de base
+ if (possibleNames.length === 0) {
+ possibleNames = NAMES.slice();
+ }
+
+ // Génère un prénom aléatoire et le supprime de la liste de prénom disponible
+ name = getRandomElement(possibleNames);
+ possibleNames.splice(possibleNames.indexOf(name), 1);
+ }
+
+ const newPerson = new Person(name, age, color, sports);
+
+ // Vérifie si la personne n'est pas déjà dans la liste
+ // Si déjà dans la liste, on recommence
+ // if (existingPeople.some(person => person.equals(newPerson))) {
+ // return generatePerson(possibleSports, existingPeople);
+ // }
+
+ return newPerson;
+}
+
+function generatePeople(nbPeople: number) {
+ const people = [];
+ let possibleSports = SPORTS.slice();
+ let possibleNames = NAMES.slice();
+
+ for (let i = 0; i < nbPeople; i++) {
+ const person = generatePerson(possibleNames, possibleSports, people);
+ person.id += i;
+ people.push(person);
+ }
+
+ return people;
+}
+
+// Ajouter des amis aléatoirement entre une liste de personnes
+function addFriends(people: Person[]) {
+ people.forEach(person => {
+ // const nbFriends = getRandomNumber(0, people.length - 1);
+ const nbFriends = getRandomNumber(1, 5);
+
+
+ for (let i = 0; i < nbFriends; i++) {
+ let friend = getRandomElement(people);
+
+ // S'assurer que l'ami généré aléatoirement est différent de la personne
+ while (friend === person) {
+ friend = getRandomElement(people);
+ }
+
+ person.addFriend(friend);
+ }
+ });
+}
+
+const people = generatePeople(40);
+addFriends(people);
+
+const MyGraphComponent = () => {
+ useEffect(() => {
+ const container = document.getElementById('graph-container');
+ if (!container) {
+ console.error("Container not found");
+ return;
+ }
+
+ // Création du réseau
+ const persons: any[] = [];
+ const edges: any[] = [];
+ people.forEach(person => {
+ const visPerson = {id: person.id, label: person.name};
+ persons.push(visPerson);
+ person.friends.forEach(friend => {
+ // Eviter le double sens des relations
+ if (edges.some(edge => edge.from === friend.id && edge.to === person.id || edge.from === person.id && edge.to === friend.id)) {
+ return;
+ }
+ edges.push({from: person.id, to: friend.id});
+ });
+ });
+ // Charger les données dans le graph
+ const nodes = new DataSet(persons);
+
+ // Configuration des options du Graphe
+ const initialOptions = {
+ nodes: {
+ shape: 'circle',
+ size: 30,
+ font: {
+ size: 20
+ },
+ },
+ layout: {
+ improvedLayout: true,
+ hierarchical: {
+ enabled: false,
+ direction: 'LR', // LR (Left to Right) ou autre selon votre préférence
+ sortMethod: 'hubsize'
+ }
+ },
+ physics: {
+ enabled: true,
+ barnesHut: {
+ gravitationalConstant: -1000,
+ springConstant: 0.001,
+ springLength: 100
+ }
+ }
+ };
+
+ const networkData = { nodes: nodes, edges: edges };
+ const network = new Network(container, networkData, initialOptions);
+
+ // Gérer le changement entre la physique et le déplacement manuel
+ let physicsEnabled = true;
+
+ network.on("dragging", (params) => {
+ if (params.nodes.length > 0) {
+ // Un nœud a été cliqué
+ initialOptions.physics.enabled = false;
+ network.setOptions(initialOptions);
+ }
+ });
+
+ }, []); // Le tableau vide signifie que cela ne s'exécutera qu'une fois après le premier rendu
+
+ return (
+ <>
+
+ >
+ );
+};
+
+export default MyGraphComponent;
\ No newline at end of file
diff --git a/cryptide_project/src/Pages/InGame.css b/cryptide_project/src/Pages/InGame.css
new file mode 100644
index 0000000..e69de29
diff --git a/cryptide_project/src/Pages/InGame.tsx b/cryptide_project/src/Pages/InGame.tsx
new file mode 100644
index 0000000..6a4a32b
--- /dev/null
+++ b/cryptide_project/src/Pages/InGame.tsx
@@ -0,0 +1,8 @@
+import React from "react";
+import GraphContainer from "../Components/GraphContainer";
+
+export default function InGame() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/cryptide_project/src/Pages/Lobby.tsx b/cryptide_project/src/Pages/Lobby.tsx
index 9b45c6a..38a59e0 100644
--- a/cryptide_project/src/Pages/Lobby.tsx
+++ b/cryptide_project/src/Pages/Lobby.tsx
@@ -39,7 +39,7 @@ function Lobby() {
}
- {/* page de baptiste ici */}
+ {/* page de baptiste ici */}
diff --git a/cryptide_project/src/Services/GraphCreation.tsx b/cryptide_project/src/Services/GraphCreation.tsx
new file mode 100644
index 0000000..77be46c
--- /dev/null
+++ b/cryptide_project/src/Services/GraphCreation.tsx
@@ -0,0 +1,36 @@
+import {
+ Network,
+ Options,
+ Data,
+ Edge,
+ Node
+} from "vis-network/standalone/esm/vis-network";
+import React, { useState, useLayoutEffect, useRef } from "react";
+
+export interface UseVisNetworkOptions {
+ options: Options;
+ nodes: Node[];
+ edges: Edge[];
+}
+
+export default (props: UseVisNetworkOptions) => {
+ const { edges, nodes, options } = props;
+
+ const [network, addNetwork] = useState(null);
+ const ref = useRef(null);
+
+ const data: Data = { nodes, edges };
+
+ useLayoutEffect(() => {
+ if (ref.current) {
+ const instance = new Network(ref.current, data, options);
+ addNetwork(instance);
+ }
+ return () => network?.destroy();
+ }, []);
+
+ return {
+ network,
+ ref
+ };
+};