diff --git a/include/js/charts.js b/include/js/charts.js new file mode 100644 index 0000000000000000000000000000000000000000..5db45da7b00efcd69a4370dcb9dda744225f3280 --- /dev/null +++ b/include/js/charts.js @@ -0,0 +1,56 @@ +/** + * Requête AJAX pour obtenir une information du serveur et l'utiliser pour faire deux graphiques. + * Il faut déclarer la requête et lui dire de faire les graphiques dès qu'on reçoit le résultat. + */ +const httpRequest = new XMLHttpRequest() // 1. Déclaration de la requête +httpRequest.onreadystatechange = () => { // 2. Définition de ce qu'il faut faire quand on obtient une réponse + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status === 200) { + // On a reçu la réponse du serveur, on peut générer la graphique + const response = JSON.parse(httpRequest.responseText) + google.charts.load("current", { "packages": ["corechart"], "language": "fr" }) + google.charts.setOnLoadCallback(function() { + drawChart(response) + }) + } else { + console.log("Erreur de connexion au serveur !") + } + } +} +httpRequest.open('POST', 'include/php/data.php', true) // 3. Ouverture et configuration de la requête +httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') +// Requête SQL +const query = "SELECT acad_mies, sum(capa_fin) AS places FROM parcoursup GROUP BY acad_mies ORDER BY places DESC" +httpRequest.send(`query=${encodeURIComponent(query)}`) // 4. Envoi de la requête + + +/** + * Fonction qui fait deux graphiques avec les données du serveur + */ +function drawChart(result) { + // Données de la graphique + let data = new google.visualization.DataTable() + data.addColumn('string', 'Académie') + data.addColumn('number', 'Places') + // Utiliser les données du serveur + let dataArray = [] + for (const item of result) { + dataArray.push([item.acad_mies, Number(item.places)]) + } + data.addRows(dataArray) + + let piechart_options = { + title: "Pie Chart : Nombre de places dans chaque académie", + height: 600 + } + let piechart = new google.visualization.PieChart(document.getElementById('piechart_div')) + piechart.draw(data, piechart_options) + + let barchart_options = { + title: "Barchart : Nombre de places dans chaque académie", + height: 600, + legend: 'none' + } + let barchart = new google.visualization.BarChart(document.getElementById('barchart_div')) + barchart.draw(data, barchart_options) +} \ No newline at end of file diff --git a/include/js/geochart.js b/include/js/geochart.js new file mode 100644 index 0000000000000000000000000000000000000000..d985945ec5d29e86c3c2f821eb29f5378eed5729 --- /dev/null +++ b/include/js/geochart.js @@ -0,0 +1,74 @@ +/** + * Fonction pour transformer le nom d'une region + * dans un objet JavaScript que Google Charts comprend. + */ +function formatter_region(region) { + const codes = { + "Ile-de-France": 'FR-IDF', + "Auvergne-Rhône-Alpes": 'FR-ARA', + "Grand Est": 'FR-GES', + "Occitanie": 'FR-OCC', + "Nouvelle-Aquitaine": 'FR-NAQ', + "Hauts-de-France": 'FR-HDF', + "Normandie": 'FR-NOR', + "Provence Alpes Côte d'Azur": 'FR-PAC', + "Bretagne": 'FR-BRE', + "Bourgogne-Franche-Comté": 'FR-BFC', + "Pays de la Loire": 'FR-PDL', + "Centre-Val de Loire": 'FR-CVL', + "La Réunion": 'FR-974', + "Corse": 'FR-20R', + "Guadeloupe": 'FR-971', + "Guyane": 'FR-973', + "Polynésie française": 'FR-PF', + "Martinique": 'FR-972', + } + return {v: codes[region], f: region} +} + + +const httpRequest = new XMLHttpRequest() +httpRequest.onreadystatechange = () => { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status === 200) { + const response = JSON.parse(httpRequest.responseText) + google.charts.load("current", { "packages": ["geochart"], "language": "fr" }) + google.charts.setOnLoadCallback(function() { + drawChart(response) + }) + } else { + console.log("Erreur de connexion au serveur !") + } + } +} +httpRequest.open('POST', 'include/php/data.php', true) +httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') +const query = 'SELECT region_etab_aff, count(*) AS count FROM parcoursup WHERE fili = "BUT" GROUP BY region_etab_aff ORDER BY count DESC' +httpRequest.send(`query=${encodeURIComponent(query)}`) // 4. Envoi de la requête + + +/** + * Fonction qui fait un geochart avec les régions de la France + */ +function drawChart(result) { + let data = new google.visualization.DataTable() + data.addColumn("string", "Région") + data.addColumn("number", "Nombre des BUT") + let dataArray = [] + for (const item of result) { + dataArray.push([formatter_region(item.region_etab_aff), item.count]) + } + data.addRows(dataArray) + + let options = { + width: 600, + height: 500, + displayMode: 'regions', + region: 'FR', + resolution: 'provinces', + geochartVersion: 11, + } + + let chart = new google.visualization.GeoChart(document.getElementById("geochart_div")) + chart.draw(data, options) +} \ No newline at end of file diff --git a/include/php/data.php b/include/php/data.php new file mode 100644 index 0000000000000000000000000000000000000000..43bd6c653fc817d72309755048680f80b1cb1a85 --- /dev/null +++ b/include/php/data.php @@ -0,0 +1,13 @@ +<?php +// Cette page reçoit une requête SQL par la méthode POST +// On se connecte à la base de données pour faire cette requête et affiche le résultat +// en format JSON. +// Cette page sert à faire une requête AJAX avec JavaScript. +require_once 'functions.php'; +$query = $_POST['query']; +$dbh = db_connection(); +$sth = $dbh->prepare($query); +$sth->execute(); +$results = $sth->fetchAll(PDO::FETCH_OBJ); +echo json_encode($results); +?> \ No newline at end of file diff --git a/include/php/functions.php b/include/php/functions.php new file mode 100644 index 0000000000000000000000000000000000000000..5db2e05fb45954e7ca0cbc4c584d28a2493b27ea --- /dev/null +++ b/include/php/functions.php @@ -0,0 +1,44 @@ +<?php + +/** + * Coordonnées de connexion à la base de données en local + */ +const db_local = [ + 'dbname' => 'sae303', + 'user' => 'root', + 'pwd' => '' // 'root' pour MAMP +]; + +/** + * Coordonnées de connexion à la base de données sur un serveur + */ +const db_serveur = [ + 'dbname' => 'a21000000', // remplacer par votre identifiant + 'user' => 'a21000000', // remplacer par votre identifiant + 'pwd' => 'secret' +]; + +/** + * Connexion à la base de données + * + * Mettre la variable $local à true si le site web est déployé en local (avec XAMPP), + * ou false s'il est déployé sur un serveur web. + */ +function db_connection() { + $local = true; + if ($local) { + $dbh = new PDO( + 'mysql:host=localhost;dbname=' . db_local['dbname'] . ';charset=utf8', + db_local['user'], + db_local['pwd'] + ); + } else { + $dbh = new PDO( + 'mysql:host=localhost;dbname=' . db_serveur['dbname'] . ';charset=utf8', + db_serveur['user'], + db_serveur['pwd'] + ); + } + return $dbh; +} +?> \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000000000000000000000000000000000000..3c6485cc7a37cfe5dbef273f3ad47b0500408bda --- /dev/null +++ b/index.php @@ -0,0 +1,80 @@ +<?php +/** + * Différents exemples de requêtes SQL + */ +include 'include/php/functions.php'; +?> +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="utf-8"> + <title>SAÉ 303</title> +</head> +<body> + <h1>SAÉ 303</h1> + <p> + Concevoir des visualisations de données pour le web et un support animé. + </p> + <p> + Voici quelques exemples d'utilisation de la base de données. + </p> + <p> + Aussi, vous trouverez + </p> + <ul> + <li><a href="test-charts.html">un exemple</a> avec deux graphiques utilisant Google Charts</li> + <li><a href="regions.html">un exemple</a> avec une graphique avec les régions de l'Hexagone</li> + <li><a href="search.php">un exemple</a> avec une barre de recherche</li> + </ul> + + <section> + <h2>Les BUT avec le plus grand nombre de candidats</h2> + <ol> +<?php +$dbh = db_connection(); +$sth = $dbh->prepare('SELECT lib_comp_voe_ins, voe_tot FROM parcoursup + WHERE fili = "BUT" + ORDER BY voe_tot DESC LIMIT 5'); +$sth->execute(); +$result = $sth->fetchAll(); +foreach ($result as $row) { + echo '<li>' . $row['lib_comp_voe_ins'] . ' (<em>' . $row['voe_tot'] . ' candidats</em>)</li>'; +} +?> + </ol> + </section> + + <section> + <h2>Les villes avec le plus de BTS</h2> + <ol> +<?php +$sth = $dbh->prepare('SELECT ville_etab, count(*) AS count FROM parcoursup + WHERE fili = "BTS" + GROUP BY ville_etab + ORDER BY count DESC LIMIT 5'); +$sth->execute(); +$result = $sth->fetchAll(); +foreach ($result as $row) { + echo '<li>' . $row['ville_etab'] . ' (<em>' . $row['count'] . ' BTS</em>)</li>'; +} +?> + </ol> + </section> + + <section> + <h2>Les BUT Informatique avec le plus grand nombre de candidates admises</h2> + <ol> +<?php +$sth = $dbh->prepare('SELECT lib_comp_voe_ins, acc_tot_f, acc_tot FROM parcoursup + WHERE lib_for_voe_ins LIKE "BUT - Informatique%" + ORDER BY acc_tot_f DESC LIMIT 5'); +$sth->execute(); +$result = $sth->fetchAll(); +foreach ($result as $row) { + echo '<li>' . $row['lib_comp_voe_ins'] . ' (<em>' . $row['acc_tot_f'] . ' étudiantes sur ' . $row['acc_tot'] . '</em>)</li>'; +} +?> + </ol> + </section> +</body> +</html> \ No newline at end of file diff --git a/search.php b/search.php new file mode 100644 index 0000000000000000000000000000000000000000..50b582a0e491710acf92b3251a96b4b4ebb57aa9 --- /dev/null +++ b/search.php @@ -0,0 +1,63 @@ +<?php +/** + * Barre de recherche de formations avec affichage d'informations + * + * L'utilisateur choisit une formation dans le formulaire. + * Le formulaire envoie cette information vers la même page, et on + * affiche le nombre de places et de candidats. + */ +include 'include/php/functions.php'; +?> +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="utf-8"> + <title>SAÉ 303</title> +</head> +<body> + <h1>SAÉ 303</h1> + + <form method="get" action="search.php"> + <label> + Choisis une formation : + <input list="formations" name="formation" style="width: 400px"> + </label> + <datalist id="formations"> +<?php +// On remplit l'élément datalist (les suggestions pour le formulaire) avec les noms des formations +$dbh = db_connection(); +$sth = $dbh->prepare('SELECT lib_comp_voe_ins FROM parcoursup + ORDER BY lib_comp_voe_ins ASC'); +$sth->execute(); +$result = $sth->fetchAll(); +foreach ($result as $row) { + echo '<option value="' . $row['lib_comp_voe_ins'] . '">'; +} +?> + </datalist> + <input type="submit" value="Confirmer"> + </form> + +<?php +// Si $_GET['formation'] est défini, ça veut dire qu'on est arrivé dans cette page +// après avoir sélectionné une formation. Dans ce cas, on affiche les informations +// de cette formation +if (isset($_GET['formation'])) { + $sth = $dbh->prepare('SELECT capa_fin, voe_tot FROM parcoursup + WHERE lib_comp_voe_ins = :formation'); + $donnees = [ + "formation" => $_GET['formation'] + ]; + $sth->execute($donnees); + $result = $sth->fetchAll(); + if (count($result) == 1) { + // Si on obtient un résultat, on affiche les informations + echo "<h2>" . $_GET['formation'] . "</h2>"; + echo "<p>" . $result[0]['voe_tot'] . " candidats pour " . $result[0]['capa_fin'] . " places</p>"; + } +} else { + echo "<p>Veuillez choisir une formation</p>"; +} +?> +</body> +</html> \ No newline at end of file diff --git a/test-charts.html b/test-charts.html new file mode 100644 index 0000000000000000000000000000000000000000..1d940ff45caea7871b2876292453b04abd1dd7f4 --- /dev/null +++ b/test-charts.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> + <title>SAÉ 303</title> +</head> +<body> + <div class="container"> + <div class="row"> + <div class="col-12 col-lg-6"> + <div id="piechart_div"></div> + </div> + <div class="col-12 col-lg-6"> + <div id="barchart_div"></div> + </div> + </div> + </div> + + <script src="https://www.gstatic.com/charts/loader.js"></script> + <script src="include/js/charts.js" defer></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script> +</body> +</html> \ No newline at end of file