forked from TDTP/admin_transporte_frontend
Agrega Graficos
parent
cc109373b3
commit
a2687861a2
|
@ -11,6 +11,8 @@
|
||||||
"@adminkit/core": "^3.4.0",
|
"@adminkit/core": "^3.4.0",
|
||||||
"bootstrap": "^5.3.0",
|
"bootstrap": "^5.3.0",
|
||||||
"bootstrap-icons": "^1.10.5",
|
"bootstrap-icons": "^1.10.5",
|
||||||
|
"chart.js": "^3.9.1",
|
||||||
|
"chartjs-plugin-datalabels": "^2.2.0",
|
||||||
"history": "^5.3.0",
|
"history": "^5.3.0",
|
||||||
"svelte-navigator": "^3.2.2",
|
"svelte-navigator": "^3.2.2",
|
||||||
"svelte-pagination": "^0.0.1",
|
"svelte-pagination": "^0.0.1",
|
||||||
|
@ -37,6 +39,15 @@
|
||||||
"simplebar": "5.3.9"
|
"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": {
|
"node_modules/@babel/polyfill": {
|
||||||
"version": "7.12.1",
|
"version": "7.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz",
|
||||||
|
@ -508,13 +519,9 @@
|
||||||
"integrity": "sha512-ceOhN1DL7Y4O6M0j9ICgmTYziV89WMd96SvSl0REd8PMgrY0B/WBOPoed5S1KUmJqXgUXh8gzSe6E3ae27upsQ=="
|
"integrity": "sha512-ceOhN1DL7Y4O6M0j9ICgmTYziV89WMd96SvSl0REd8PMgrY0B/WBOPoed5S1KUmJqXgUXh8gzSe6E3ae27upsQ=="
|
||||||
},
|
},
|
||||||
"node_modules/chart.js": {
|
"node_modules/chart.js": {
|
||||||
"version": "2.9.4",
|
"version": "3.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
|
||||||
"integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==",
|
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
|
||||||
"dependencies": {
|
|
||||||
"chartjs-color": "^2.1.0",
|
|
||||||
"moment": "^2.10.2"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/chartjs-color": {
|
"node_modules/chartjs-color": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
|
@ -533,6 +540,14 @@
|
||||||
"color-name": "^1.0.0"
|
"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": {
|
"node_modules/classnames": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||||
|
@ -727,9 +742,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/moment": {
|
"node_modules/moment": {
|
||||||
"version": "2.29.4",
|
"version": "2.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
"@adminkit/core": "^3.4.0",
|
"@adminkit/core": "^3.4.0",
|
||||||
"bootstrap": "^5.3.0",
|
"bootstrap": "^5.3.0",
|
||||||
"bootstrap-icons": "^1.10.5",
|
"bootstrap-icons": "^1.10.5",
|
||||||
|
"chart.js": "^3.9.1",
|
||||||
|
"chartjs-plugin-datalabels": "^2.2.0",
|
||||||
"history": "^5.3.0",
|
"history": "^5.3.0",
|
||||||
"svelte-navigator": "^3.2.2",
|
"svelte-navigator": "^3.2.2",
|
||||||
"svelte-pagination": "^0.0.1",
|
"svelte-pagination": "^0.0.1",
|
||||||
"svelte-qrcode": "^1.0.0",
|
"svelte-qrcode": "^1.0.0"
|
||||||
"chart.js": "^3.7.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -3,14 +3,18 @@
|
||||||
import CantidadParaderos from "./CantidadParaderos.svelte";
|
import CantidadParaderos from "./CantidadParaderos.svelte";
|
||||||
import CantidadLineas from "./CantidadLineas.svelte";
|
import CantidadLineas from "./CantidadLineas.svelte";
|
||||||
import CantidadParaderosComuna from "./CantidadParaderosComuna.svelte";
|
import CantidadParaderosComuna from "./CantidadParaderosComuna.svelte";
|
||||||
|
import CantidadParaderosComunaGrafico from "./CantidadParaderosComunaGrafico.svelte";
|
||||||
import CantidadBusesRecorrido from "./CantidadBusesRecorrido.svelte";
|
import CantidadBusesRecorrido from "./CantidadBusesRecorrido.svelte";
|
||||||
import CantidadBusesLinea from "./CantidadBusesLinea.svelte";
|
import CantidadBusesLinea from "./CantidadBusesLinea.svelte";
|
||||||
|
import RutasCorrectas from "./rutasCorrectas.svelte";
|
||||||
|
import CantidadRutasBuses from "./CantidadRutaBuses.svelte";
|
||||||
|
|
||||||
let loading1 = false
|
let loading1 = false
|
||||||
let loading2 = false
|
let loading2 = false
|
||||||
let loading3 = false
|
let loading3 = false
|
||||||
let loading4 = false
|
let loading4 = false
|
||||||
let loading5 = false
|
let loading5 = false
|
||||||
|
let loading6 = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<PageTitle
|
<PageTitle
|
||||||
|
@ -26,15 +30,30 @@
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<CantidadParaderos on:loading={ev => loading2 = ev.detail} />
|
<CantidadParaderos on:loading={ev => loading2 = ev.detail} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<CantidadParaderosComuna on:loading={ev => loading3 = ev.detail} />
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<CantidadBusesRecorrido on:loading={ev => loading4 = ev.detail} />
|
<CantidadBusesRecorrido on:loading={ev => loading4 = ev.detail} />
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
@ -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) {
|
export async function getCountBusesRecorridos(params) {
|
||||||
const query = !params ? '' : '?' + (new URLSearchParams(params).toString());
|
const query = !params ? '' : '?' + (new URLSearchParams(params).toString());
|
||||||
const res = await fetch(`${base}/lineas/count_buses_recorridos/${query}`, {
|
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()
|
if (!res.ok) throw await res.text()
|
||||||
return res.json()
|
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()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue