penambahan tampilan pcpd_pajak tambahan gauge

1 parent d8e4d127
......@@ -3,6 +3,9 @@ eis-pcpd,PCPD,/eis/pcpd,1,0,0
eis-pcpd-act,PCPD Act,/eis/pcpd/{act}/act,1,0
eis-pajak,Pajak,#,1,0,1
eis-pajak-kumulatif,Pajak,/eis/pajak,1,0,1,eis-pajak,pcpd,Views,view_pajak,,pcpd_pajak.pt
eis-pajak-kumulatif2,Pajak,/eis/pajak2,1,0,1,eis-pajak,pcpd,Views,view_pajak,,pcpd_pajak2.pt
eis-pajak-kumulatif3,Pajak,/eis/pajak3,1,0,1,eis-pajak,pcpd,Views,view_pajak,,pcpd_pajak3.pt
eis-pajak-kumulatif4,Pajak,/eis/pajak4,1,0,1,eis-pajak,pcpd,Views,view_pajak,,pcpd_pajak4.pt
eis-pbb,PBB,/eis/pbb,1,0,1,eis-pajak,pcpd,Views,view_pbb,,pbb.pt
eis-bphtb,BPHTB,/eis/bphtb,1,0,1,eis-pajak,pcpd,Views,view_bphtb,eis,pcpd.pt
eis-pbjt,PBJT,#,1,0,1,eis-pajak
......
......@@ -30,94 +30,63 @@ PAD_TYP = {
}
jenis_pajak = {
"opsen": {
"kode": "41012",
"nama": "Opsen",
"subs": [
{"kode": "410120010001",
{"kode": "4.1.1.10",
"nama": "Opsen PKB"},
{"kode": "410121010001",
{"kode": "4.1.1.11",
"nama": "Opsen BBNKB"},
]},
"pbb": {
"kode": "410115",
"nama": "PBBP2"},
"kode": "4.1.1.0",
"nama": "Pajak Bumi & Bangunan",
"subs": []
},
"bphtb": {
"kode": "410116",
"nama": "BPHTB-Pemindahan Hak"},
"kode": "4.1.0.0",
"nama": "Bea Perolehan Hak atas Tanah dan Bangunan",
"subs": []
},
"resto": {
"kode": "41011901",
"nama": "PBJT Restoran",
"subs": [
{"kode": "410119010001",
"nama": "PBJT-Restoran"},
{"kode": "410119010002",
"nama": "PBJT-Penyedia Jasa Boga atau Katering"},
{"kode": "410119020001",
"nama": "PBJT-Konsumsi Tenaga Listrik dari Sumber Lain"},
]},
"kode": "4.1.1.02",
"nama": "PBJT - Makanan dan Minuman",
"subs": []
},
"ppju": {
"kode": "41011902",
"kode": "4.1.1.05",
"nama": "PBJT-Tenaga Listrik",
"subs": []},
"hotel": {
"kode": "41011903",
"kode": "4.1.1.01",
"nama": "PBJT Jasa Perhotelan",
"subs": [
{"kode": "410119030001", "nama": "PBJT-Hotel"},
{"kode": "410119030003", "nama": "PBJT-Vila"},
{"kode": "410119030007", "nama": "PBJT-Wisma Pariwisata"},
]},
"subs": []
},
"parkir": {
"kode": "41011904",
"nama": "PBJT-Penyediaan atau Penyelenggaraan Tempat Parkir"},
"kode": "4.1.1.07",
"nama": "Pajak Parkir"},
"hiburan": {
"kode": "41011905",
"nama": "PBJT-Jasa Kesenian dan Hiburan",
"subs": [
{"kode": "410119050001",
"nama": "PBJT-Tontonan Film atau Bentuk Tontonan Audio Visual Lainnya yang Dipertontonkan secara Langsung di Suatu Lokasi Tertentu"},
{"kode": "410119050002",
"nama": "PBJT-Pergelaran Kesenian, Musik, Tari, dan/atau Busana"},
{"kode": "410119050007",
"nama": "PBJT-Pacuan Kuda dan Perlombaan Kendaraan Bermotor"},
{"kode": "410119050008",
"nama": "PBJT-Permainan Ketangkasan"},
{"kode": "410119050009",
"nama": "PBJT-Olahraga Permainan dengan Menggunakan Tempat/Ruang dan/atau Peralatan dan Perlengkapan untuk Olahraga dan Kebugaran"},
{"kode": "410119050010",
"nama": "PBJT-Rekreasi Wahana Air, Wahana Ekologi, Wahana Pendidikan, Wahana Budaya, Wahana Salju, Wahana Permainan, Pemancingan, Agrowisata, dan Kebun Binatang"},
{"kode": "410119050012",
"nama": "PBJT-Distkotek, Karaoke, Kelab Malam, Bar, dan Mandi Uap/Spa"},
]},
"kode": "4.1.1.03",
"nama": "PBJT - Jasa Kesenian dan Hiburan",
"subs": []
},
"reklame": {
"kode": "410109",
"nama": "Pajak Reklame",
"subs": [
{"kode": "410109010001",
"nama": "Pajak Reklame Papan/Billboard/Videotron/Megatron"},
{"kode": "410109020001", "nama": "Pajak Reklame Kain"},
{"kode": "410109030001",
"nama": "Pajak Reklame Melekat/Stiker"},
{"kode": "410109050001", "nama": "Pajak Reklame Berjalan"},
]},
"kode": "4.1.1.04",
"nama": "Pajak Rekalme",
"subs": []
},
"atd": {
"kode": "410112",
"kode": "4.1.1.08",
"nama": "Pajak Air Tanah"},
"walet": {
"kode": "410113",
"nama": "Pajak Sarang Burung Walet "},
"kode": "4.1.1.09",
"nama": "Pajak Sarang Burung Walet"},
"minerba": {
"kode": "410114",
"kode": "4.1.1.06",
"nama": "Pajak Mineral Bukan Logam dan Batuan",
"subs": [
{"kode": "410114230001", "nama": "Pajak Pasir dan Kerikil"},
{"kode": "410114300001", "nama": "Pajak Tanah Liat"},
]}
"subs": []
}
}
......
......@@ -10,7 +10,22 @@
</style>
<div metal:fill-slot="content">
<!-- Main Title -->
<div class="row">
<div class="col-md-12">
<div class="text-center" style="margin-bottom: 20px; padding: 15px 0;">
<h2 style="margin: 0; font-weight: bold; color: #333; text-transform: uppercase; letter-spacing: 1px;">
LAPORAN REALTIME REALISASI PAJAK DAERAH
</h2>
<h3 style="margin: 5px 0 0; font-weight: bold; color: #cc5200; text-transform: uppercase; letter-spacing: 1px;">
DATA DAN INFORMASI
</h3>
<h4 id="tanggalHariIni" style="margin: 5px 0 0; color: #003399; font-weight: bold;"></h4>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-3 col1">
<img src="${home}/eis/static/pcpd-logo.png" class="img-responsive logo-pcpd" alt="PCPD Logo">
</div>
......@@ -29,7 +44,7 @@
</div>
</div>
</div>
<div class="row">
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default text-center">
<div class="panel-heading">
......@@ -70,10 +85,10 @@
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-statistics.png" class="icon-rounded" alt="" align="left">
<img src="${home}/eis/static/bapend.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Target dan Realisasi per Pajak
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
......@@ -111,10 +126,28 @@
</div>
</div>
</div>
<hr>
<!-- Gauge Chart Section -->
<div class="col-md-4">
<div class="panel panel-default" id="gaugePanel" style="min-height: 500px;">
<div class="panel-heading" style="padding: 10px 15px;">
<h5 class="text-center bold" style="margin: 0;">REALISASI PAJAK DAERAH</h5>
</div>
<div class="panel-body" style="padding: 0; height: calc(100% - 50px); overflow: hidden; display: flex; flex-direction: column;">
<div id="chartContainer" style="flex: 1; display: flex; align-items: center; justify-content: center; margin: 0; padding: 0;">
<canvas id="gaugeChart" width="100%" height="100%"></canvas>
</div>
<div class="text-center" style="padding: 10px; background: rgba(0,0,0,0.02); border-top: 1px solid #ddd;">
<h4 id="gaugePercentage" style="margin: 2px 0; font-weight: bold; color: #333; font-size: 16px;">63.70%</h4>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Realisasi: Rp.<span id="gaugeRealisasi">2.343.460.022.116</span></p>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Target: Rp.<span id="gaugeTarget">3.679.068.431.493</span></p>
</div>
</div>
</div>
</div>
</div>
<hr>
<div class="row ">
<div class="row hide">
<div class="col-md-2">
<select class="form-control rounded" id="rangeType">
<option value="3">Bulanan</option>
......@@ -124,7 +157,7 @@
</div>
<hr>
</div>
<div class="row">
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
......@@ -156,7 +189,7 @@
</div>
</div>
</div>
<div class="row">
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
......@@ -199,12 +232,22 @@
</metal:js>
<script metal:fill-slot="scripts">
<script metal:fill-slot="scripts">
const today = new Date();
const options = { day: 'numeric', month: 'long', year: 'numeric' };
const tanggalFormat = today.toLocaleDateString('id-ID', options);
document.addEventListener("DOMContentLoaded", function () {
document.getElementById("tanggalHariIni").innerText = "Tanggal, " + tanggalFormat;
});
var pieChart;
var amtTrendChart;
var trxTrendChart;
var amtKumulatifChart;
var trxKumulatifChart;
var gaugeChart;
var newData;
$(document).ready(function () {
......@@ -342,8 +385,153 @@
$("#rangeType").change(function () {
trendChart();
});
// Initialize Gauge Chart
initializeGauge();
$().datarefresh();
});
// Function to match gauge panel height with table panel
function matchPanelHeights() {
var tablePanel = document.querySelector('.col-md-8 .panel');
var gaugePanel = document.getElementById('gaugePanel');
if (tablePanel && gaugePanel) {
var tablePanelHeight = tablePanel.offsetHeight;
gaugePanel.style.height = tablePanelHeight + 'px';
}
}
function initializeGauge() {
var canvas = document.getElementById('gaugeChart');
var ctx = canvas.getContext('2d');
var container = document.getElementById('chartContainer');
// Set canvas size to fill container
function resizeCanvas() {
var containerRect = container.getBoundingClientRect();
var size = Math.min(containerRect.width, containerRect.height);
canvas.width = containerRect.width;
canvas.height = size * 0.7; // Semi-circle height ratio
// Update gauge properties
if (gaugeChart) {
gaugeChart.centerX = canvas.width / 2;
gaugeChart.centerY = canvas.height - 20;
gaugeChart.radius = Math.min(canvas.width * 0.45, canvas.height * 0.65);
gaugeChart.draw();
}
}
// Match panel heights and resize canvas
matchPanelHeights();
setTimeout(resizeCanvas, 100); // Allow DOM to update
gaugeChart = {
canvas: canvas,
ctx: ctx,
centerX: canvas.width / 2,
centerY: canvas.height - 20,
radius: Math.min(canvas.width * 0.45, canvas.height * 0.65),
value: 63.70,
draw: function() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Draw gauge background segments
this.drawSegments();
// Draw scale numbers
this.drawScale();
// Draw needle
this.drawNeedle();
},
drawSegments: function() {
var ctx = this.ctx;
var segments = [
{ start: 0, end: 40, color: '#ff0000' }, // Red (0-40)
{ start: 40, end: 70, color: '#ffff00' }, // Yellow (40-70)
{ start: 70, end: 100, color: '#00ff00' } // Green (70-100)
];
segments.forEach(segment => {
var startAngle = Math.PI + (segment.start / 100) * Math.PI;
var endAngle = Math.PI + (segment.end / 100) * Math.PI;
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, this.radius, startAngle, endAngle);
ctx.lineWidth = Math.max(12, this.radius * 0.08);
ctx.strokeStyle = segment.color;
ctx.stroke();
});
},
drawScale: function() {
var ctx = this.ctx;
ctx.fillStyle = '#000';
ctx.font = Math.max(10, this.radius * 0.08) + 'px Arial';
ctx.textAlign = 'center';
// Draw scale numbers (0, 10, 20, ..., 100)
for (var i = 0; i <= 100; i += 10) {
var angle = Math.PI + (i / 100) * Math.PI;
var labelRadius = this.radius + Math.max(20, this.radius * 0.15);
var x = this.centerX + Math.cos(angle) * labelRadius;
var y = this.centerY + Math.sin(angle) * labelRadius + 5;
ctx.fillText(i.toString(), x, y);
}
},
drawNeedle: function() {
var ctx = this.ctx;
var angle = Math.PI + (this.value / 100) * Math.PI;
ctx.save();
// Draw needle line
ctx.beginPath();
ctx.moveTo(this.centerX, this.centerY);
var needleLength = this.radius - Math.max(8, this.radius * 0.05);
var needleX = this.centerX + Math.cos(angle) * needleLength;
var needleY = this.centerY + Math.sin(angle) * needleLength;
ctx.lineTo(needleX, needleY);
ctx.strokeStyle = '#000';
ctx.lineWidth = Math.max(3, this.radius * 0.02);
ctx.lineCap = 'round';
ctx.stroke();
ctx.restore();
// Draw center circle
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, Math.max(5, this.radius * 0.04), 0, 2 * Math.PI);
ctx.fillStyle = '#000';
ctx.fill();
},
update: function(value) {
this.value = Math.max(0, Math.min(100, value));
this.draw();
}
};
// Initial draw
gaugeChart.draw();
}
function updateGauge(percentage, realisasi, target) {
if (gaugeChart) {
gaugeChart.update(percentage);
}
document.getElementById('gaugePercentage').textContent = percentage.toFixed(2) + '%';
document.getElementById('gaugeRealisasi').textContent = parseInt(realisasi).toLocaleString('id-ID');
document.getElementById('gaugeTarget').textContent = parseInt(target).toLocaleString('id-ID');
}
function addData(chart, data) {
labels = [];
......@@ -459,6 +647,13 @@
$('#sum_realisasi').html(sum_realisasi.toLocaleString("id-ID"));
$('#sum_sisa').html(sum_sisa.toLocaleString("id-ID"));
$('#sum_persen').html((sum_realisasi / sum_target * 100).toFixed(2));
// Update gauge with total values
var gaugePercentage = (sum_realisasi / sum_target * 100);
updateGauge(gaugePercentage, sum_realisasi, sum_target);
// Match panel heights after data load
matchPanelHeights();
table.draw();
} else {
......
<html metal:use-macro="load: eis-base.pt" tal:define="url request.route_url('eis-pcpd-act', act=module);">
<metal:css fill-slot="css_files">
<link rel="stylesheet" href="${home}/eis/static/css/odometer-theme-plaza.css">
<link rel="stylesheet" href="${home}/static/v3/plugin/datatables/1.10/media/css/dataTables.bootstrap.css">
<link href="${home}/eis/static/css/pcpd.css" rel="stylesheet">
</metal:css>
<style metal:fill-slot="styles">
</style>
<div metal:fill-slot="content">
<!-- Main Title -->
<div class="row">
<div class="col-md-12">
<div class="text-center" style="margin-bottom: 20px; padding: 15px 0;">
<h2 style="margin: 0; font-weight: bold; color: #333; text-transform: uppercase; letter-spacing: 1px;">
LAPORAN REALTIME REALISASI PAJAK DAERAH
</h2>
<h3 style="margin: 5px 0 0; font-weight: bold; color: #cc5200; text-transform: uppercase; letter-spacing: 1px;">
DATA DAN INFORMASI
</h3>
<h4 id="tanggalHariIni" style="margin: 5px 0 0; color: #003399; font-weight: bold;"></h4>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-3 col1">
<img src="${home}/eis/static/pcpd-logo.png" class="img-responsive logo-pcpd" alt="PCPD Logo">
</div>
<div class="col-md-9 col2">
<div class="panel panel-default text-center main-panel uppercase">
<div class="panel-body">
<h1 class="title-panel"><b>${title}</b></h1>
<div class="padding-top-sm">
<h5 id="time">Rab, 4 Jun 2025 - 14:11:05</h5>
</div>
<h4 class="odoometer-head">
<b>Rp.<h4 class="odometer bold" id="today"></h4></b>
</h4>
<h5 class="padding-top-sm"><b><span id="trx"></span> Transaksi</b></h5>
</div>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default text-center">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-money-transfer.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">
Total Realisasi s.d Hari Ini
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container">
<h2 class="primary">
<b>Realisasi Rp. <span class="odometer sub-odometer bold primary" id="ytd">0</span></b>
<p>
Target Rp. <span class=" bold" id="ytdTarget">123</span>
<p>
Persentase <span class="odometer sub-odometer bold primary" id="ytdPersen">
</h2>
<h3 class="primary bold"><span id="trxYtd">0</span> Transaksi</h3>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default hide">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-pie-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Jumlah Transaksi
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center">
<canvas id="chartPie"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/bapend.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Target dan Realisasi per Pajak
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<table class="table table-bordered table-sm" id="table1">
<thead>
<tr>
<th class="align-middle text-center">Kode</th>
<th class="align-middle text-center">Uraian</th>
<th class="text-center">Target</th>
<th class="text-center">Realisasi</th>
<th class="text-center">Selisih</th>
<th class="text-center">%</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class=""></td>
<td class=""></td>
<td class="right">0</td>
<td class="right">0</td>
<td class="right">0</td>
<td class="right">0</td>
</tr>
</tbody>
<tfoot>
<td colspan="2" class="text-right">Jumlah</td>
<td><span id="sum_target"></span></td>
<td><span id="sum_realisasi"></span></td>
<td><span id="sum_sisa"></span></td>
<td><span id="sum_persen"></span></td>
</tfoot>
</table>
</div>
</div>
</div>
<!-- Gauge Chart Section -->
<div class="col-md-4">
<div class="panel panel-default" id="gaugePanel" style="min-height: 500px;">
<div class="panel-heading" style="padding: 10px 15px;">
<h5 class="text-center bold" style="margin: 0;">REALISASI PAJAK DAERAH</h5>
</div>
<div class="panel-body" style="padding: 0; height: calc(100% - 50px); overflow: hidden; display: flex; flex-direction: column;">
<div id="chartContainer" style="flex: 1; display: flex; align-items: center; justify-content: center; margin: 0; padding: 0;">
<canvas id="gaugeChart" width="100%" height="100%"></canvas>
</div>
<div class="text-center" style="padding: 10px; background: rgba(0,0,0,0.02); border-top: 1px solid #ddd;">
<h4 id="gaugePercentage" style="margin: 2px 0; font-weight: bold; color: #333; font-size: 16px;">63.70%</h4>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Realisasi: Rp.<span id="gaugeRealisasi">2.343.460.022.116</span></p>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Target: Rp.<span id="gaugeTarget">3.679.068.431.493</span></p>
</div>
</div>
</div>
</div>
</div>
<hr>
<div class="row hide">
<div class="col-md-2">
<select class="form-control rounded" id="rangeType">
<option value="3">Bulanan</option>
<option value="2">Mingguan</option>
<option value="1">Harian</option>
</select>
</div>
<hr>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-gantt-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Realiasi (Rp)
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartRealisasi"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Realiasi Kumulatif (Rp)
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartKumulatif" width="200" height="200"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-statistics.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Transaksi
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartRealisasiCnt"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-line-chart-icon.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Transaksi Kumulatif
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartKumulatifCnt" width="200" height="200"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<metal:js fill-slot="js_files">
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script> -->
<script src="${home}/eis/static/js/chart.js"></script>
<script src="${home}/eis/static/js/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="${home}/eis/static/js/odometer.js"></script>
<script src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.min.js"></script>
<script src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.ext.js"></script>
</metal:js>
<script metal:fill-slot="scripts">
const today = new Date();
const options = { day: 'numeric', month: 'long', year: 'numeric' };
const tanggalFormat = today.toLocaleDateString('id-ID', options);
document.addEventListener("DOMContentLoaded", function () {
document.getElementById("tanggalHariIni").innerText = "Tanggal, " + tanggalFormat;
});
var pieChart;
var amtTrendChart;
var trxTrendChart;
var amtKumulatifChart;
var trxKumulatifChart;
var gaugeChart;
var newData;
$(document).ready(function () {
var ctx = document.getElementById('chartPie').getContext('2d');
var canvas = document.getElementById('chartPie');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.8;
const pie_data = {
labels: [
'Pajak',
'Retribusi',
],
datasets: [{
data: [300, 100],
backgroundColor: [
'#16a75c', //'rgb(255, 99, 132)',
'#ffb900', // 'rgb(54, 162, 235)'
],
hoverOffset: 4
}]
};
pieChart = new Chart(ctx,
{
type: 'pie',
data: pie_data,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom'
}
}
}
}
);
var ctx = document.getElementById('chartRealisasi').getContext('2d');
var canvas = document.getElementById('chartRealisasi');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
var realisasi_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Realiasi',
data: [100, 50, 300, 250, 100, 150, 2000],
borderColor: '#16a75c',// 'rgb(75, 192, 192)',
backgroundColor: '#16a75c8a',
fill: true,
tension: 0.5
}]
};
amtTrendChart = new Chart(ctx, {
type: 'line',
data: realisasi_data,
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: {
display: false,
drawBorder: false,
}
}
}
}
});
var transaksi_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Transaksi',
data: [100, 50, 300, 250, 100, 150, 2000],
borderColor: '#16a75c',// 'rgb(75, 192, 192)',
backgroundColor: '#16a75c8a',
fill: true,
tension: 0.5
}]
};
var ctx = document.getElementById('chartRealisasiCnt').getContext('2d');
var canvas = document.getElementById('chartRealisasiCnt');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
trxTrendChart = new Chart(ctx, {
type: 'line',
data: transaksi_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
var ctx = document.getElementById('chartKumulatif').getContext('2d');
var canvas = document.getElementById('chartKumulatif');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
var kumulatif_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Kumulatif',
data: [100, 150, 400, 650, 900, 950, 1100],
borderColor: '#ffb900', //'rgb(75, 192, 192)',
backgroundColor: '#debd68ad',
fill: true,
tension: 0.5
}]
};
amtKumulatifChart = new Chart(ctx, {
type: 'line',
data: kumulatif_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
var ctx = document.getElementById('chartKumulatifCnt').getContext('2d');
var canvas = document.getElementById('chartKumulatifCnt');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
trxKumulatifChart = new Chart(ctx, {
type: 'line',
data: kumulatif_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
$("#rangeType").change(function () {
trendChart();
});
// Initialize Gauge Chart
initializeGauge();
$().datarefresh();
});
// Function to match gauge panel height with table panel
function matchPanelHeights() {
var tablePanel = document.querySelector('.col-md-8 .panel');
var gaugePanel = document.getElementById('gaugePanel');
if (tablePanel && gaugePanel) {
var tablePanelHeight = tablePanel.offsetHeight;
gaugePanel.style.height = tablePanelHeight + 'px';
}
}
function initializeGauge() {
var canvas = document.getElementById('gaugeChart');
var ctx = canvas.getContext('2d');
var container = document.getElementById('chartContainer');
// Set canvas size to fill container
function resizeCanvas() {
var containerRect = container.getBoundingClientRect();
var size = Math.min(containerRect.width, containerRect.height);
canvas.width = containerRect.width;
canvas.height = size * 0.7; // Semi-circle height ratio
// Update gauge properties
if (gaugeChart) {
gaugeChart.centerX = canvas.width / 2;
gaugeChart.centerY = canvas.height - 20;
gaugeChart.radius = Math.min(canvas.width * 0.45, canvas.height * 0.65);
gaugeChart.draw();
}
}
// Match panel heights and resize canvas
matchPanelHeights();
setTimeout(resizeCanvas, 100); // Allow DOM to update
gaugeChart = {
canvas: canvas,
ctx: ctx,
centerX: canvas.width / 2,
centerY: canvas.height - 20,
radius: Math.min(canvas.width * 0.45, canvas.height * 0.65),
value: 63.70,
draw: function() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Draw gauge background segments
this.drawSegments();
// Draw scale numbers
this.drawScale();
// Draw needle
this.drawNeedle();
},
drawSegments: function() {
var ctx = this.ctx;
var segments = [
{ start: 0, end: 40, color: '#ff0000' }, // Merah (0-40)
{ start: 40, end: 70, color: '#ffff00' }, // Kuning (40-70)
{ start: 70, end: 100, color: '#00ff00' } // Hijau (70-100)
];
segments.forEach(segment => {
var startAngle = Math.PI + (segment.start / 100) * Math.PI;
var endAngle = Math.PI + (segment.end / 100) * Math.PI;
ctx.beginPath();
ctx.moveTo(this.centerX, this.centerY); // mulai dari pusat gauge
ctx.arc(this.centerX, this.centerY, this.radius, startAngle, endAngle);
ctx.closePath();
ctx.fillStyle = segment.color;
ctx.fill(); // isi penuh
});
},
drawScale: function() {
var ctx = this.ctx;
ctx.fillStyle = '#000';
ctx.font = Math.max(10, this.radius * 0.08) + 'px Arial';
ctx.textAlign = 'center';
// Draw scale numbers (0, 10, 20, ..., 100)
for (var i = 0; i <= 100; i += 10) {
var angle = Math.PI + (i / 100) * Math.PI;
var labelRadius = this.radius + Math.max(20, this.radius * 0.15);
var x = this.centerX + Math.cos(angle) * labelRadius;
var y = this.centerY + Math.sin(angle) * labelRadius + 5;
ctx.fillText(i.toString(), x, y);
}
},
drawNeedle: function() {
var ctx = this.ctx;
var angle = Math.PI + (this.value / 100) * Math.PI;
ctx.save();
// Draw needle line
ctx.beginPath();
ctx.moveTo(this.centerX, this.centerY);
var needleLength = this.radius - Math.max(8, this.radius * 0.05);
var needleX = this.centerX + Math.cos(angle) * needleLength;
var needleY = this.centerY + Math.sin(angle) * needleLength;
ctx.lineTo(needleX, needleY);
ctx.strokeStyle = '#000';
ctx.lineWidth = Math.max(3, this.radius * 0.02);
ctx.lineCap = 'round';
ctx.stroke();
ctx.restore();
// Draw center circle
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, Math.max(5, this.radius * 0.04), 0, 2 * Math.PI);
ctx.fillStyle = '#000';
ctx.fill();
},
update: function(value) {
this.value = Math.max(0, Math.min(100, value));
this.draw();
}
};
// Initial draw
gaugeChart.draw();
}
function updateGauge(percentage, realisasi, target) {
if (gaugeChart) {
gaugeChart.update(percentage);
}
document.getElementById('gaugePercentage').textContent = percentage.toFixed(2) + '%';
document.getElementById('gaugeRealisasi').textContent = parseInt(realisasi).toLocaleString('id-ID');
document.getElementById('gaugeTarget').textContent = parseInt(target).toLocaleString('id-ID');
}
function addData(chart, data) {
labels = [];
aData = [];
backgroundColor = [];
data.forEach(element => {
labels.push(element[0]);
aData.push(element[1]);
if (element.length > 2)
backgroundColor.push(element[2]);
});
chart.data.labels.length = 0;
chart.data.datasets[0].data.length = 0;
if (backgroundColor.length != 0) {
chart.data.datasets[0].data.backgroundColor = 0;
chart.data.datasets[0].backgroundColor = backgroundColor;
}
chart.data.labels = labels;
chart.data.datasets[0].data = aData;
chart.update();
}
trendChart = function () {
if (rangeType.value == 1) {
amtTrendChartData = newData.daily;
trxTrendChartData = newData.dailyTrx;
amtKumulatifChartData = newData.dailyAcc;
trxKumulatifChartData = newData.dailyAccTrx;
}
else if (rangeType.value == 2) {
amtTrendChartData = newData.weekly;
trxTrendChartData = newData.weeklyTrx;
amtKumulatifChartData = newData.weeklyAcc;
trxKumulatifChartData = newData.weeklyAccTrx;
}
else {
amtTrendChartData = newData.monthly;
trxTrendChartData = newData.monthlyTrx;
amtKumulatifChartData = newData.monthlyAcc;
trxKumulatifChartData = newData.monthlyAccTrx;
}
addData(amtTrendChart, amtTrendChartData);
addData(trxTrendChart, trxTrendChartData);
addData(amtKumulatifChart, amtKumulatifChartData);
addData(trxKumulatifChart, trxKumulatifChartData);
}
const formatter = new Intl.DateTimeFormat('id-ID', { dateStyle: 'full', timeStyle: 'medium' });
var today_el = document.getElementById('today');
odtoday = new Odometer({
el: today_el,
value: 0,
format: '(.ddd)',
});
var ytd_el = document.getElementById('ytd');
odytd = new Odometer({
el: ytd_el,
value: 0,
format: '(.ddd)',
});
// var ytd_target = new Odometer({
// el: document.getElementById('ytd_target'),
// value: 0,
// format: '(.ddd)',
// });
var table = $('#table1').DataTable(
{
"destroy": true,
"paging": false,
"searching": false,
"info": false,
"autoWidth": false,
"scrollX": true,
"order": [[0, 'asc']],
"columnDefs": [
{ className: 'text-center', width: "50px", targets: [0] },
{ className: 'text-left', targets: [1] },
{ className: 'text-right', width: "100px", targets: [2, 3, 4], render: $.fn.dataTable.render.number('.', ',', 0, '') },
{ className: 'text-right', width: "100px", targets: [5], render: $.fn.dataTable.render.number('.', ',', 2, '') },
]
}
);
var tableRefresh = function () {
table.clear();
var url = "${url}".replace("/pajak/", "/grid/");
$.get(url, {}, function (data, status) {
if (status === "success") {
console.log(data);
var sum_target = 0;
var sum_realisasi = 0;
var sum_sisa = 0;
var sum_persen = 0;
data.forEach(function (row) {
console.log(row);
table.row.add([
row.kode,
row.nama,
row.target,
row.realisasi,
row.sisa,
row.persen.toFixed(2)
]);
sum_target += row.target;
sum_realisasi += row.realisasi;
sum_sisa += row.sisa;
sum_persen += row.persen;
});
$('#sum_target').html(sum_target.toLocaleString("id-ID"));
$('#sum_realisasi').html(sum_realisasi.toLocaleString("id-ID"));
$('#sum_sisa').html(sum_sisa.toLocaleString("id-ID"));
$('#sum_persen').html((sum_realisasi / sum_target * 100).toFixed(2));
// Update gauge with total values
var gaugePercentage = (sum_realisasi / sum_target * 100);
updateGauge(gaugePercentage, sum_realisasi, sum_target);
// Match panel heights after data load
matchPanelHeights();
table.draw();
} else {
console.log("Request failed.");
table.draw();
}
}).fail(function () {
console.log("Request failed.");
table.draw();
});
}
$.fn.datarefresh = function () {
// console.log("data_refresh");
// console.log("${url}");
$.get("${url}", {}, function (data, status) {
if (status === "success") {
newData = data;
date = new Date(newData.time);
odtoday.update(newData.today);
trx.innerHTML = parseInt(newData.trx).toLocaleString("id-ID");
odytd.update(newData.ytd);
ytdTarget.innerHTML = parseInt(newData.ytdTarget).toLocaleString("id-ID");
ytdPersen.innerHTML = parseFloat(newData.ytdPersen).toFixed(2) + "%";
trxYtd.innerHTML = parseInt(newData.trxYtd).toLocaleString("id-ID");
time.innerHTML = formatter.format(date);//newData.time;
time.style.fontWeight = 'bold';
// removeData(pieChart);
addData(pieChart, newData.pie);
trendChart();
tableRefresh();
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 300000);
} else {
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 60000);
console.log("Request failed.");
}
}).fail(function () {
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 60000);
});
}
</script>
</html>
\ No newline at end of file
<html metal:use-macro="load: eis-base.pt" tal:define="url request.route_url('eis-pcpd-act', act=module);">
<metal:css fill-slot="css_files">
<link rel="stylesheet" href="${home}/eis/static/css/odometer-theme-plaza.css">
<link rel="stylesheet" href="${home}/static/v3/plugin/datatables/1.10/media/css/dataTables.bootstrap.css">
<link href="${home}/eis/static/css/pcpd.css" rel="stylesheet">
</metal:css>
<style metal:fill-slot="styles">
#table1 tbody td:nth-child(3) {
background-color: #f2f2f2;
font-weight: bold;
}
/* Kolom Realisasi */
#table1 tbody td:nth-child(4) {
background-color: #f5f5dc;
font-weight: bold;
}
/* Kolom Selisih */
#table1 tbody td:nth-child(5) {
background-color: #f2f2f2;
font-weight: bold;
}
/* Kolom Persentase */
#table1 tbody td:nth-child(6) {
background-color: #f5f5dc;
font-weight: bold;
}
</style>
<div metal:fill-slot="content">
<!-- Main Title -->
<div class="row">
<div class="col-md-12">
<div class="text-center" style="margin-bottom: 20px; padding: 15px 0;">
<h2 style="margin: 0; font-weight: bold; color: #333; text-transform: uppercase; letter-spacing: 1px;">
LAPORAN REALTIME REALISASI PAJAK DAERAH
</h2>
<h3 style="margin: 5px 0 0; font-weight: bold; color: #cc5200; text-transform: uppercase; letter-spacing: 1px;">
DATA DAN INFORMASI
</h3>
<h4 id="tanggalHariIni" style="margin: 5px 0 0; color: #003399; font-weight: bold;"></h4>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-3 col1">
<img src="${home}/eis/static/pcpd-logo.png" class="img-responsive logo-pcpd" alt="PCPD Logo">
</div>
<div class="col-md-9 col2">
<div class="panel panel-default text-center main-panel uppercase">
<div class="panel-body">
<h1 class="title-panel"><b>${title}</b></h1>
<div class="padding-top-sm">
<h5 id="time">Rab, 4 Jun 2025 - 14:11:05</h5>
</div>
<h4 class="odoometer-head">
<b>Rp.<h4 class="odometer bold" id="today"></h4></b>
</h4>
<h5 class="padding-top-sm"><b><span id="trx"></span> Transaksi</b></h5>
</div>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default text-center">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-money-transfer.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">
Total Realisasi s.d Hari Ini
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container">
<h2 class="primary">
<b>Realisasi Rp. <span class="odometer sub-odometer bold primary" id="ytd">0</span></b>
<p>
Target Rp. <span class=" bold" id="ytdTarget">123</span>
<p>
Persentase <span class="odometer sub-odometer bold primary" id="ytdPersen">
</h2>
<h3 class="primary bold"><span id="trxYtd">0</span> Transaksi</h3>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default hide">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-pie-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Jumlah Transaksi
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center">
<canvas id="chartPie"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/bapend.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Target dan Realisasi per Pajak
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<table class="table table-bordered table-sm" id="table1">
<thead>
<tr>
<th class="align-middle text-center">Kode</th>
<th class="align-middle text-center">Uraian</th>
<th class="text-center">Target</th>
<th class="text-center">Realisasi</th>
<th class="text-center">Selisih</th>
<th class="text-center">%</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class=""></td>
<td class=""></td>
<td class="right">0</td>
<td class="right">0</td>
<td class="right">0</td>
<td class="right">0</td>
</tr>
</tbody>
<tfoot>
<td colspan="2" class="text-right">Jumlah</td>
<td><span id="sum_target"></span></td>
<td><span id="sum_realisasi"></span></td>
<td><span id="sum_sisa"></span></td>
<td><span id="sum_persen"></span></td>
</tfoot>
</table>
</div>
</div>
</div>
<!-- Gauge Chart Section -->
<div class="col-md-4 hide">
<div class="panel panel-default" id="gaugePanel" style="min-height: 500px;">
<div class="panel-heading" style="padding: 10px 15px;">
<h5 class="text-center bold" style="margin: 0;">REALISASI PAJAK DAERAH</h5>
</div>
<div class="panel-body" style="padding: 0; height: calc(100% - 50px); overflow: hidden; display: flex; flex-direction: column;">
<div id="chartContainer" style="flex: 1; display: flex; align-items: center; justify-content: center; margin: 0; padding: 0;">
<canvas id="gaugeChart" width="100%" height="100%"></canvas>
</div>
<div class="text-center" style="padding: 10px; background: rgba(0,0,0,0.02); border-top: 1px solid #ddd;">
<h4 id="gaugePercentage" style="margin: 2px 0; font-weight: bold; color: #333; font-size: 16px;">63.70%</h4>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Realisasi: Rp.<span id="gaugeRealisasi">2.343.460.022.116</span></p>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Target: Rp.<span id="gaugeTarget">3.679.068.431.493</span></p>
</div>
</div>
</div>
</div>
</div>
<hr>
<div class="row hide">
<div class="col-md-2">
<select class="form-control rounded" id="rangeType">
<option value="3">Bulanan</option>
<option value="2">Mingguan</option>
<option value="1">Harian</option>
</select>
</div>
<hr>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-gantt-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Realiasi (Rp)
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartRealisasi"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Realiasi Kumulatif (Rp)
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartKumulatif" width="200" height="200"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-statistics.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Transaksi
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartRealisasiCnt"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-line-chart-icon.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Transaksi Kumulatif
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartKumulatifCnt" width="200" height="200"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<metal:js fill-slot="js_files">
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script> -->
<script src="${home}/eis/static/js/chart.js"></script>
<script src="${home}/eis/static/js/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="${home}/eis/static/js/odometer.js"></script>
<script src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.min.js"></script>
<script src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.ext.js"></script>
</metal:js>
<script metal:fill-slot="scripts">
const today = new Date();
const options = { day: 'numeric', month: 'long', year: 'numeric' };
const tanggalFormat = today.toLocaleDateString('id-ID', options);
document.addEventListener("DOMContentLoaded", function () {
document.getElementById("tanggalHariIni").innerText = "Tanggal, " + tanggalFormat;
});
var pieChart;
var amtTrendChart;
var trxTrendChart;
var amtKumulatifChart;
var trxKumulatifChart;
var gaugeChart;
var newData;
$(document).ready(function () {
var ctx = document.getElementById('chartPie').getContext('2d');
var canvas = document.getElementById('chartPie');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.8;
const pie_data = {
labels: [
'Pajak',
'Retribusi',
],
datasets: [{
data: [300, 100],
backgroundColor: [
'#16a75c', //'rgb(255, 99, 132)',
'#ffb900', // 'rgb(54, 162, 235)'
],
hoverOffset: 4
}]
};
pieChart = new Chart(ctx,
{
type: 'pie',
data: pie_data,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom'
}
}
}
}
);
var ctx = document.getElementById('chartRealisasi').getContext('2d');
var canvas = document.getElementById('chartRealisasi');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
var realisasi_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Realiasi',
data: [100, 50, 300, 250, 100, 150, 2000],
borderColor: '#16a75c',// 'rgb(75, 192, 192)',
backgroundColor: '#16a75c8a',
fill: true,
tension: 0.5
}]
};
amtTrendChart = new Chart(ctx, {
type: 'line',
data: realisasi_data,
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: {
display: false,
drawBorder: false,
}
}
}
}
});
var transaksi_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Transaksi',
data: [100, 50, 300, 250, 100, 150, 2000],
borderColor: '#16a75c',// 'rgb(75, 192, 192)',
backgroundColor: '#16a75c8a',
fill: true,
tension: 0.5
}]
};
var ctx = document.getElementById('chartRealisasiCnt').getContext('2d');
var canvas = document.getElementById('chartRealisasiCnt');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
trxTrendChart = new Chart(ctx, {
type: 'line',
data: transaksi_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
var ctx = document.getElementById('chartKumulatif').getContext('2d');
var canvas = document.getElementById('chartKumulatif');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
var kumulatif_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Kumulatif',
data: [100, 150, 400, 650, 900, 950, 1100],
borderColor: '#ffb900', //'rgb(75, 192, 192)',
backgroundColor: '#debd68ad',
fill: true,
tension: 0.5
}]
};
amtKumulatifChart = new Chart(ctx, {
type: 'line',
data: kumulatif_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
var ctx = document.getElementById('chartKumulatifCnt').getContext('2d');
var canvas = document.getElementById('chartKumulatifCnt');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
trxKumulatifChart = new Chart(ctx, {
type: 'line',
data: kumulatif_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
$("#rangeType").change(function () {
trendChart();
});
// Initialize Gauge Chart
initializeGauge();
$().datarefresh();
});
// Function to match gauge panel height with table panel
function matchPanelHeights() {
var tablePanel = document.querySelector('.col-md-8 .panel');
var gaugePanel = document.getElementById('gaugePanel');
if (tablePanel && gaugePanel) {
var tablePanelHeight = tablePanel.offsetHeight;
gaugePanel.style.height = tablePanelHeight + 'px';
}
}
function initializeGauge() {
var canvas = document.getElementById('gaugeChart');
var ctx = canvas.getContext('2d');
var container = document.getElementById('chartContainer');
// Set canvas size to fill container
function resizeCanvas() {
var containerRect = container.getBoundingClientRect();
var size = Math.min(containerRect.width, containerRect.height);
canvas.width = containerRect.width;
canvas.height = size * 0.7; // Semi-circle height ratio
// Update gauge properties
if (gaugeChart) {
gaugeChart.centerX = canvas.width / 2;
gaugeChart.centerY = canvas.height - 20;
gaugeChart.radius = Math.min(canvas.width * 0.45, canvas.height * 0.65);
gaugeChart.draw();
}
}
// Match panel heights and resize canvas
matchPanelHeights();
setTimeout(resizeCanvas, 100); // Allow DOM to update
gaugeChart = {
canvas: canvas,
ctx: ctx,
centerX: canvas.width / 2,
centerY: canvas.height - 20,
radius: Math.min(canvas.width * 0.45, canvas.height * 0.65),
value: 63.70,
draw: function() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Draw gauge background segments
this.drawSegments();
// Draw scale numbers
this.drawScale();
// Draw needle
this.drawNeedle();
},
drawSegments: function() {
var ctx = this.ctx;
var segments = [
{ start: 0, end: 40, color: '#ff0000' }, // Red (0-40)
{ start: 40, end: 70, color: '#ffff00' }, // Yellow (40-70)
{ start: 70, end: 100, color: '#00ff00' } // Green (70-100)
];
segments.forEach(segment => {
var startAngle = Math.PI + (segment.start / 100) * Math.PI;
var endAngle = Math.PI + (segment.end / 100) * Math.PI;
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, this.radius, startAngle, endAngle);
ctx.lineWidth = Math.max(12, this.radius * 0.08);
ctx.strokeStyle = segment.color;
ctx.stroke();
});
},
drawScale: function() {
var ctx = this.ctx;
ctx.fillStyle = '#000';
ctx.font = Math.max(10, this.radius * 0.08) + 'px Arial';
ctx.textAlign = 'center';
// Draw scale numbers (0, 10, 20, ..., 100)
for (var i = 0; i <= 100; i += 10) {
var angle = Math.PI + (i / 100) * Math.PI;
var labelRadius = this.radius + Math.max(20, this.radius * 0.15);
var x = this.centerX + Math.cos(angle) * labelRadius;
var y = this.centerY + Math.sin(angle) * labelRadius + 5;
ctx.fillText(i.toString(), x, y);
}
},
drawNeedle: function() {
var ctx = this.ctx;
var angle = Math.PI + (this.value / 100) * Math.PI;
ctx.save();
// Draw needle line
ctx.beginPath();
ctx.moveTo(this.centerX, this.centerY);
var needleLength = this.radius - Math.max(8, this.radius * 0.05);
var needleX = this.centerX + Math.cos(angle) * needleLength;
var needleY = this.centerY + Math.sin(angle) * needleLength;
ctx.lineTo(needleX, needleY);
ctx.strokeStyle = '#000';
ctx.lineWidth = Math.max(3, this.radius * 0.02);
ctx.lineCap = 'round';
ctx.stroke();
ctx.restore();
// Draw center circle
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, Math.max(5, this.radius * 0.04), 0, 2 * Math.PI);
ctx.fillStyle = '#000';
ctx.fill();
},
update: function(value) {
this.value = Math.max(0, Math.min(100, value));
this.draw();
}
};
// Initial draw
gaugeChart.draw();
}
function updateGauge(percentage, realisasi, target) {
if (gaugeChart) {
gaugeChart.update(percentage);
}
document.getElementById('gaugePercentage').textContent = percentage.toFixed(2) + '%';
document.getElementById('gaugeRealisasi').textContent = parseInt(realisasi).toLocaleString('id-ID');
document.getElementById('gaugeTarget').textContent = parseInt(target).toLocaleString('id-ID');
}
function addData(chart, data) {
labels = [];
aData = [];
backgroundColor = [];
data.forEach(element => {
labels.push(element[0]);
aData.push(element[1]);
if (element.length > 2)
backgroundColor.push(element[2]);
});
chart.data.labels.length = 0;
chart.data.datasets[0].data.length = 0;
if (backgroundColor.length != 0) {
chart.data.datasets[0].data.backgroundColor = 0;
chart.data.datasets[0].backgroundColor = backgroundColor;
}
chart.data.labels = labels;
chart.data.datasets[0].data = aData;
chart.update();
}
trendChart = function () {
if (rangeType.value == 1) {
amtTrendChartData = newData.daily;
trxTrendChartData = newData.dailyTrx;
amtKumulatifChartData = newData.dailyAcc;
trxKumulatifChartData = newData.dailyAccTrx;
}
else if (rangeType.value == 2) {
amtTrendChartData = newData.weekly;
trxTrendChartData = newData.weeklyTrx;
amtKumulatifChartData = newData.weeklyAcc;
trxKumulatifChartData = newData.weeklyAccTrx;
}
else {
amtTrendChartData = newData.monthly;
trxTrendChartData = newData.monthlyTrx;
amtKumulatifChartData = newData.monthlyAcc;
trxKumulatifChartData = newData.monthlyAccTrx;
}
addData(amtTrendChart, amtTrendChartData);
addData(trxTrendChart, trxTrendChartData);
addData(amtKumulatifChart, amtKumulatifChartData);
addData(trxKumulatifChart, trxKumulatifChartData);
}
const formatter = new Intl.DateTimeFormat('id-ID', { dateStyle: 'full', timeStyle: 'medium' });
var today_el = document.getElementById('today');
odtoday = new Odometer({
el: today_el,
value: 0,
format: '(.ddd)',
});
var ytd_el = document.getElementById('ytd');
odytd = new Odometer({
el: ytd_el,
value: 0,
format: '(.ddd)',
});
// var ytd_target = new Odometer({
// el: document.getElementById('ytd_target'),
// value: 0,
// format: '(.ddd)',
// });
var table = $('#table1').DataTable(
{
"destroy": true,
"paging": false,
"searching": false,
"info": false,
"autoWidth": false,
"scrollX": true,
"order": [[0, 'asc']],
"columnDefs": [
{ className: 'text-center', width: "50px", targets: [0] },
{ className: 'text-left', width: "250px" ,targets: [1] },
{ className: 'text-right', width: "100px", targets: [2, 3, 4], render: $.fn.dataTable.render.number('.', ',', 0, '') },
{ className: 'text-right', width: "100px", targets: [5], render: $.fn.dataTable.render.number('.', ',', 2, '') },
]
}
);
var tableRefresh = function () {
table.clear();
var url = "${url}".replace("/pajak/", "/grid/");
$.get(url, {}, function (data, status) {
if (status === "success") {
console.log(data);
var sum_target = 0;
var sum_realisasi = 0;
var sum_sisa = 0;
var sum_persen = 0;
data.forEach(function (row) {
console.log(row);
table.row.add([
row.kode,
row.nama,
row.target,
row.realisasi,
row.sisa,
row.persen.toFixed(2)
]);
sum_target += row.target;
sum_realisasi += row.realisasi;
sum_sisa += row.sisa;
sum_persen += row.persen;
});
$('#sum_target').html(sum_target.toLocaleString("id-ID"));
$('#sum_realisasi').html(sum_realisasi.toLocaleString("id-ID"));
$('#sum_sisa').html(sum_sisa.toLocaleString("id-ID"));
$('#sum_persen').html((sum_realisasi / sum_target * 100).toFixed(2));
// Update gauge with total values
var gaugePercentage = (sum_realisasi / sum_target * 100);
updateGauge(gaugePercentage, sum_realisasi, sum_target);
// Match panel heights after data load
matchPanelHeights();
table.draw();
} else {
console.log("Request failed.");
table.draw();
}
}).fail(function () {
console.log("Request failed.");
table.draw();
});
}
$.fn.datarefresh = function () {
// console.log("data_refresh");
// console.log("${url}");
$.get("${url}", {}, function (data, status) {
if (status === "success") {
newData = data;
date = new Date(newData.time);
odtoday.update(newData.today);
trx.innerHTML = parseInt(newData.trx).toLocaleString("id-ID");
odytd.update(newData.ytd);
ytdTarget.innerHTML = parseInt(newData.ytdTarget).toLocaleString("id-ID");
ytdPersen.innerHTML = parseFloat(newData.ytdPersen).toFixed(2) + "%";
trxYtd.innerHTML = parseInt(newData.trxYtd).toLocaleString("id-ID");
time.innerHTML = formatter.format(date);//newData.time;
time.style.fontWeight = 'bold';
// removeData(pieChart);
addData(pieChart, newData.pie);
trendChart();
tableRefresh();
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 300000);
} else {
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 60000);
console.log("Request failed.");
}
}).fail(function () {
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 60000);
});
}
</script>
</html>
\ No newline at end of file
<html metal:use-macro="load: eis-base.pt" tal:define="url request.route_url('eis-pcpd-act', act=module);">
<metal:css fill-slot="css_files">
<link rel="stylesheet" href="${home}/eis/static/css/odometer-theme-plaza.css">
<link rel="stylesheet" href="${home}/static/v3/plugin/datatables/1.10/media/css/dataTables.bootstrap.css">
<link href="${home}/eis/static/css/pcpd.css" rel="stylesheet">
</metal:css>
<style metal:fill-slot="styles">
</style>
<div metal:fill-slot="content">
<!-- Main Title -->
<div class="row">
<div class="col-md-12">
<div class="text-center" style="margin-bottom: 20px; padding: 15px 0;">
<h2 style="margin: 0; font-weight: bold; color: #333; text-transform: uppercase; letter-spacing: 1px;">
LAPORAN REALTIME REALISASI PAJAK DAERAH
</h2>
<h3 style="margin: 5px 0 0; font-weight: bold; color: #cc5200; text-transform: uppercase; letter-spacing: 1px;">
DATA DAN INFORMASI
</h3>
<h4 id="tanggalHariIni" style="margin: 5px 0 0; color: #003399; font-weight: bold;"></h4>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-3 col1">
<img src="${home}/eis/static/pcpd-logo.png" class="img-responsive logo-pcpd" alt="PCPD Logo">
</div>
<div class="col-md-9 col2">
<div class="panel panel-default text-center main-panel uppercase">
<div class="panel-body">
<h1 class="title-panel"><b>${title}</b></h1>
<div class="padding-top-sm">
<h5 id="time">Rab, 4 Jun 2025 - 14:11:05</h5>
</div>
<h4 class="odoometer-head">
<b>Rp.<h4 class="odometer bold" id="today"></h4></b>
</h4>
<h5 class="padding-top-sm"><b><span id="trx"></span> Transaksi</b></h5>
</div>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default text-center">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-money-transfer.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">
Total Realisasi s.d Hari Ini
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container">
<h2 class="primary">
<b>Realisasi Rp. <span class="odometer sub-odometer bold primary" id="ytd">0</span></b>
<p>
Target Rp. <span class=" bold" id="ytdTarget">123</span>
<p>
Persentase <span class="odometer sub-odometer bold primary" id="ytdPersen">
</h2>
<h3 class="primary bold"><span id="trxYtd">0</span> Transaksi</h3>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default hide">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-pie-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Jumlah Transaksi
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center">
<canvas id="chartPie"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/bapend.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Target dan Realisasi per Pajak
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<table class="table table-bordered table-sm" id="table1">
<thead>
<tr>
<th class="align-middle text-center">Kode</th>
<th class="align-middle text-center">Uraian</th>
<th class="text-center">Target</th>
<th class="text-center">Realisasi</th>
<th class="text-center">Selisih</th>
<th class="text-center">%</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class=""></td>
<td class=""></td>
<td class="right">0</td>
<td class="right">0</td>
<td class="right">0</td>
<td class="right">0</td>
</tr>
</tbody>
<tfoot>
<td colspan="2" class="text-right">Jumlah</td>
<td><span id="sum_target"></span></td>
<td><span id="sum_realisasi"></span></td>
<td><span id="sum_sisa"></span></td>
<td><span id="sum_persen"></span></td>
</tfoot>
</table>
</div>
</div>
</div>
<!-- Gauge Chart Section -->
<div class="col-md-4">
<div class="panel panel-default" id="gaugePanel" style="min-height: 500px;">
<div class="panel-heading" style="padding: 10px 15px;">
<h5 class="text-center bold" style="margin: 0;">REALISASI PAJAK DAERAH</h5>
</div>
<div class="panel-body" style="padding: 0; height: calc(100% - 50px); overflow: hidden; display: flex; flex-direction: column;">
<div id="chartContainer" style="flex: 1; display: flex; align-items: center; justify-content: center; margin: 0; padding: 0;">
<canvas id="gaugeChart" width="100%" height="100%"></canvas>
</div>
<div class="text-center" style="padding: 10px; background: rgba(0,0,0,0.02); border-top: 1px solid #ddd;">
<h4 id="gaugePercentage" style="margin: 2px 0; font-weight: bold; color: #333; font-size: 16px;">63.70%</h4>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Realisasi: Rp.<span id="gaugeRealisasi">2.343.460.022.116</span></p>
<p style="margin: 1px 0; font-size: 11px; color: #666;">Target: Rp.<span id="gaugeTarget">3.679.068.431.493</span></p>
</div>
</div>
</div>
</div>
</div>
<hr>
<div class="row hide">
<div class="col-md-2">
<select class="form-control rounded" id="rangeType">
<option value="3">Bulanan</option>
<option value="2">Mingguan</option>
<option value="1">Harian</option>
</select>
</div>
<hr>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-gantt-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Realiasi (Rp)
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartRealisasi"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-chart.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Realiasi Kumulatif (Rp)
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartKumulatif" width="200" height="200"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row hide">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-statistics.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Transaksi
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartRealisasiCnt"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<img src="${home}/eis/static/42x42-line-chart-icon.png" class="icon-rounded" alt="" align="left">
<h5 class="text-left bold">Tren Transaksi Kumulatif
<i class="fa fa-info-circle pull-right icon-color"></i>
</h5>
</div>
<div class="panel-body">
<div class="chart-container text-center" style="position: relative;">
<canvas id="chartKumulatifCnt" width="200" height="200"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<metal:js fill-slot="js_files">
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script> -->
<script src="${home}/eis/static/js/chart.js"></script>
<script src="${home}/eis/static/js/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="${home}/eis/static/js/odometer.js"></script>
<script src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.min.js"></script>
<script src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.ext.js"></script>
</metal:js>
<script metal:fill-slot="scripts">
const today = new Date();
const options = { day: 'numeric', month: 'long', year: 'numeric' };
const tanggalFormat = today.toLocaleDateString('id-ID', options);
document.addEventListener("DOMContentLoaded", function () {
document.getElementById("tanggalHariIni").innerText = "Tanggal, " + tanggalFormat;
});
var pieChart;
var amtTrendChart;
var trxTrendChart;
var amtKumulatifChart;
var trxKumulatifChart;
var gaugeChart;
var newData;
$(document).ready(function () {
var ctx = document.getElementById('chartPie').getContext('2d');
var canvas = document.getElementById('chartPie');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.8;
const pie_data = {
labels: [
'Pajak',
'Retribusi',
],
datasets: [{
data: [300, 100],
backgroundColor: [
'#16a75c', //'rgb(255, 99, 132)',
'#ffb900', // 'rgb(54, 162, 235)'
],
hoverOffset: 4
}]
};
pieChart = new Chart(ctx,
{
type: 'pie',
data: pie_data,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom'
}
}
}
}
);
var ctx = document.getElementById('chartRealisasi').getContext('2d');
var canvas = document.getElementById('chartRealisasi');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
var realisasi_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Realiasi',
data: [100, 50, 300, 250, 100, 150, 2000],
borderColor: '#16a75c',// 'rgb(75, 192, 192)',
backgroundColor: '#16a75c8a',
fill: true,
tension: 0.5
}]
};
amtTrendChart = new Chart(ctx, {
type: 'line',
data: realisasi_data,
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: {
display: false,
drawBorder: false,
}
}
}
}
});
var transaksi_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Transaksi',
data: [100, 50, 300, 250, 100, 150, 2000],
borderColor: '#16a75c',// 'rgb(75, 192, 192)',
backgroundColor: '#16a75c8a',
fill: true,
tension: 0.5
}]
};
var ctx = document.getElementById('chartRealisasiCnt').getContext('2d');
var canvas = document.getElementById('chartRealisasiCnt');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
trxTrendChart = new Chart(ctx, {
type: 'line',
data: transaksi_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
var ctx = document.getElementById('chartKumulatif').getContext('2d');
var canvas = document.getElementById('chartKumulatif');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
var kumulatif_data = {
labels: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7',],
datasets: [{
label: 'Tren Kumulatif',
data: [100, 150, 400, 650, 900, 950, 1100],
borderColor: '#ffb900', //'rgb(75, 192, 192)',
backgroundColor: '#debd68ad',
fill: true,
tension: 0.5
}]
};
amtKumulatifChart = new Chart(ctx, {
type: 'line',
data: kumulatif_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
var ctx = document.getElementById('chartKumulatifCnt').getContext('2d');
var canvas = document.getElementById('chartKumulatifCnt');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 3.38;
trxKumulatifChart = new Chart(ctx, {
type: 'line',
data: kumulatif_data,
options: {
responsive: true,
maintainAspectRatio: false,
}
});
$("#rangeType").change(function () {
trendChart();
});
// Initialize Gauge Chart
initializeGauge();
$().datarefresh();
});
// Function to match gauge panel height with table panel
function matchPanelHeights() {
var tablePanel = document.querySelector('.col-md-8 .panel');
var gaugePanel = document.getElementById('gaugePanel');
if (tablePanel && gaugePanel) {
var tablePanelHeight = tablePanel.offsetHeight;
gaugePanel.style.height = tablePanelHeight + 'px';
}
}
function initializeGauge() {
var canvas = document.getElementById('gaugeChart');
var ctx = canvas.getContext('2d');
var container = document.getElementById('chartContainer');
// Set canvas size to fill container
function resizeCanvas() {
var containerRect = container.getBoundingClientRect();
var size = Math.min(containerRect.width, containerRect.height);
canvas.width = containerRect.width;
canvas.height = size * 0.7; // Semi-circle height ratio
// Update gauge properties
if (gaugeChart) {
gaugeChart.centerX = canvas.width / 2;
gaugeChart.centerY = canvas.height - 20;
gaugeChart.radius = Math.min(canvas.width * 0.45, canvas.height * 0.65);
gaugeChart.draw();
}
}
// Match panel heights and resize canvas
matchPanelHeights();
setTimeout(resizeCanvas, 100); // Allow DOM to update
gaugeChart = {
canvas: canvas,
ctx: ctx,
centerX: canvas.width / 2,
centerY: canvas.height - 20,
radius: Math.min(canvas.width * 0.45, canvas.height * 0.65),
value: 63.70,
draw: function() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Draw gauge background segments
this.drawSegments();
this.drawTicks();
// Draw scale numbers
this.drawScale();
// Draw needle
this.drawNeedle();
},
drawSegments: function() {
var ctx = this.ctx;
var segments = [
{ start: 0, end: 40, color: '#ff0000' }, // Red (0-40)
{ start: 40, end: 70, color: '#ffff00' }, // Yellow (40-70)
{ start: 70, end: 100, color: '#00ff00' } // Green (70-100)
];
segments.forEach(segment => {
var startAngle = Math.PI + (segment.start / 100) * Math.PI;
var endAngle = Math.PI + (segment.end / 100) * Math.PI;
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, this.radius, startAngle, endAngle);
ctx.lineWidth = Math.max(12, this.radius * 0.08);
ctx.strokeStyle = segment.color;
ctx.stroke();
});
},
drawTicks: function() {
var ctx = this.ctx;
var innerRadius = this.radius * 0.965;
var outerRadius = this.radius * 0.90;
for (var i = 0; i <= 100; i += 5) { // setiap 5%
var angle = Math.PI + (i / 100) * Math.PI;
var x1 = this.centerX + Math.cos(angle) * innerRadius;
var y1 = this.centerY + Math.sin(angle) * innerRadius;
var x2 = this.centerX + Math.cos(angle) * outerRadius;
var y2 = this.centerY + Math.sin(angle) * outerRadius;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = '#000';
ctx.lineWidth = (i % 10 === 0) ? 2 : 1; // tebal di kelipatan 10
ctx.stroke();
}
},
drawScale: function() {
var ctx = this.ctx;
ctx.fillStyle = '#000';
ctx.font = Math.max(10, this.radius * 0.08) + 'px Arial';
ctx.textAlign = 'center';
// Draw scale numbers (0, 10, 20, ..., 100)
for (var i = 0; i <= 100; i += 10) {
var angle = Math.PI + (i / 100) * Math.PI;
var labelRadius = this.radius + Math.max(20, this.radius * 0.15);
var x = this.centerX + Math.cos(angle) * labelRadius;
var y = this.centerY + Math.sin(angle) * labelRadius + 5;
ctx.fillText(i.toString(), x, y);
}
},
drawNeedle: function() {
var ctx = this.ctx;
var angle = Math.PI + (this.value / 100) * Math.PI;
ctx.save();
// Draw needle line
ctx.beginPath();
ctx.moveTo(this.centerX, this.centerY);
var needleLength = this.radius - Math.max(8, this.radius * 0.05);
var needleX = this.centerX + Math.cos(angle) * needleLength;
var needleY = this.centerY + Math.sin(angle) * needleLength;
ctx.lineTo(needleX, needleY);
ctx.strokeStyle = '#000';
ctx.lineWidth = Math.max(3, this.radius * 0.02);
ctx.lineCap = 'round';
ctx.stroke();
ctx.restore();
// Draw center circle
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, Math.max(5, this.radius * 0.04), 0, 2 * Math.PI);
ctx.fillStyle = '#000';
ctx.fill();
},
update: function(value) {
this.value = Math.max(0, Math.min(100, value));
this.draw();
}
};
// Initial draw
gaugeChart.draw();
}
function updateGauge(percentage, realisasi, target) {
if (gaugeChart) {
gaugeChart.update(percentage);
}
document.getElementById('gaugePercentage').textContent = percentage.toFixed(2) + '%';
document.getElementById('gaugeRealisasi').textContent = parseInt(realisasi).toLocaleString('id-ID');
document.getElementById('gaugeTarget').textContent = parseInt(target).toLocaleString('id-ID');
}
function addData(chart, data) {
labels = [];
aData = [];
backgroundColor = [];
data.forEach(element => {
labels.push(element[0]);
aData.push(element[1]);
if (element.length > 2)
backgroundColor.push(element[2]);
});
chart.data.labels.length = 0;
chart.data.datasets[0].data.length = 0;
if (backgroundColor.length != 0) {
chart.data.datasets[0].data.backgroundColor = 0;
chart.data.datasets[0].backgroundColor = backgroundColor;
}
chart.data.labels = labels;
chart.data.datasets[0].data = aData;
chart.update();
}
trendChart = function () {
if (rangeType.value == 1) {
amtTrendChartData = newData.daily;
trxTrendChartData = newData.dailyTrx;
amtKumulatifChartData = newData.dailyAcc;
trxKumulatifChartData = newData.dailyAccTrx;
}
else if (rangeType.value == 2) {
amtTrendChartData = newData.weekly;
trxTrendChartData = newData.weeklyTrx;
amtKumulatifChartData = newData.weeklyAcc;
trxKumulatifChartData = newData.weeklyAccTrx;
}
else {
amtTrendChartData = newData.monthly;
trxTrendChartData = newData.monthlyTrx;
amtKumulatifChartData = newData.monthlyAcc;
trxKumulatifChartData = newData.monthlyAccTrx;
}
addData(amtTrendChart, amtTrendChartData);
addData(trxTrendChart, trxTrendChartData);
addData(amtKumulatifChart, amtKumulatifChartData);
addData(trxKumulatifChart, trxKumulatifChartData);
}
const formatter = new Intl.DateTimeFormat('id-ID', { dateStyle: 'full', timeStyle: 'medium' });
var today_el = document.getElementById('today');
odtoday = new Odometer({
el: today_el,
value: 0,
format: '(.ddd)',
});
var ytd_el = document.getElementById('ytd');
odytd = new Odometer({
el: ytd_el,
value: 0,
format: '(.ddd)',
});
// var ytd_target = new Odometer({
// el: document.getElementById('ytd_target'),
// value: 0,
// format: '(.ddd)',
// });
var table = $('#table1').DataTable(
{
"destroy": true,
"paging": false,
"searching": false,
"info": false,
"autoWidth": false,
"scrollX": true,
"order": [[0, 'asc']],
"columnDefs": [
{ className: 'text-center', width: "50px", targets: [0] },
{ className: 'text-left', targets: [1] },
{ className: 'text-right', width: "100px", targets: [2, 3, 4], render: $.fn.dataTable.render.number('.', ',', 0, '') },
{ className: 'text-right', width: "100px", targets: [5], render: $.fn.dataTable.render.number('.', ',', 2, '') },
]
}
);
var tableRefresh = function () {
table.clear();
var url = "${url}".replace("/pajak/", "/grid/");
$.get(url, {}, function (data, status) {
if (status === "success") {
console.log(data);
var sum_target = 0;
var sum_realisasi = 0;
var sum_sisa = 0;
var sum_persen = 0;
data.forEach(function (row) {
console.log(row);
table.row.add([
row.kode,
row.nama,
row.target,
row.realisasi,
row.sisa,
row.persen.toFixed(2)
]);
sum_target += row.target;
sum_realisasi += row.realisasi;
sum_sisa += row.sisa;
sum_persen += row.persen;
});
$('#sum_target').html(sum_target.toLocaleString("id-ID"));
$('#sum_realisasi').html(sum_realisasi.toLocaleString("id-ID"));
$('#sum_sisa').html(sum_sisa.toLocaleString("id-ID"));
$('#sum_persen').html((sum_realisasi / sum_target * 100).toFixed(2));
// Update gauge with total values
var gaugePercentage = (sum_realisasi / sum_target * 100);
updateGauge(gaugePercentage, sum_realisasi, sum_target);
// Match panel heights after data load
matchPanelHeights();
table.draw();
} else {
console.log("Request failed.");
table.draw();
}
}).fail(function () {
console.log("Request failed.");
table.draw();
});
}
$.fn.datarefresh = function () {
// console.log("data_refresh");
// console.log("${url}");
$.get("${url}", {}, function (data, status) {
if (status === "success") {
newData = data;
date = new Date(newData.time);
odtoday.update(newData.today);
trx.innerHTML = parseInt(newData.trx).toLocaleString("id-ID");
odytd.update(newData.ytd);
ytdTarget.innerHTML = parseInt(newData.ytdTarget).toLocaleString("id-ID");
ytdPersen.innerHTML = parseFloat(newData.ytdPersen).toFixed(2) + "%";
trxYtd.innerHTML = parseInt(newData.trxYtd).toLocaleString("id-ID");
time.innerHTML = formatter.format(date);//newData.time;
time.style.fontWeight = 'bold';
// removeData(pieChart);
addData(pieChart, newData.pie);
trendChart();
tableRefresh();
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 300000);
} else {
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 60000);
console.log("Request failed.");
}
}).fail(function () {
setTimeout(function () {
console.log("timeout");
$().datarefresh();
}, 60000);
});
}
</script>
</html>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!