Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
simpmw
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Alfiro Pratama
simpmw
Commits
6e11c3af
Commit
6e11c3af
authored
Oct 15, 2025
by
Alfiro Pratama
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Chart PMW per Fakultas
parent
2b7759b3
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
516 additions
and
7 deletions
+516
-7
app/Helpers/InseoHelper.php
+1
-0
app/Http/Controllers/DashboardController.php
+133
-2
app/Models/DaftarProposal.php
+1
-1
app/Models/DaftarProposalMonev.php
+2
-2
resources/views/backend/index.blade.php
+377
-1
routes/web.php
+2
-1
No files found.
app/Helpers/InseoHelper.php
View file @
6e11c3af
...
@@ -90,6 +90,7 @@ class InseoHelper
...
@@ -90,6 +90,7 @@ class InseoHelper
'psikologi'
=>
'FP'
,
'psikologi'
=>
'FP'
,
'hukum'
=>
'FH'
,
'hukum'
=>
'FH'
,
'ilmu hukum'
=>
'FH'
,
'kampus unesa magetan'
=>
'PSDKU Magetan'
,
'kampus unesa magetan'
=>
'PSDKU Magetan'
,
];
];
...
...
app/Http/Controllers/DashboardController.php
View file @
6e11c3af
...
@@ -2,8 +2,17 @@
...
@@ -2,8 +2,17 @@
namespace
App\Http\Controllers
;
namespace
App\Http\Controllers
;
use
App\Models\DaftarProposal
;
use
App\Models\DaftarProposalMonev
;
use
App\Models\Jenis
;
use
App\Models\JenisMonev
;
use
App\Models\MonevInternal
;
use
App\Models\Pengumuman
;
use
App\Models\Pengumuman
;
use
App\Models\Periode
;
use
App\Models\Proposal
;
use
Illuminate\Http\Request
;
use
Illuminate\Http\Request
;
use
Illuminate\Support\Facades\DB
;
use
Illuminate\Support\Facades\Log
;
class
DashboardController
extends
Controller
class
DashboardController
extends
Controller
{
{
...
@@ -16,14 +25,136 @@ class DashboardController extends Controller
...
@@ -16,14 +25,136 @@ class DashboardController extends Controller
{
{
//
//
$title
=
'Dashboard PMW'
;
$title
=
'Dashboard PMW'
;
// $pengumuman = $pengumuman = Pengumuman::query()->first();
$pengumuman
=
$pengumuman
=
Pengumuman
::
query
()
->
where
(
'status'
,
1
)
->
first
();
$tahun
=
Periode
::
orderBy
(
'nama'
,
'ASC'
)
->
get
();
$jenis
=
Jenis
::
where
(
'status_hapus'
,
0
)
->
whereNotNull
(
'nama'
)
->
orderBy
(
'nama'
,
'ASC'
)
->
get
();
$proposal
=
DaftarProposal
::
all
();
$jenis_monev
=
JenisMonev
::
where
(
'status_hapus'
,
0
)
->
get
();
$monev
=
DaftarProposalMonev
::
where
(
'status_hapus'
,
0
)
->
get
();
$fakultas
=
DB
::
connection
(
'siakadu'
)
->
table
(
'sms'
)
->
whereNull
(
'id_induk_sms'
)
->
whereNull
(
'kode_prodi'
)
->
get
();
$data
=
[
$data
=
[
'title'
=>
$title
,
'title'
=>
$title
,
'pengumuman'
=>
null
,
'pengumuman'
=>
$pengumuman
,
'tahun'
=>
$tahun
,
'jenis'
=>
$jenis
,
'proposal'
=>
$proposal
,
'tahap'
=>
$jenis_monev
,
'monev'
=>
$monev
,
'fakultas'
=>
$fakultas
,
];
];
return
view
(
'backend.index'
,
$data
);
return
view
(
'backend.index'
,
$data
);
}
}
public
function
getChartData
(
Request
$request
)
{
try
{
$jenis_id
=
$request
->
get
(
'reqJenisPmw'
);
$tahap
=
$request
->
get
(
'reqStatus'
);
$tahun
=
$request
->
get
(
'tahun'
);
// Debug: log received parameters
Log
::
info
(
'Chart data request parameters:'
,
[
'jenis_id'
=>
$jenis_id
,
'tahap'
=>
$tahap
,
'tahun'
=>
$tahun
]);
// 1️⃣ Ambil semua fakultas (sekali saja)
$fakultas
=
DB
::
connection
(
'siakadu'
)
->
table
(
'sms'
)
->
select
(
'id_sms'
,
'nm_lemb'
)
->
whereNull
(
'id_induk_sms'
)
->
whereNull
(
'kode_prodi'
)
->
where
(
'nm_lemb'
,
'!='
,
'FPS'
)
->
orderBy
(
'nm_lemb'
,
'ASC'
)
->
get
()
->
map
(
function
(
$item
)
{
if
(
strtolower
(
$item
->
nm_lemb
)
===
'vokasi'
)
{
$item
->
nm_lemb
=
'VOKASI'
;
}
if
(
strtolower
(
$item
->
nm_lemb
)
===
'kedokteran'
)
{
$item
->
nm_lemb
=
'FK'
;
}
if
(
strtolower
(
$item
->
nm_lemb
)
===
'fpsi'
)
{
$item
->
nm_lemb
=
'FP'
;
}
if
(
strtolower
(
$item
->
nm_lemb
)
===
'psdku'
)
{
$item
->
nm_lemb
=
"PSDKU
\n
Magetan"
;
}
return
$item
;
})
->
sortBy
(
function
(
$item
)
{
$urutanKhusus
=
[
'VOKASI'
=>
1
,
"PSDKU
\n
Magetan"
=>
2
,
'FK'
=>
3
,
'FKP'
=>
4
,
];
$rank
=
$urutanKhusus
[
$item
->
nm_lemb
]
??
0
;
return
sprintf
(
'%02d_%s'
,
$rank
,
$item
->
nm_lemb
);
})
->
values
();
// 2️⃣ Query proposal per fakultas (1 query saja)
$proposalQuery
=
DaftarProposal
::
select
(
'fakultas_ketua'
,
DB
::
raw
(
'COUNT(*) as total'
))
->
where
(
'status_hapus'
,
0
)
->
when
(
$jenis_id
,
fn
(
$q
)
=>
$q
->
where
(
'jenis_id'
,
$jenis_id
))
->
when
(
$tahun
,
fn
(
$q
)
=>
$q
->
where
(
'periode'
,
$tahun
))
->
when
(
$tahap
===
'proposal'
,
fn
(
$q
)
=>
$q
)
// Only show proposal data when tahap is 'proposal'
->
when
(
$tahap
&&
$tahap
!==
'proposal'
,
fn
(
$q
)
=>
$q
->
whereRaw
(
'1 = 0'
))
// Hide proposal data for other tahap
->
groupBy
(
'fakultas_ketua'
)
->
get
()
->
pluck
(
'total'
,
'fakultas_ketua'
);
// 3️⃣ Query Monev 1 (1 query)
$monev1Query
=
DaftarProposalMonev
::
select
(
'fakultas_ketua'
,
DB
::
raw
(
'COUNT(*) as total'
))
->
where
(
'jenis_monev_desc'
,
'Monev Internal I'
)
->
where
(
'status_hapus'
,
0
)
->
when
(
$jenis_id
,
fn
(
$q
)
=>
$q
->
where
(
'jenis_id'
,
$jenis_id
))
->
when
(
$tahun
,
fn
(
$q
)
=>
$q
->
where
(
'periode'
,
$tahun
))
->
when
(
$tahap
===
'monev1'
,
fn
(
$q
)
=>
$q
)
// Only show monev1 data when tahap is 'monev1'
->
when
(
$tahap
&&
$tahap
!==
'monev1'
,
fn
(
$q
)
=>
$q
->
whereRaw
(
'1 = 0'
))
// Hide monev1 data for other tahap
->
groupBy
(
'fakultas_ketua'
)
->
get
()
->
pluck
(
'total'
,
'fakultas_ketua'
);
// 4️⃣ Query Monev 2 (1 query)
$monev2Query
=
DaftarProposalMonev
::
select
(
'fakultas_ketua'
,
DB
::
raw
(
'COUNT(*) as total'
))
->
where
(
'jenis_monev_desc'
,
'Monev Internal II'
)
->
where
(
'status_hapus'
,
0
)
->
when
(
$jenis_id
,
fn
(
$q
)
=>
$q
->
where
(
'jenis_id'
,
$jenis_id
))
->
when
(
$tahun
,
fn
(
$q
)
=>
$q
->
where
(
'periode'
,
$tahun
))
->
when
(
$tahap
===
'monev2'
,
fn
(
$q
)
=>
$q
)
// Only show monev2 data when tahap is 'monev2'
->
when
(
$tahap
&&
$tahap
!==
'monev2'
,
fn
(
$q
)
=>
$q
->
whereRaw
(
'1 = 0'
))
// Hide monev2 data for other tahap
->
groupBy
(
'fakultas_ketua'
)
->
get
()
->
pluck
(
'total'
,
'fakultas_ketua'
);
// 5️⃣ Gabungkan data
$chartData
=
$fakultas
->
map
(
function
(
$f
)
use
(
$proposalQuery
,
$monev1Query
,
$monev2Query
)
{
$namaFak
=
$f
->
nm_lemb
;
return
[
'fakultas'
=>
$namaFak
,
'proposal'
=>
$proposalQuery
[
$namaFak
]
??
0
,
'monev1'
=>
$monev1Query
[
$namaFak
]
??
0
,
'monev2'
=>
$monev2Query
[
$namaFak
]
??
0
,
];
});
return
response
()
->
json
(
$chartData
);
}
catch
(
\Throwable
$e
)
{
Log
::
error
([
'error'
=>
true
,
'message'
=>
$e
->
getMessage
(),
'line'
=>
$e
->
getLine
(),
'file'
=>
$e
->
getFile
(),
]);
return
response
()
->
json
([
'error'
=>
'Terjadi kesalahan saat mengambil data chart.'
],
500
);
}
}
}
}
app/Models/DaftarProposal.php
View file @
6e11c3af
...
@@ -12,7 +12,7 @@ class DaftarProposal extends Model
...
@@ -12,7 +12,7 @@ class DaftarProposal extends Model
protected
$keyType
=
'string'
;
protected
$keyType
=
'string'
;
protected
$fillable
=
[
protected
$fillable
=
[
'proposal_id'
,
'jenis_id'
,
'kode'
,
'jenis_pkm'
,
'judul'
,
'status'
,
'status_hapus'
,
'status_administrasi_1'
,
'status_administrasi_2'
,
'reviewer_id_1'
,
'reviewer_id_2'
,
'status_final'
,
'nidn_reviewer_id_1'
,
'nidn_reviewer_id_2'
,
'upload_dokumen'
,
'date_upload'
,
'date_approval'
,
'identitas_ketua'
,
'identitas_dospem'
,
'periode'
,
'url'
'proposal_id'
,
'jenis_id'
,
'kode'
,
'jenis_pkm'
,
'judul'
,
'status'
,
'status_hapus'
,
'status_administrasi_1'
,
'status_administrasi_2'
,
'reviewer_id_1'
,
'reviewer_id_2'
,
'status_final'
,
'nidn_reviewer_id_1'
,
'nidn_reviewer_id_2'
,
'upload_dokumen'
,
'date_upload'
,
'date_approval'
,
'identitas_ketua'
,
'identitas_dospem'
,
'periode'
,
'url'
,
'fakultas'
,
];
];
public
function
rKelompokDetil
()
public
function
rKelompokDetil
()
...
...
app/Models/DaftarProposalMonev.php
View file @
6e11c3af
...
@@ -12,9 +12,9 @@ class DaftarProposalMonev extends Model
...
@@ -12,9 +12,9 @@ class DaftarProposalMonev extends Model
protected
$fillable
=
[
protected
$fillable
=
[
'monev_internal_id'
,
'proposal_id'
,
'jenis_monev_id'
,
'kode'
,
'judul'
,
'monev_internal_id'
,
'proposal_id'
,
'jenis_monev_id'
,
'kode'
,
'judul'
,
'jenis_pkm'
,
'jenis_monev'
,
'status'
,
'status_administrasi_1'
,
'status_administrasi_2'
,
'jenis_pkm'
,
'jenis_monev'
,
'
jenis_monev_desc'
,
'
status'
,
'status_administrasi_1'
,
'status_administrasi_2'
,
'nilai_1'
,
'nilai_2'
,
'reviewer_komentar_1'
,
'reviewer_komentar_2'
,
'reviewer_monev_id_1'
,
'nilai_1'
,
'nilai_2'
,
'reviewer_komentar_1'
,
'reviewer_komentar_2'
,
'reviewer_monev_id_1'
,
'reviewer_monev_id_2'
,
'reviewer_id_1'
,
'reviewer_id_2'
,
'kelompok_id'
'reviewer_monev_id_2'
,
'reviewer_id_1'
,
'reviewer_id_2'
,
'kelompok_id'
,
'fakultas_ketua'
,
'status_hapus'
,
'status'
,
'periode'
,
// 'proposal_id', 'reviewer_monev_id', 'jenis_id', 'kode', 'jenis_pkm', 'judul', 'status', 'status_administrasi_1', 'status_administrasi_2', 'nilai_1', 'nilai_2', 'reviewer_monev_id_1', 'reviewer_monev_id_1', 'status_final'
// 'proposal_id', 'reviewer_monev_id', 'jenis_id', 'kode', 'jenis_pkm', 'judul', 'status', 'status_administrasi_1', 'status_administrasi_2', 'nilai_1', 'nilai_2', 'reviewer_monev_id_1', 'reviewer_monev_id_1', 'status_final'
];
];
...
...
resources/views/backend/index.blade.php
View file @
6e11c3af
...
@@ -11,10 +11,47 @@
...
@@ -11,10 +11,47 @@
</div>
</div>
@endsection
@endsection
@section('css')
<style>
.btn-fakultas {
background: none;
border: none;
color: #007bff;
font-weight: 600;
cursor: pointer;
padding: 4px 8px;
transition: all 0.2s ease-in-out;
border-radius: 8px;
}
.btn-fakultas:hover {
background: #007bff;
color: white;
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
.tooltip-fakultas {
position: absolute;
background: white;
border: 1px solid #ccc;
border-radius: 8px;
padding: 8px 12px;
font-size: 13px;
display: none;
z-index: 9999;
pointer-events: none;
max-width: 220px;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
transition: opacity 0.15s ease-in-out;
}
</style>
@endsection
@section('contents')
@section('contents')
@php
@php
$menu
= 'dashboard';
$menu
= 'dashboard';
@endphp
@endphp
<!-- start page title -->
<!-- start page title -->
<div class="
page
-
title
-
box
">
<div class="
page
-
title
-
box
">
...
@@ -41,10 +78,349 @@
...
@@ -41,10 +78,349 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div class="
col
-
lg
-
12
">
<div class="
card
">
<div class="
card
-
body
">
<div class="
row
">
<div class="
col
-
12
col
-
lg
-
4
col
-
md
-
4
col
-
sm
-
12
">
<div class="
row
">
<label class="
col
-
sm
-
3
col
-
form
-
label
">Kategori : </label>
<div class="
col
-
sm
-
6
">
<select class="
form
-
select
select2
" name="
reqJenisPmw
" id="
reqJenisPmw
">
<option value="">Semua</option>
@foreach (
$jenis
as
$item
)
<option value="
{{
$item
->
jenis_id
}}
">{{
$item->nama
}}</option>
@endforeach
</select>
</div>
</div>
</div>
<div class="
col
-
12
col
-
lg
-
4
col
-
md
-
4
col
-
sm
-
12
">
<div class="
row
">
<label class="
col
-
sm
-
3
col
-
form
-
label
">Tahap : </label>
<div class="
col
-
sm
-
6
">
<select class="
form
-
select
select2
" name="
reqStatus
" id="
reqStatus
">
<option value="">Semua</option>
<option value="
proposal
">Proposal</option>
{{-- <option value="
internal
">Seleksi Internal</option> --}}
<option value="
monev1
">Monev Internal I</option>
<option value="
monev2
">Monev Internal II</option>
</select>
</div>
</div>
</div>
<div class="
col
-
12
col
-
lg
-
4
col
-
md
-
4
col
-
sm
-
12
">
<div class="
row
">
<label class="
col
-
sm
-
3
col
-
form
-
label
">Tahun : </label>
<div class="
col
-
sm
-
6
">
<select class="
form
-
select
select2
" name="
tahun
" id="
tahun
">
<option value="">Semua</option>
@foreach (
$tahun
as
$item
)
<option value="
{{
$item
->
nama
}}
" {{
$item->nama
== date('Y') ? 'selected' : '' }}>
{{
$item->nama
}}</option>
@endforeach
</select>
{{-- <select class="
form
-
select
select2
" name="
reqTahun
" id="
reqTahun
">
<option value="
0
">Semua</option>
@foreach (
$periode
as
$res
)
<option value="
{{
$res
->
nama
}}
">{{
$res->nama
}}</option>
@endforeach
</select> --}}
</div>
</div>
</div>
</div>
</div>
@if (Auth::user()->hasrole(['operator']))
<div class="
card
-
body
">
<div class="
card
-
title
card
-
title
-
grafik
">
<h4>Grafik Data PMW Per Fakultas</h4>
</div>
<div class="
row
">
<div class="
col
-
12
">
<div id="
chartLoading
" class="
shadow
rounded
-
pill
col
-
3
mx
-
auto
p
-
3
text
-
center
my
-
4
" style="
display
:
none
;
">
{{-- <div class="
shadow
rounded
border
col
-
3
mx
-
auto
p
-
3
text
-
center
py
-
4
"> --}}
<div class="
spinner
-
border
text
-
primary
" role="
status
"></div>
<p class="
mt
-
2
mb
-
0
d
-
none
d
-
lg
-
block
">Memuat data grafik...</p>
{{-- </div> --}}
</div>
<canvas id="
chartFakultas
" style="
min
-
height
:
400
px
;
display
:
none
;
"></canvas>
</div>
</div>
<div class="
row
mt
-
3
">
<div class="
col
-
12
">
<div class="
alert
alert
-
info
">
<i class="
mdi
mdi
-
information
-
outline
me
-
2
"></i>
<strong>Petunjuk:</strong> Klik pada bar chart untuk memfilter data berdasarkan fakultas tertentu.
</div>
</div>
</div>
</div>
@endif
</div>
</div>
{{-- <div class="
col
-
lg
-
12
">
<div class="
card
">
</div>
</div> --}}
</div>
</div>
@endsection
@endsection
@section('js')
@section('js')
@if (Auth::user()->hasrole(['operator']))
{{-- <script src="
{{
asset
(
'theme/libs/chart.js/Chart.min.js'
)
}}
"></script> --}}
<script src="
https
://
cdn
.
jsdelivr
.
net
/
npm
/
chart
.
js
"></script>
<script>
let chartInstance = null;
let fullData = [];
@endsection
async function loadChart() {
const spinner = document.getElementById('chartLoading');
const canvas = document.getElementById('chartFakultas');
try {
// Tampilkan spinner, sembunyikan canvas
spinner.style.display = 'block';
canvas.style.display = 'none';
// Ambil nilai filter
const kategori = document.getElementById('reqJenisPmw').value;
const tahap = document.getElementById('reqStatus').value;
const tahun = document.getElementById('tahun').value;
// Buat URL dengan parameter filter
const url = new URL("
{{
route
(
'dashboard.chart-data'
)
}}
", window.location.origin);
if (kategori) url.searchParams.append('reqJenisPmw', kategori);
if (tahap) url.searchParams.append('reqStatus', tahap);
if (tahun) url.searchParams.append('tahun', tahun);
// Debug: log filter parameters
// console.log('Filter parameters:', { kategori, tahap, tahun });
// console.log('Request URL:', url.toString());
// Timeout 3 detik agar loading tidak terlalu lama
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3000);
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeout);
if (!response.ok) throw new Error('Gagal mengambil data');
const data = await response.json();
// Validasi format data
if (!Array.isArray(data) || !data.length || !data[0].fakultas) {
throw new Error('Format data tidak sesuai');
}
const labels = data.map(item => {
// Handle multi-line labels for Chart.js
let label = item.fakultas;
if (label.includes('
\n
')) {
label = label.split('
\n
');
}
// Change FP to FPsi for display only
if (Array.isArray(label)) {
return label.map(line => line === 'FP' ? 'FPsi' : line);
} else {
return label === 'FP' ? 'FPsi' : label;
}
});
const proposalData = data.map(item => item.proposal);
const monev1Data = data.map(item => item.monev1);
const monev2Data = data.map(item => item.monev2);
const ctx = document.getElementById('chartFakultas').getContext('2d');
// const { labels, proposalData, monev1Data, monev2Data } = data;
// Hapus chart lama jika ada
if (window.chartFakultasInstance) {
window.chartFakultasInstance.destroy();
}
// Buat chart baru
window.chartFakultasInstance = new Chart(ctx, {
type: 'bar',
data: {
labels,
datasets: [
{ label: 'Proposal', data: proposalData, backgroundColor: 'rgba(54, 162, 235, 0.8)' },
{ label: 'Monev Internal I', data: monev1Data, backgroundColor: 'rgba(255, 206, 86, 0.8)' },
{ label: 'Monev Internal II', data: monev2Data, backgroundColor: 'rgba(255, 99, 132, 0.8)' },
]
},
options: {
responsive: true,
animation: { duration: 1000, easing: 'easeOutQuart' },
plugins: {
legend: {
position: 'top',
labels: { padding: 32, cursor: 'pointer' },
onHover: (e) => e.native.target.style.cursor = 'pointer',
onLeave: (e) => e.native.target.style.cursor = 'default'
},
title: {
display: true,
text: 'Jumlah Data Proposal & Monev Internal per Fakultas',
font: { size: 16 }
}
},
scales: {
x: {
ticks: {
maxRotation: 0,
minRotation: 0
}
},
y: {
beginAtZero: true,
ticks: { stepSize: 50 }
}
}
}
});
// ✅ Simpan data penuh agar bisa difilter nanti
fullData = data;
// ✅ Tambahkan event klik label fakultas di bawah chart (area sumbu X)
canvas.addEventListener('click', function (event) {
const chart = window.chartFakultasInstance;
const xAxis = chart.scales.x;
const yAxis = chart.scales.y;
const x = event.offsetX;
const y = event.offsetY;
// Pastikan klik di area label bawah
if (y > yAxis.bottom && y < yAxis.bottom + 30) {
const labelIndex = Math.floor(
((x - xAxis.left) / (xAxis.right - xAxis.left)) * chart.data.labels.length
);
const fakultas = Array.isArray(chart.data.labels[labelIndex])
? chart.data.labels[labelIndex].join(' ')
: chart.data.labels[labelIndex];
if (!fakultas) return;
// Toggle filter: jika sudah difilter, klik lagi untuk tampilkan semua
const isFiltered = chart.data.labels.length === 1 && chart.data.labels[0] === fakultas;
const filtered = isFiltered
? fullData
: fullData.filter(d =>
(Array.isArray(d.fakultas) ? d.fakultas.join(' ') : d.fakultas) === fakultas
);
chart.data.labels = filtered.map(d => d.fakultas.includes('
\n
') ? d.fakultas.split('
\n
') : d.fakultas);
chart.data.datasets[0].data = filtered.map(d => d.proposal);
chart.data.datasets[1].data = filtered.map(d => d.monev1);
chart.data.datasets[2].data = filtered.map(d => d.monev2);
chart.update();
}
});
// Sembunyikan spinner, tampilkan chart
spinner.style.display = 'none';
canvas.style.display = 'block';
let labelTooltip = document.createElement('div');
labelTooltip.className = 'tooltip-fakultas shadow';
labelTooltip.style.display = 'none';
document.body.appendChild(labelTooltip);
// event listener untuk mendeteksi hover di atas tick label
canvas.addEventListener('mousemove', function (event) {
const chart = window.chartFakultasInstance;
const xAxis = chart.scales.x;
const yAxis = chart.scales.y;
const x = event.offsetX;
const y = event.offsetY;
// Cek apakah posisi mouse berada di area bawah chart (dekat label fakultas)
if (y > yAxis.bottom && y < yAxis.bottom + 30) {
const labelIndex = Math.floor(
((x - xAxis.left) / (xAxis.right - xAxis.left)) * chart.data.labels.length
);
const item = data[labelIndex];
const fakultas = Array.isArray(chart.data.labels[labelIndex])
? chart.data.labels[labelIndex].join(' ')
: chart.data.labels[labelIndex];
if (item) {
labelTooltip.innerHTML = `
<strong>${fakultas}</strong><br>
<div class="
d
-
flex
align
-
items
-
center
mt
-
1
">
<div style="
width
:
12
px
;
height
:
12
px
;
background
-
color
:
rgba
(
54
,
162
,
235
,
0.8
);
margin
-
right
:
6
px
;
border
-
radius
:
2
px
;
"></div>
Proposal: ${item.proposal}
</div>
<div class="
d
-
flex
align
-
items
-
center
mt
-
1
">
<div style="
width
:
12
px
;
height
:
12
px
;
background
-
color
:
rgba
(
255
,
206
,
86
,
0.8
);
margin
-
right
:
6
px
;
border
-
radius
:
2
px
;
"></div>
Monev I: ${item.monev1}
</div>
<div class="
d
-
flex
align
-
items
-
center
mt
-
1
">
<div style="
width
:
12
px
;
height
:
12
px
;
background
-
color
:
rgba
(
255
,
99
,
132
,
0.8
);
margin
-
right
:
6
px
;
border
-
radius
:
2
px
;
"></div>
Monev II: ${item.monev2}
</div>
`;
labelTooltip.style.display = 'block';
labelTooltip.style.left = `${event.pageX + 10}px`;
labelTooltip.style.top = `${event.pageY - labelTooltip.offsetHeight - 10}px`;
canvas.style.cursor = 'pointer';
}
} else {
labelTooltip.style.display = 'none';
canvas.style.cursor = 'default';
}
});
canvas.addEventListener('mouseleave', function () {
labelTooltip.style.display = 'none';
canvas.style.cursor = 'default';
});
} catch (error) {
console.error('Gagal memuat chart:', error);
spinner.style.display = 'none';
canvas.style.display = 'none';
await Swal.fire({
icon: 'error',
title: 'Gagal Memuat Grafik',
text: 'Terjadi kesalahan saat mengambil data grafik.
\n
Silakan coba lagi.',
confirmButtonText: 'OK',
timer: 4000
});
}
}
// Muat chart pertama kali
document.addEventListener('DOMContentLoaded', () => {
loadChart();
// Tambahkan event listener untuk filter dropdowns
const filterSelects = ['reqJenisPmw', 'reqStatus', 'tahun'];
filterSelects.forEach(selectId => {
const select = document.getElementById(selectId);
if (select) {
select.addEventListener('change', () => {
loadChart();
});
}
});
});
</script>
@endif
@endsection
routes/web.php
View file @
6e11c3af
...
@@ -67,7 +67,8 @@ Route::post('login', [Laravel\Fortify\Http\Controllers\AuthenticatedSessionContr
...
@@ -67,7 +67,8 @@ Route::post('login', [Laravel\Fortify\Http\Controllers\AuthenticatedSessionContr
Route
::
group
([
'middleware'
=>
[
'auth:sanctum'
,
'verified'
]],
function
()
{
Route
::
group
([
'middleware'
=>
[
'auth:sanctum'
,
'verified'
]],
function
()
{
Route
::
resource
(
'dashboard'
,
DashboardController
::
class
);
Route
::
get
(
'dashboard'
,
[
DashboardController
::
class
,
'index'
])
->
name
(
'dashboard.index'
);
Route
::
get
(
'getChartData'
,
[
DashboardController
::
class
,
'getChartData'
])
->
name
(
'dashboard.chart-data'
);
Route
::
post
(
'selectmahasiswa'
,
[
SelectController
::
class
,
'mahasiswa'
])
->
name
(
'mahasiswa-select'
);
Route
::
post
(
'selectmahasiswa'
,
[
SelectController
::
class
,
'mahasiswa'
])
->
name
(
'mahasiswa-select'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment