parent
01369648c9
commit
3b9d8f7d4d
@ -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;
|
||||||
|
}
|
@ -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 (
|
||||||
|
<>
|
||||||
|
<div id="graph-container"/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MyGraphComponent;
|
@ -0,0 +1,8 @@
|
|||||||
|
import React from "react";
|
||||||
|
import GraphContainer from "../Components/GraphContainer";
|
||||||
|
|
||||||
|
export default function InGame() {
|
||||||
|
return (
|
||||||
|
<GraphContainer />
|
||||||
|
);
|
||||||
|
}
|
@ -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<Network | null>(null);
|
||||||
|
const ref = useRef<HTMLDivElement>(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
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in new issue