<style> #wpBayar { min-width: 600px; max-width: auto; height: 600px; margin: 0 auto; } #wpBayarTable { width: 100% !important; } #wpBayarTable th, #wpLaporTable td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } #wpBayarTable td.dt-body-right { text-align: right; } </style> <?php ini_set('memory_limit', '4096M'); echo 'Initial memory usage: ' . memory_get_usage() . ' bytes' . PHP_EOL; $tahun2 = date('Y'); $rentang_tahun = range($tahun2, 2022); $totalWPBYR = 0; $totalWPBYRTERATUR = 0; $totalJMLWP = 0; foreach ($raporbyr as $row) { $totalWPBYR += $row->WPBYR; $totalWPBYRTERATUR += $row->WPBYRTERATUR; $totalJMLWP += $row->JMLWP; } $nasionalX = ($totalWPBYR / ($totalJMLWP ?: 1)) * 100; $nasionalY = ($totalWPBYRTERATUR / ($totalWPBYR ?: 1)) * 100; $area1Count = 0; // Top right $area2Count = 0; // Top left $area3Count = 0; // Bottom right $area4Count = 0; // Bottom left foreach ($raporbyr as $row) { $x = ($row->WPBYR / ($row->JMLWP ?: 1)) * 100; $y = ($row->WPBYRTERATUR / ($row->WPBYR ?: 1)) * 100; if ($x > $nasionalX && $y > $nasionalY) { $area1Count++; } elseif ($x <= $nasionalX && $y > $nasionalY) { $area2Count++; } elseif ($x > $nasionalX && $y <= $nasionalY) { $area3Count++; } elseif ($x <= $nasionalX && $y <= $nasionalY) { $area4Count++; } } $dataraporkwl = "["; $dataraporkwl .= "{x: " . $nasionalX . ", y: " . $nasionalY . ", z: 2, name: 'Nasional', color: '#000000', jmlwp: " . $totalJMLWP . ", wpbyr: " . $totalWPBYR . ", wpbyrteratur: " . $totalWPBYRTERATUR . "},"; foreach ($raporbyr as $row) { $x = (($row->WPBYR / $row->JMLWP ?: 1)) * 100; $y = (($row->WPBYRTERATUR / $row->WPBYR ?: 1)) * 100; $dd = $row->KWLADM; $dataraporkwl .= "{x: " . $x . ", y: " . $y . ", z: 1, name: '" . addslashes($row->NAMA) . "', drilldown: \"" . $dd . "\", jmlwp: " . $row->JMLWP . ", wpbyr: " . $row->WPBYR . ", wpbyrteratur: " . $row->WPBYRTERATUR . "},"; } $dataraporkwl = rtrim($dataraporkwl, ',') . "]"; $nasionalX = ($totalWPBYR / ($totalJMLWP ?: 1)) * 100; $nasionalY = ($totalWPBYRTERATUR / ($totalWPBYR ?: 1)) * 100; $drilldownSeries = []; // per KPP foreach ($drilldownData['kpp'] as $kwladm => $kpps) { $parentPoint = null; $data = []; foreach ($raporbyr as $row) { if ($row->KWLADM == $kwladm) { $parentPoint = [ 'name' => $row->NAMA, 'x' => ($row->WPBYR / ($row->JMLWP ?: 1)) * 100, 'y' => ($row->WPBYRTERATUR / ($row->WPBYR ?: 1)) * 100, 'color' => '#FF0000', 'dataLabels' => [ 'enabled' => true, 'format' => '{point.name}', 'style' => ['fontWeight' => 'bold'] ], 'jmlwp' => $row->JMLWP, 'wpbyr' => $row->WPBYR, 'wpbyrteratur' => $row->WPBYRTERATUR ]; break; } } if ($parentPoint) { $data[] = $parentPoint; } foreach ($kpps as $kpp) { $data[] = [ 'name' => $kpp['name'], 'x' => $kpp['x'], 'y' => $kpp['y'], 'z' => $kpp['z'], 'drilldown' => (string)$kpp['drilldown'], 'jmlwp' => $kpp['jmlwp'], 'wpbyr' => $kpp['wpbyr'], 'wpbyrteratur' => $kpp['wpbyrteratur'] ]; } $drilldownSeries[] = [ 'id' => (string)$kwladm, 'name' => "KPP in " . $kwladm, 'data' => $data ]; } // per Seksi foreach ($drilldownData['sie'] as $kppadm => $sies) { $parentPoint = null; $data = []; foreach ($raporbyrkpp as $row) { if ($row->KPPADM == $kppadm) { $parentPoint = [ 'name' => $row->NAMA, 'x' => ($row->WPBYR / ($row->JMLWP ?: 1)) * 100, 'y' => ($row->WPBYRTERATUR / ($row->WPBYR ?: 1)) * 100, 'color' => '#00FF00', 'dataLabels' => [ 'enabled' => true, 'format' => '{point.name}', 'style' => ['fontWeight' => 'bold'] ], 'jmlwp' => $row->JMLWP, 'wpbyr' => $row->WPBYR, 'wpbyrteratur' => $row->WPBYRTERATUR ]; break; } } if ($parentPoint) { $data[] = $parentPoint; } foreach ($sies as $sie) { $data[] = [ 'name' => $sie['name'], 'x' => $sie['x'], 'y' => $sie['y'], 'z' => $sie['z'], 'drilldown' => (string)($kppadm . '_' . $sie['drilldown']), 'jmlwp' => $sie['jmlwp'], 'wpbyr' => $sie['wpbyr'], 'wpbyrteratur' => $sie['wpbyrteratur'] ]; } $drilldownSeries[] = [ 'id' => (string)$kppadm, 'name' => "SIE in " . $kppadm, 'data' => $data ]; } // per Pegawai foreach ($drilldownData['peg'] as $key => $pegs) { $parentPoint = null; $data = []; list($kppadm, $kodesie) = explode('_', $key); foreach ($raporbyrsie as $row) { if ($row->KPPADM == $kppadm && $row->KODESIE == $kodesie) { $parentPoint = [ 'name' => $row->NAMA, 'x' => ($row->WPBYR / ($row->JMLWP ?: 1)) * 100, 'y' => ($row->WPBYRTERATUR / ($row->WPBYR ?: 1)) * 100, 'color' => '#0000FF', 'dataLabels' => [ 'enabled' => true, 'format' => '{point.name}', 'style' => ['fontWeight' => 'bold'] ], 'jmlwp' => $row->JMLWP, 'wpbyr' => $row->WPBYR, 'wpbyrteratur' => $row->WPBYRTERATUR ]; break; } } if ($parentPoint) { $data[] = $parentPoint; } foreach ($pegs as $peg) { $data[] = [ 'name' => $peg['name'], 'x' => $peg['x'], 'y' => $peg['y'], 'z' => $peg['z'], 'drilldown' => null, 'jmlwp' => $peg['jmlwp'], 'wpbyr' => $peg['wpbyr'], 'wpbyrteratur' => $peg['wpbyrteratur'] ]; } $drilldownSeries[] = [ 'id' => (string)$key, 'name' => "PEG in " . $key, 'data' => $data ]; } $d['drilldownSeries'] = $drilldownSeries; ?> <div class="main-content"> <div class="container-fluid"> <div class="row"> <div class="col-sm-12 mb-2"> <form class="form-inline" action="<?php base_url('rapor/wpbyr') ?>" method="post"> <label class="my-1 mr-2">Tahun :</label> <select class="custom-select my-1 mr-sm-2" id="tahun" name="tahun"> <?php foreach ($rentang_tahun as $tahun) { if ($tahun == $tahunx) { $sel = "selected"; } else { $sel = ""; } echo "<option value=\"" . $tahun . "\" " . $sel . ">" . $tahun . "</option>"; } ?> </select> <label class="my-1 mr-2">s.d. Bulan :</label> <select class="custom-select my-1 mr-sm-2" id="bulan" name="bulan"> <?php foreach ($refbulan as $rowb) { if ($rowb->KODE == $bulanx) { $isSelected = ' selected="selected"'; } else { $isSelected = ''; } echo "<option value='" . $rowb->KODE . "'" . $isSelected . ">" . ucfirst(strtolower($rowb->NM_PANJANG)) . "</option>"; } ?> </select> <button type="submit" class="btn btn-primary my-1">Proses</button> </form> </div> </div> <div class="row clearfix"> <div class="col-md-12"> <div class="card"> <div class="card-header"> <h3 class="text-center">WP Bayar dan WP Bayar Teratur</h3> <div class="card-header-right"> <ul class="list-unstyled card-option"> <li><i class="ik ik-chevron-left action-toggle"></i></li> <li><i class="ik ik-minus minimize-card"></i></li> <li><i class="ik ik-x close-card"></i></li> </ul> </div> </div> <div class="card-body"> <div id="wpBayar" style="height:600px"></div> </div> </div> </div> </div> <div class="row clearfix"> <div class="col-md-12"> <div class="card"> <div class="card-header"> <h3 class="text-center">Data</h3> <div class="card-header-right"> <ul class="list-unstyled card-option"> <li><i class="ik ik-chevron-left action-toggle"></i></li> <li><i class="ik ik-minus minimize-card"></i></li> <li><i class="ik ik-x close-card"></i></li> </ul> </div> </div> <div class="card-body"> <table class="table table-hover table-striped table-bordered tablesorter" id="wpBayarTable"> <thead class='thead-dark'> <tr class="table-active"> <th class="text-center">No</th> <th class="text-center">Unit</th> <th class="text-center">%WP Bayar</th> <th class="text-center">%WP Bayar Teratur</th> <th class="text-center">Jumlah WP</th> <th class="text-center">WP Bayar <?= $tahunx ?></th> <th class="text-center">WP Bayar Teratur <?= $tahunx ?></th> </tr> </thead> <tbody> <?php $no = 1; $totalJmlWP = 0; $totalWPBayar = 0; $totalWPBayarTeratur = 0; foreach ($raporbyr as $row) { $wpBayarPercentage = ($row->WPBYR / ($row->JMLWP ?: 1)) * 100; $wpBayarTeraturPercentage = ($row->WPBYRTERATUR / ($row->WPBYR ?: 1)) * 100; $totalJmlWP += $row->JMLWP; $totalWPBayar += $row->WPBYR; $totalWPBayarTeratur += $row->WPBYRTERATUR; ?> <tr> <td><?= $no++ ?></td> <td><?= $row->KWLADM ?>-<?= $row->NM_PANJANG ?></td> <td class="text-right"><?= number_format($wpBayarPercentage, 2) ?>%</td> <td class="text-right"><?= number_format($wpBayarTeraturPercentage, 2) ?>%</td> <td class="text-right"><?= number_format($row->JMLWP, 0, ',', '.') ?></td> <td class="text-right"><?= number_format($row->WPBYR, 0, ',', '.') ?></td> <td class="text-right"><?= number_format($row->WPBYRTERATUR, 0, ',', '.') ?></td> </tr> <?php } ?> </tbody> </table> </div> </div> </div> </div> </div> </div> <?php echo view('inc/js.php') ?> <script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script> <link rel="stylesheet" href="https://cdn.datatables.net/1.10.24/css/jquery.dataTables.min.css"> <script> function updateAreaLabels(chart) { var renderer = chart.renderer; var plotLeft = chart.plotLeft; var plotTop = chart.plotTop; var plotWidth = chart.plotWidth; var plotHeight = chart.plotHeight; // Remove existing labels if any if (chart.areaLabels) { chart.areaLabels.forEach(function (label) { label.destroy(); }); } chart.areaLabels = []; // Determine the center point for quadrants var centerX = chart.options.centerPointX; var centerY = chart.options.centerPointY; var level = 'Kanwil'; if (chart.drilldownLevels) { if (chart.drilldownLevels.length === 1) level = 'KPP'; else if (chart.drilldownLevels.length === 2) level = 'Seksi'; else if (chart.drilldownLevels.length === 3) level = 'AR'; } var series = chart.drilldownLevels && chart.drilldownLevels.length > 0 ? chart.series[0] : chart.series[chart.series.length - 1]; var quadrantCounts = [0, 0, 0, 0]; series.points.forEach(function (point) { if (point.x > centerX && point.y > centerY) quadrantCounts[0]++; else if (point.x <= centerX && point.y > centerY) quadrantCounts[1]++; else if (point.x > centerX && point.y <= centerY) quadrantCounts[2]++; else if (point.x < centerX && point.y < centerY) quadrantCounts[3]++; }); var labelStyle = { color: '#FFFFFF', fontWeight: 'bold', fontSize: '12px', padding: 5, borderRadius: 5 }; var labels = [ { text: 'Kuadran 1<br>' + quadrantCounts[0] + ' ' + level, x: plotLeft + plotWidth - 10, y: plotTop + 10, align: 'right', verticalAlign: 'top', color: 'rgba(0, 128, 0, 0.7)' }, { text: 'Kuadran 2<br>' + quadrantCounts[1] + ' ' + level, x: plotLeft + 10, y: plotTop + 10, align: 'left', verticalAlign: 'top', color: 'rgba(255, 165, 0, 0.7)' }, { text: 'Kuadran 3<br>' + quadrantCounts[2] + ' ' + level, x: plotLeft + plotWidth - 10, y: plotTop + plotHeight - 40, align: 'right', verticalAlign: 'bottom', color: 'rgba(255, 165, 0, 0.7)' }, { text: 'Kuadran 4<br>' + quadrantCounts[3] + ' ' + level, x: plotLeft + 10, y: plotTop + plotHeight - 40, align: 'left', verticalAlign: 'bottom', color: 'rgba(255, 0, 0, 0.7)' } ]; labels.forEach(function (labelConfig) { var label = renderer.label(labelConfig.text, labelConfig.x, labelConfig.y) .css(labelStyle) .attr({ align: labelConfig.align, zIndex: 6, padding: 5, r: 5, fill: labelConfig.color, stroke: '#000000', 'stroke-width': 1 }) .add(); chart.areaLabels.push(label); }); } function updatePlotLines(chart, point) { var xAxis = chart.xAxis[0]; var yAxis = chart.yAxis[0]; // Remove existing plotlines xAxis.removePlotLine('wpBayarLine'); yAxis.removePlotLine('wpBayarTeraturLine'); if (point) { // Drilling down - add plotlines for the drilled point xAxis.addPlotLine({ id: 'wpBayarLine', value: point.x, color: 'red', dashStyle: 'dash', width: 1, label: { text: point.name + ' - WP Bayar', align: 'left', style: { color: 'gray' } } }); yAxis.addPlotLine({ id: 'wpBayarTeraturLine', value: point.y, color: 'red', dashStyle: 'dash', width: 1, label: { text: point.name + ' - WP Bayar Teratur', align: 'right', style: { color: 'gray' } } }); } else { // Top level - add national plotlines xAxis.addPlotLine({ id: 'wpBayarLine', value: <?php echo $nasionalX; ?>, color: 'red', dashStyle: 'dash', width: 1, label: { text: 'WP Bayar - Nasional', align: 'left', style: { color: 'gray' } } }); yAxis.addPlotLine({ id: 'wpBayarTeraturLine', value: <?php echo $nasionalY; ?>, color: 'red', dashStyle: 'dash', width: 1, label: { text: 'WP Bayar Teratur - Nasional', align: 'right', style: { color: 'gray' } } }); } chart.options.centerPointX = point ? point.x : <?php echo $nasionalX; ?>; chart.options.centerPointY = point ? point.y : <?php echo $nasionalY; ?>; } function updateTable(data) { var table = $('#wpBayarTable').DataTable(); table.clear(); data.forEach(function (point) { var wpBayarPercentage = (point.wpbyr / (point.jmlwp || 1)) * 100; var wpBayarTeraturPercentage = (point.wpbyrteratur / (point.wpbyr || 1)) * 100; table.row.add([ '', point.name, wpBayarPercentage.toFixed(2) + '%', wpBayarTeraturPercentage.toFixed(2) + '%', point.jmlwp.toLocaleString('id-ID'), point.wpbyr.toLocaleString('id-ID'), point.wpbyrteratur.toLocaleString('id-ID') ]); }); table.draw(); table.order([2, 'desc']).draw(); } function updateTableFromChart(chart) { var currentSeries = chart.series[0]; var data = currentSeries.options.data; updateTable(data); } function updateChartElements(chart) { var currentPoint = null; if (chart.drilldownLevels && chart.drilldownLevels.length > 0) { currentPoint = chart.drilldownLevels[chart.drilldownLevels.length - 1].lowerSeries.points[0]; } updatePlotLines(chart, currentPoint); updateAreaLabels(chart); } Highcharts.chart('wpBayar', { chart: { type: 'scatter', plotBorderWidth: 1, zoomType: 'xy', panning: true, panKey: 'shift', events: { load: function () { updateChartElements(this) }, render: function () { updateChartElements(this); }, drilldown: function (e) { var chart = this; chart.options.centerPointX = e.point.x; chart.options.centerPointY = e.point.y; setTimeout(function () { updateTableFromChart(chart); }, 100); }, drillup: function () { var chart = this; chart.options.centerPointX = <?php echo $nasionalX; ?>; chart.options.centerPointY = <?php echo $nasionalY; ?>; setTimeout(function () { updateTableFromChart(chart); }, 100); } }, }, legend: { enabled: false }, title: { text: '' }, credits: { enabled: false }, accessibility: { point: { valueDescriptionFormat: '{index}. {point.name}, WPbayar: {point.x}%, WPBayarT: {point.y}%, index: {point.z}%.' } }, xAxis: { gridLineWidth: 1, type: 'logarithmic', title: { text: 'WP Bayar' }, labels: { format: '{value:.2f}%' }, accessibility: { rangeDescription: 'Range: 0 to 100 %.' }, crosshair: { snap: false } }, yAxis: { startOnTick: false, endOnTick: false, type: 'logarithmic', title: { text: 'WP Bayar Teratur' }, labels: { format: '{value:.2f}%' }, maxPadding: 0.2, accessibility: { rangeDescription: 'Range: 0 to 100 persen.' }, crosshair: { snap: false } }, tooltip: { useHTML: true, headerFormat: '<table style="width:100%; text-align:justify;">', pointFormatter: function () { return '<tr><th colspan="2" style="text-align:center; font-size: 20px; padding-bottom: 5px;">' + this.name + '</th></tr>' + '<tr><td style="font-size: 14px; padding-right: 10px;">%WP Bayar:</td><td style="font-size: 14px; text-align: right;">' + Highcharts.numberFormat(this.x, 2) + '%</td></tr>' + '<tr><td style="font-size: 14px; padding-right: 10px;">%WP Bayar Teratur:</td><td style="font-size: 14px; text-align: right;">' + Highcharts.numberFormat(this.y, 2) + '%</td></tr>' + '<tr><td style="font-size: 14px; padding-right: 10px;">Jumlah WP:</td><td style="font-size: 14px; text-align: right;">' + Highcharts.numberFormat(this.jmlwp, 0, '.', ',') + '</td></tr>' + '<tr><td style="font-size: 14px; padding-right: 10px;">WP Bayar:</td><td style="font-size: 14px; text-align: right;">' + Highcharts.numberFormat(this.wpbyr, 0, '.', ',') + '</td></tr>' + '<tr><td style="font-size: 14px; padding-right: 10px;">WP Bayar Teratur:</td><td style="font-size: 14px; text-align: right;">' + Highcharts.numberFormat(this.wpbyrteratur, 0, '.', ',') + '</td></tr>'; }, footerFormat: '</table>', followPointer: true, style: { fontSize: '14px' }, backgroundColor: 'rgba(255, 255, 255, 0.9)', borderWidth: 1, borderColor: '#AAA', borderRadius: 5, padding: 10 }, plotOptions: { series: { dataLabels: { enabled: true, format: '{point.name}', allowOverlap: true } } }, series: [{ data: <?php echo $dataraporkwl; ?>, colorByPoint: true, point: { events: { click: function () { if (this.name === 'Nasional') { return false; } } } } }], drilldown: { activeDataLabelStyle: { color: '#FFFFFF', textDecoration: 'none', textOutline: '1px #000000' }, series: <?php echo json_encode($drilldownSeries); ?>, breadcrumbs: {showFullPath: false} }, }); console.log('Main series data:', <?php echo $dataraporkwl; ?>); console.log('Drilldown series:', <?php echo json_encode($drilldownSeries, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT); ?>); $(document).ready(function () { var table = $('#wpBayarTable').DataTable({ "order": [[2, "desc"]], // Sort by %WP Bayar (3rd column) in descending order "columnDefs": [ { "searchable": false, "orderable": false, "targets": 0, "width": "5%", "className": "dt-body-right" }, { "type": "formatted-num", "targets": [2, 3], "width": "15%", "className": "dt-body-right", "render": function (data, type, row) { if (type === 'sort') { return parseFloat(data.replace(/[\.%,]/g, '')); } return data; } }, { "type": "formatted-num", "targets": [4, 5, 6], "width": "15%", "className": "dt-body-right", "render": function (data, type, row) { if (type === 'sort') { return parseFloat(data.replace(/[\.%,]/g, '')); } if (type === 'display') { return data.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); } return data; } } ], "paging": false, // Remove pagination "info": false, // Remove "Showing X to Y of Z entries" "searching": false, // Remove search functionality "language": { "decimal": ",", "thousands": "." } }); table.on('order.dt', function () { table.column(0, {search: 'applied', order: 'applied'}).nodes().each(function (cell, i) { cell.innerHTML = i + 1; }); }).draw(); }); </script>