Agrega Graficos

develop/Ronald
Ronald Morales 2024-04-22 22:50:48 -04:00
parent cc109373b3
commit a2687861a2
7 changed files with 327 additions and 19 deletions

35
package-lock.json generated
View File

@ -11,6 +11,8 @@
"@adminkit/core": "^3.4.0",
"bootstrap": "^5.3.0",
"bootstrap-icons": "^1.10.5",
"chart.js": "^3.9.1",
"chartjs-plugin-datalabels": "^2.2.0",
"history": "^5.3.0",
"svelte-navigator": "^3.2.2",
"svelte-pagination": "^0.0.1",
@ -37,6 +39,15 @@
"simplebar": "5.3.9"
}
},
"node_modules/@adminkit/core/node_modules/chart.js": {
"version": "2.9.4",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz",
"integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==",
"dependencies": {
"chartjs-color": "^2.1.0",
"moment": "^2.10.2"
}
},
"node_modules/@babel/polyfill": {
"version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz",
@ -508,13 +519,9 @@
"integrity": "sha512-ceOhN1DL7Y4O6M0j9ICgmTYziV89WMd96SvSl0REd8PMgrY0B/WBOPoed5S1KUmJqXgUXh8gzSe6E3ae27upsQ=="
},
"node_modules/chart.js": {
"version": "2.9.4",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz",
"integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==",
"dependencies": {
"chartjs-color": "^2.1.0",
"moment": "^2.10.2"
}
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
},
"node_modules/chartjs-color": {
"version": "2.4.1",
@ -533,6 +540,14 @@
"color-name": "^1.0.0"
}
},
"node_modules/chartjs-plugin-datalabels": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz",
"integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==",
"peerDependencies": {
"chart.js": ">=3.0.0"
}
},
"node_modules/classnames": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
@ -727,9 +742,9 @@
}
},
"node_modules/moment": {
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"engines": {
"node": "*"
}

View File

@ -17,10 +17,11 @@
"@adminkit/core": "^3.4.0",
"bootstrap": "^5.3.0",
"bootstrap-icons": "^1.10.5",
"chart.js": "^3.9.1",
"chartjs-plugin-datalabels": "^2.2.0",
"history": "^5.3.0",
"svelte-navigator": "^3.2.2",
"svelte-pagination": "^0.0.1",
"svelte-qrcode": "^1.0.0",
"chart.js": "^3.7.0"
"svelte-qrcode": "^1.0.0"
}
}

View File

@ -0,0 +1,113 @@
<script>
import { onMount } from 'svelte';
import { getCountByComuna } from '$/services/paraderos';
import Chart from 'chart.js/auto';
import ChartDataLabels from 'chartjs-plugin-datalabels';
let comunasCounts = [];
let chart = null; // Referencia al gráfico
onMount(() => {
getCountByComuna({ vigente: 1 })
.then(data => {
comunasCounts = data.count_by_comuna.sort((a, b) => a.id_comuna__nombre_comuna.localeCompare(b.id_comuna__nombre_comuna));
updateChart(); // Actualizar el gráfico cuando los datos estén listos
})
.catch(error => console.error("Failed to load comunas counts:", error));
});
function updateChart() {
const ctx = document.getElementById('comunasChart').getContext('2d');
if (chart) {
chart.destroy(); // Destruir el gráfico existente antes de crear uno nuevo
}
chart = new Chart(ctx, {
type: 'pie',
data: {
labels: comunasCounts.map(c => c.id_comuna__nombre_comuna),
datasets: [{
label: 'Total Paraderos',
data: comunasCounts.map(c => c.total),
backgroundColor: comunasCounts.map(() => `hsla(${Math.random() * 360}, 100%, 75%, 0.8)`), // Colores aleatorios con opacidad
hoverOffset: 4
}]
},
plugins: [ChartDataLabels],
options: {
responsive: true,
plugins: {
datalabels: {
color: '#ffffff',
anchor: 'end',
align: 'start',
font: {
size: 14,
weight: 'bold',
family: 'Arial'
},
formatter: (value, ctx) => {
let sum = ctx.dataset.data.reduce((acc, curr) => acc + curr, 0);
let percentage = (value * 100 / sum).toFixed(2) + "%";
return ` (${percentage})`;
}
},
tooltip: {
callbacks: {
label: function(tooltipItem) {
let label = tooltipItem.label || '';
let value = tooltipItem.raw;
let total = tooltipItem.dataset.data.reduce((acc, curr) => acc + curr, 0);
let percentage = ((value / total) * 100).toFixed(2) + '%';
return `${label}: (${percentage})`;
}
}
},
legend: {
position: 'top',
}
}
}
});
}
</script>
<table class="table table-striped table-hover table-responsive">
<tr>
<th>
<div class="card">
<div class="card-body">
<h5 class="card-title">Paraderos por Comuna </h5>
<div class="col-auto">
<div class="stat text-primary">
<i class="bi bi-map"></i>
</div>
</div>
<table class="table table-striped table-hover table-responsive">
<thead>
<tr>
<th>Comuna</th>
<th>Total Paraderos</th>
</tr>
</thead>
<tbody>
{#each comunasCounts as { id_comuna__nombre_comuna, total }}
<tr>
<td>{id_comuna__nombre_comuna}</td>
<td>{total}</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
</th>
<th>
<div class="card">
<div class="card-body">
<canvas id="comunasChart"></canvas>
</div>
</div>
</th>
</tr>
</table>

View File

@ -0,0 +1,71 @@
<script>
import { onMount, createEventDispatcher } from "svelte";
import Chart from 'chart.js/auto';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import { getCountRutasBuses } from "$/services/lineas";
import { getCount } from "$/services/lineas";
const dispatch = createEventDispatcher();
let rutasConGPS = [];
let rutasSinGPS = 0;
let chart = null;
onMount(() => {
dispatch('loading', true);
Promise.all([
getCountRutasBuses(),
getCount({ vigente: 1 })
]).then(([dataRutasConGPS, dataTotalRutas]) => {
rutasConGPS = dataRutasConGPS;
rutasSinGPS = parseInt (dataTotalRutas.count) - parseInt (dataRutasConGPS.count);
updateChart();
}).catch(error => {
console.error('Error fetching counts:', error);
}).finally(() => {
dispatch('loading', false);
});
});
function updateChart() {
const ctx = document.getElementById('barChartR').getContext('2d');
if (chart) {
chart.destroy();
}
chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Rutas con información', 'Rutas sin información'],
datasets: [{
label: 'Posicionamiento',
data: [rutasConGPS.count, rutasSinGPS],
backgroundColor: ['rgba(54, 162, 235, 0.8)', 'rgba(255, 99, 132, 0.8)']
}]
},
plugins: [ChartDataLabels],
options: {
plugins: {
legend: {
display: true
},
tooltip: {
enabled: true
}
},
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
});
}
</script>
<div class="card">
<div class="card-body">
<h5 class="card-title">Rutas con Informacion de Posicionamiento</h5>
<canvas id="barChartR"></canvas>
</div>
</div>

View File

@ -3,14 +3,18 @@
import CantidadParaderos from "./CantidadParaderos.svelte";
import CantidadLineas from "./CantidadLineas.svelte";
import CantidadParaderosComuna from "./CantidadParaderosComuna.svelte";
import CantidadParaderosComunaGrafico from "./CantidadParaderosComunaGrafico.svelte";
import CantidadBusesRecorrido from "./CantidadBusesRecorrido.svelte";
import CantidadBusesLinea from "./CantidadBusesLinea.svelte";
import RutasCorrectas from "./rutasCorrectas.svelte";
import CantidadRutasBuses from "./CantidadRutaBuses.svelte";
let loading1 = false
let loading2 = false
let loading3 = false
let loading4 = false
let loading5 = false
let loading6 = false
</script>
<PageTitle
@ -26,15 +30,30 @@
<div class="col">
<CantidadParaderos on:loading={ev => loading2 = ev.detail} />
</div>
</div>
<div class="row">
<div class="col">
<CantidadParaderosComuna on:loading={ev => loading3 = ev.detail} />
</div>
<div class="col">
<CantidadBusesRecorrido on:loading={ev => loading4 = ev.detail} />
</div>
</div>
<div class="row">
<div class="col">
<RutasCorrectas on:loading={ev => loading5 = ev.detail} />
</div>
</div>
<div class="row">
<div class="col">
<CantidadRutasBuses on:loading={ev => loading6 = ev.detail} />
</div>
<div class="col">
<!--<CantidadParaderosComuna on:loading={ev => loading3 = ev.detail} /> -->
<CantidadParaderosComunaGrafico on:loading={ev => loading3 = ev.detail} />
</div>
</div>
</div>

View File

@ -0,0 +1,69 @@
<script>
import { onMount } from "svelte";
import Chart from 'chart.js/auto';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import { getCountLineasCorrectas } from "$/services/lineas";
let rutas = [];
let chart = null;
onMount(() => {
getCountLineasCorrectas().then(data => {
rutas = data;
updateChart();
}).catch(error => console.error('Error fetching line counts:', error));
});
function updateChart() {
const ctx = document.getElementById('barChart').getContext('2d');
if (chart) {
chart.destroy();
}
// Generando colores aleatorios para cada barra
const backgroundColors = rutas.map(() => `hsla(${Math.random() * 360}, 70%, 70%, 0.8)`);
const borderColors = rutas.map(() => `hsla(${Math.random() * 360}, 70%, 50%, 1)`);
chart = new Chart(ctx, {
type: 'bar',
data: {
labels: rutas.map(ruta => ruta.titulo),
datasets: [{
label: 'Rutas',
data: rutas.map(ruta => ruta.cantidad),
backgroundColor: backgroundColors,
borderColor: borderColors,
borderWidth: 1
}]
},
plugins: [ChartDataLabels],
options: {
scales: {
y: {
beginAtZero: true
}
},
plugins: {
datalabels: {
color: '#444',
font: {
weight: 'bold'
},
formatter: (value, ctx) => {
let sum = ctx.dataset.data.reduce((a, b) => a + b, 0);
let percentage = (value * 100 / sum).toFixed(2) + "%";
return value + " (" + percentage + ")";
}
}
}
}
});
}
</script>
<div class="card">
<div class="card-body">
<h5 class="card-title">Rutas Definidas</h5>
<canvas id="barChart"></canvas>
</div>
</div>

View File

@ -86,6 +86,16 @@ export async function getCountBuses(params) {
}
export async function getCountLineasCorrectas(params) {
const query = !params ? '' : '?' + (new URLSearchParams(params).toString());
const res = await fetch(`${base}/lineas/count_lineas_correctas/${query}`, {
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}
export async function getCountBusesRecorridos(params) {
const query = !params ? '' : '?' + (new URLSearchParams(params).toString());
const res = await fetch(`${base}/lineas/count_buses_recorridos/${query}`, {
@ -93,4 +103,14 @@ export async function getCountBusesRecorridos(params) {
})
if (!res.ok) throw await res.text()
return res.json()
}
}
export async function getCountRutasBuses(params) {
const query = !params ? '' : '?' + (new URLSearchParams(params).toString());
const res = await fetch(`${base}/lineas/count_rutas_buses/${query}`, {
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}