123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- <form action="/" method="post">
- <input type="hidden" name="page" value="menu">
- <button class="btn btn-primary mb-4">
- <i class="fas fa-arrow-left"></i> Regresar
- </button>
- </form>
- <main class="container" @vue:mounted="mounted">
- <fieldset class="mb-4">
- <legend v-if="alumno_y_clave">
- {{ alumno_y_clave }}
- </legend>
- <legend v-else>
- Gráficos
- </legend>
- <form>
- <div class="row mb-3 form-box">
- <label for="alumno.grupo" class="col-sm-1 col-form-label form-group barra">Grupo</label>
- <div class="col-sm-10">
- <select name="alumno.grupo" id="alumno.grupo" class="form-control col-form-label"
- v-model="filter.grupo">
- <option :value="null">Todos los grupos</option>
- <option v-for="alumno in alumnos.filter(alumno => alumno.grupo)" :value="alumno.grupo">
- {{ alumno.grupo }}
- </option>
- </select>
- </div>
- </div>
- <div class="row mb-3 form-box">
- <label for="alumno" class="col-sm-1 col-form-label form-group barra">Alumno</label>
- <div class="col-sm-10">
- <input type="item.type" name="item.name" list="item.name" id="alumno"
- class="form-control col-form-label" @input="fetchDatos" v-model="filter.username"
- placeholder="Nombre o clave del alumno">
- <datalist id="item.name">
- <option v-for="alumno in alumnos_por_grupo" :value="alumno.username">
- {{ alumno.nombre }}
- </option>
- </datalist>
- </div>
- </div>
- <!-- <button type="reset" class="btn btn-danger btn-sm">
- <i class="fas fa-eraser"></i>
- </button> -->
- </form>
- </fieldset>
- <section v-if="datos != null">
- <h2>Gráficos</h2>
- <div class="row d-flex justify-content-center">
- <div class="col-md-8">
- <div id="snapshot" width="400" height="400" @vue:mounted="createMultiLineGraph($el, datos.snapshots)">
- </div>
- </div>
- <div class="col-md-8">
- <div id="calificaciones" width="400" height="400" @vue:mounted="createGraph($el,
- datos.calificaciones.map(calificacion => calificacion.course_name),
- datos.calificaciones.map(calificacion => calificacion.calificación_final))">
- </div>
- </div>
- </div>
- </section>
- </main>
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
- <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
- <script>
- const filter = PetiteVue.reactive({
- grupo: null,
- username: null,
- });
- const graph = PetiteVue.reactive({
- calificaciones: null,
- snapshot: null,
- })
- PetiteVue.createApp({
- store,
- filter,
- graph,
- alumnos: [], // schema: { grupo: string, alumnos: Array<{ nombre: string, username: string }> }
- get alumnos_por_grupo() { // returns Array<{ nombre: string, username: string }>
- if (this.filter.grupo)
- return this.alumnos.find(alumno => alumno.grupo === this.filter.grupo).alumnos;
- return this.alumnos.flatMap(alumno => alumno.alumnos);
- },
- get alumno_y_clave() { // returns string: (username) nombre
- if (this.filter.username == null) return null;
- const alumno = this.alumnos_por_grupo.find(alumno => alumno.username === this.filter.username);
- return alumno ? `(${alumno.username}) ${alumno.nombre}` : null;
- },
- datos: null,
- async mounted() {
- store.loading = true;
- const response = await fetch('fetch/alumnos.php');
- const data = await response.json();
- this.alumnos = data;
- store.loading = false;
- },
- createGraph($el, labels, data) {
- const colors = [
- 'rgba(54, 162, 235, 0.7)', // Blue
- 'rgba(255, 99, 132, 0.7)', // Red
- 'rgba(255, 159, 64, 0.7)', // Orange
- 'rgba(255, 206, 86, 0.7)', // Yellow
- 'rgba(75, 192, 192, 0.7)', // Green
- 'rgba(153, 102, 255, 0.7)', // Purple
- 'rgba(201, 203, 207, 0.7)', // Gray
- ];
- const series = data.map((datum, index) => ({
- name: labels[index], // Assuming each label corresponds to a course
- data: datum,
- colors: colors[i],
- }));
- console.log(series);
- const options = {
- series: [{data, labels, colors}],
- chart: {
- type: 'bar',
- height: 350
- },
- plotOptions: {
- bar: {
- borderRadius: 4,
- // horizontal: true, // Uncomment or comment based on desired orientation
- }
- },
- dataLabels: {
- enabled: false
- },
- xaxis: {
- categories: labels,
- },
- yaxis: {
- min: 0,
- max: 1, // Ensures y-axis scales to a max of 1
- tickAmount: 5, // Optional: Adjusts the number of ticks on the y-axis
- },
- };
- var chart = new ApexCharts($el, options);
- chart.render();
- },
- createMultiLineGraph($el, snapshots) {
- const labels = snapshots.map(snapshot => snapshot.fecha);
- const series = snapshots[0].calificaciones.map(calificacion => {
- return {
- name: calificacion.course_name,
- data: snapshots.map(snapshot => snapshot.calificaciones.find(c => c.course_name === calificacion.course_name).calificación_final)
- };
- });
- const options = {
- chart: {
- type: 'line',
- height: 'auto'
- },
- series: series,
- xaxis: {
- categories: labels
- },
- yaxis: {
- min: 0,
- max: 1, // Assuming scores are normalized between 0 and 1
- tickAmount: 5, // Adjust tick amount as needed
- labels: {
- formatter: function (val) {
- return val.toFixed(2); // Adjust the number of decimal places as needed
- }
- }
- },
- title: {
- text: 'Calificaciones por Materia a lo largo del Tiempo',
- align: 'center'
- },
- stroke: {
- width: 2, // Line thickness
- curve: 'smooth' // 'straight' or 'smooth'
- },
- fill: {
- opacity: 1,
- },
- tooltip: {
- y: {
- formatter: function (val) {
- return val.toFixed(2); // Adjust the number of decimal places as needed
- }
- }
- }
- };
- var chart = new ApexCharts($el, options);
- chart.render();
- },
- async fetchDatos() {
- if (this.filter.username == null) return;
- if (this.alumnos_por_grupo.find(alumno => alumno.username === this.filter.username) == null) return;
- store.loading = true;
- this.datos = null;
- // params POST (formadata [username])
- const params = new FormData();
- params.append('username', this.filter.username);
- const response = await fetch('fetch/calificaciones.php', {
- method: 'POST',
- body: params,
- });
- const data = await response.json();
- this.datos = data;
- store.loading = false;
- /* this.createGraph(); */
- }
- }).mount()
- </script>
|