273 lines
7.3 KiB
JavaScript
273 lines
7.3 KiB
JavaScript
Chart.register(ChartDataLabels);
|
|
function formatBrl(v) {
|
|
return 'R$ ' + convertFloatToMoeda(v)
|
|
}
|
|
|
|
function getData(el, key) {
|
|
return JSON.parse(el.dataset[key] || '[]')
|
|
}
|
|
|
|
function gerarCores(qtd) {
|
|
const paleta = [
|
|
'#4254BA',
|
|
'#2196F3',
|
|
'#FFC107',
|
|
'#F44336',
|
|
'#9C27B0',
|
|
'#00BCD4',
|
|
'#FF5722',
|
|
'#795548',
|
|
'#3F51B5',
|
|
'#8BC34A',
|
|
'#E91E63',
|
|
'#009688'
|
|
]
|
|
|
|
return paleta.slice(0, qtd)
|
|
}
|
|
|
|
|
|
function criarPizza(id) {
|
|
const el = document.getElementById(id)
|
|
if (!el) return
|
|
|
|
const existing = Chart.getChart(el)
|
|
if (existing) existing.destroy()
|
|
|
|
const labels = getData(el, 'labels')
|
|
const valores = getData(el, 'valores')
|
|
const cores = gerarCores(valores.length)
|
|
|
|
const total = valores.reduce((a, b) => a + b, 0)
|
|
|
|
new Chart(el, {
|
|
type: 'pie',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
data: valores,
|
|
backgroundColor: cores,
|
|
borderColor: '#fff',
|
|
borderWidth: 2
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
tooltip: {
|
|
callbacks: {
|
|
label: function (ctx) {
|
|
let nome = ctx.label
|
|
let valor = ctx.raw
|
|
let percentual = total > 0
|
|
? ((valor / total) * 100).toFixed(1).replace('.', ',')
|
|
: '0,0'
|
|
|
|
return `${nome}: ${formatBrl(valor)} (${percentual}%)`
|
|
}
|
|
}
|
|
},
|
|
|
|
datalabels: {
|
|
color: '#fff',
|
|
font: { weight: 'bold', size: 12 },
|
|
formatter: (value, ctx) => {
|
|
const sum = ctx.chart.data.datasets[0].data
|
|
.reduce((a, b) => a + b, 0)
|
|
|
|
if (sum === 0) return ''
|
|
|
|
const pct = ((value / sum) * 100)
|
|
.toFixed(1)
|
|
.replace('.', ',')
|
|
|
|
return pct + '%'
|
|
}
|
|
},
|
|
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: { usePointStyle: true }
|
|
}
|
|
}
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
function criarFluxo() {
|
|
const el = document.getElementById('graficoFluxo')
|
|
if (!el) return
|
|
|
|
const ctx = el.getContext('2d')
|
|
const labels = getData(el, 'labels')
|
|
const pagar = getData(el, 'pagar')
|
|
const receber = getData(el, 'receber')
|
|
|
|
const gPagar = ctx.createLinearGradient(0, 0, 0, 300)
|
|
gPagar.addColorStop(0, 'rgba(255,99,132,0.35)')
|
|
gPagar.addColorStop(1, 'rgba(255,99,132,0)')
|
|
|
|
const gReceber = ctx.createLinearGradient(0, 0, 0, 300)
|
|
gReceber.addColorStop(0, 'rgba(75,192,192,0.35)')
|
|
gReceber.addColorStop(1, 'rgba(75,192,192,0)')
|
|
|
|
new Chart(el, {
|
|
type: 'line',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [
|
|
{
|
|
label: 'Contas a Pagar',
|
|
data: pagar,
|
|
borderColor: 'rgb(255,99,132)',
|
|
backgroundColor: gPagar,
|
|
tension: 0.35,
|
|
borderWidth: 3,
|
|
pointRadius: 4,
|
|
pointHoverRadius: 6,
|
|
pointBackgroundColor: 'rgb(255,99,132)',
|
|
pointBorderColor: '#fff',
|
|
pointBorderWidth: 2,
|
|
fill: true
|
|
},
|
|
{
|
|
label: 'Contas a Receber',
|
|
data: receber,
|
|
borderColor: 'rgb(75,192,192)',
|
|
backgroundColor: gReceber,
|
|
tension: 0.35,
|
|
borderWidth: 3,
|
|
pointRadius: 4,
|
|
pointHoverRadius: 6,
|
|
pointBackgroundColor: 'rgb(75,192,192)',
|
|
pointBorderColor: '#fff',
|
|
pointBorderWidth: 2,
|
|
fill: true
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: 'top',
|
|
labels: { usePointStyle: true }
|
|
},
|
|
tooltip: {
|
|
callbacks: {
|
|
label: function(context) {
|
|
return `${context.dataset.label}: ${formatBrl(context.raw ?? 0)}`
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
anchor: 'end',
|
|
align: 'top',
|
|
offset: 10,
|
|
|
|
color: '#ffffff',
|
|
textStrokeColor: '#000000',
|
|
textStrokeWidth: 3,
|
|
|
|
shadowBlur: 4,
|
|
shadowColor: 'rgba(0,0,0,0.7)',
|
|
|
|
font: {
|
|
size: 13,
|
|
weight: 'bold'
|
|
},
|
|
|
|
formatter: function (value) {
|
|
return formatBrl(value)
|
|
}
|
|
}
|
|
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
ticks: {
|
|
callback: v => formatBrl(v)
|
|
},
|
|
grid: {
|
|
color: 'rgba(0,0,0,0.05)'
|
|
}
|
|
},
|
|
x: {
|
|
grid: { display: false }
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
function criarLucro() {
|
|
const el = document.getElementById('graficoLucro')
|
|
if (!el) return
|
|
|
|
const existing = Chart.getChart(el)
|
|
if (existing) existing.destroy()
|
|
|
|
const labels = getData(el, 'labels')
|
|
const valores = getData(el, 'valores')
|
|
|
|
const ctx = el.getContext('2d')
|
|
|
|
const gradient = ctx.createLinearGradient(0, 0, 0, 250)
|
|
gradient.addColorStop(0, 'rgba(76, 175, 80, 0.5)') // verde
|
|
gradient.addColorStop(1, 'rgba(76, 175, 80, 0.05)')
|
|
|
|
new Chart(el, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: 'Lucro Mensal',
|
|
data: valores,
|
|
backgroundColor: gradient,
|
|
borderColor: '#4CAF50',
|
|
borderWidth: 2,
|
|
borderRadius: 8
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
|
|
plugins: {
|
|
tooltip: {
|
|
callbacks: {
|
|
label: ctx => `${ctx.dataset.label}: ${formatBrl(ctx.raw)}`
|
|
}
|
|
},
|
|
legend: {
|
|
display: false
|
|
}
|
|
},
|
|
|
|
scales: {
|
|
y: {
|
|
beginAtZero: false,
|
|
ticks: {
|
|
callback: v => formatBrl(v)
|
|
}
|
|
},
|
|
x: {
|
|
grid: { display: false }
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
criarFluxo()
|
|
criarPizza('graficoPagarCategoria')
|
|
criarPizza('graficoReceberCategoria')
|
|
criarLucro()
|
|
})
|