Files
database-pertani-web/resources/views/dashboard/profil-pertanian.blade.php
T
2026-10-06 17:52:34 +07:00

3384 lines
121 KiB
PHP

@extends('layout.main')
@push('style')
<link rel="stylesheet" href="{{ asset('assets/vendor/libs/apex-charts/apex-charts.css') }}" />
<style>
.summary-card .card-body {
padding: 22px 22px;
}
.summary-card .avatar-lg {
width: 48px;
height: 48px;
flex-shrink: 0;
}
.summary-card .avatar-lg .avatar-initial {
width: 48px;
height: 48px;
}
.summary-card h4 {
font-size: 1.6rem;
line-height: 1.2;
}
.summary-card h5 {
font-size: 1.05rem;
}
.demografi-kpi-value {
overflow-wrap: anywhere;
}
#genderChart,
#commodityChart,
#farmerGroupChart,
#landOwnershipStatusChart {
min-height: 365px;
}
#genderChart .apexcharts-canvas,
#genderChart svg,
#commodityChart .apexcharts-canvas,
#commodityChart svg,
#farmerGroupChart .apexcharts-canvas,
#farmerGroupChart svg,
#landOwnershipStatusChart .apexcharts-canvas,
#landOwnershipStatusChart svg {
max-width: 100% !important;
}
#genderChart .apexcharts-tooltip,
#ageGroupChart .apexcharts-tooltip,
#educationChart .apexcharts-tooltip,
#dependentChart .apexcharts-tooltip,
#farmerGroupChart .apexcharts-tooltip,
#commodityChart .apexcharts-tooltip,
#landOwnershipStatusChart .apexcharts-tooltip,
#landAreaChart .apexcharts-tooltip,
#incomeChart .apexcharts-tooltip {
background: transparent !important;
border: none !important;
box-shadow: none !important;
overflow: visible !important;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<style>
.clickable-row {
cursor: pointer;
}
.clickable-row:hover {
background-color: rgba(0, 0, 0, 0.03);
}
.segment-distribution {
align-items: center;
display: grid;
gap: 1rem;
grid-template-columns: minmax(180px, 240px) minmax(0, 1fr);
max-width: 100%;
overflow: hidden;
}
.segment-chart-shell {
min-width: 0;
width: 100%;
}
#chart-segmentasi-petani,
#chart-segmentasi-petani .apexcharts-canvas,
#chart-segmentasi-petani svg,
.segment-commodity-chart,
.segment-commodity-chart .apexcharts-canvas,
.segment-commodity-chart svg {
max-width: 100% !important;
}
.segment-table-shell {
min-width: 0;
overflow-x: auto;
width: 100%;
}
.segment-table {
table-layout: fixed;
width: 100%;
}
.segment-table th:first-child,
.segment-table td:first-child {
min-width: 0;
width: 52%;
}
.segment-table th:nth-child(2),
.segment-table td:nth-child(2),
.segment-table th:nth-child(3),
.segment-table td:nth-child(3) {
white-space: nowrap;
width: 24%;
}
.segment-table td {
vertical-align: middle;
}
.segment-table td:first-child .d-flex {
min-width: 0;
}
.segment-table td:first-child span {
display: inline-block;
min-width: 0;
overflow-wrap: anywhere;
word-break: normal;
}
.segment-commodity-chart {
min-height: 260px;
overflow: hidden;
width: 100%;
}
@media (max-width: 1399.98px) {
.segment-distribution {
grid-template-columns: 1fr;
}
.segment-chart-shell {
margin-left: auto;
margin-right: auto;
max-width: 260px;
}
}
@media (max-width: 575.98px) {
.segment-table {
min-width: 320px;
}
}
</style>
<style>
.profile-farming-header {
margin-bottom: 1rem;
}
.profile-farming-shell {
max-width: none;
width: 100%;
}
.profile-farming-title {
color: var(--bs-heading-color);
font-size: 1.5rem;
font-weight: 700;
line-height: 1.25;
margin-bottom: .35rem;
}
.profile-farming-tabs {
gap: .2rem;
margin-bottom: 0 !important;
overflow-x: auto;
scrollbar-width: none;
width: 100%;
}
.profile-farming-tabs::-webkit-scrollbar {
display: none;
}
.profile-farming-tabs .nav-item {
flex: 1 1 0;
min-width: 0;
}
.profile-farming-tabs .nav-link {
align-items: center;
display: flex;
justify-content: center;
min-height: 38px;
padding-left: .75rem;
padding-right: .75rem;
white-space: nowrap;
width: 100%;
}
.profile-farming-tab-content {
background: transparent;
border: 0;
border-radius: 0;
box-shadow: none;
padding: 0;
}
@media (max-width: 767.98px) {
.profile-farming-tabs .nav-item {
flex-basis: auto;
}
}
</style>
@endpush
@section('content')
@php
$activeTab = $activeTab ?? 'demografi-petani';
@endphp
<div class="container-fluid flex-grow-1 container-p-y pb-0 profile-farming-shell">
<div class="profile-farming-header">
<h4 class="profile-farming-title">Karakteristik Petani</h4>
<p class="text-body-secondary mb-0">Ringkasan karakteristik dan indeks petani.</p>
</div>
@php($showTabFilterInput = true)
<div class="row g-6 py-4">
<form id="form-filter" class="col-12" method="GET" action="{{ $indeksFilterAction ?? route('dashboard.indeks-petani') }}">
@if(isset($showTabFilterInput) && $showTabFilterInput)
<input type="hidden" name="tab" id="profile-filter-tab" value="{{ $activeTab ?? 'demografi-petani' }}">
@elseif(isset($activeTab) && $activeTab === 'indeks-petani')
<input type="hidden" name="tab" value="indeks-petani">
@endif
@csrf
<div class="col-12">
<div class="card card-border-shadow-primary profile-filter-card">
<div class="card-body py-3">
<div class="d-flex align-items-center gap-2 flex-wrap">
<div class="d-flex align-items-center me-2">
<i class="icon-base ti tabler-map-2 me-2"></i>
<span class="fw-medium">Wilayah</span>
</div>
<div class="filter-item">
<select id="filter-provinsi" class="form-select form-select-sm" name="provinsi_id" data-default="{{ $provinsi_id }}">
<option value="">Semua Provinsi</option>
@foreach($provinsi as $p)
<option value="{{ $p->provinsi_id }}" {{ old('provinsi_id', $provinsi_id) == $p->provinsi_id ? 'selected' : '' }}>
{{ $p->provinsi }}
</option>
@endforeach
</select>
</div>
<div class="filter-item">
<select id="filter-kabkota" class="form-select form-select-sm" name="kabupatenKota_id" data-default="{{ $kabupatenKota_id }}" disabled>
<option value="">Semua Kabupaten/Kota</option>
</select>
</div>
<div class="filter-item">
<select id="filter-kecamatan" class="form-select form-select-sm" name="kecamatan_id" data-default="{{ $kecamatan_id }}" disabled>
<option value="">Semua Kecamatan</option>
</select>
</div>
<div class="filter-item">
<select id="filter-desa" class="form-select form-select-sm" name="desaKelurahan_id" data-default="{{ $desaKelurahan_id }}" disabled>
<option value="">Semua Desa/Kelurahan</option>
</select>
</div>
</div>
<hr class="my-3">
<div class="d-flex align-items-center gap-2 flex-wrap">
<div class="d-flex align-items-center me-2">
<i class="icon-base ti tabler-adjustments-horizontal me-2"></i>
<span class="fw-medium">Data</span>
</div>
<div class="filter-item">
<select id="filter-komoditas" class="form-select form-select-sm" name="komoditas_id">
<option value="">Semua Komoditas</option>
@foreach ($komoditas as $item)
<option value="{{ $item->id }}" {{ old('komoditas_id', $komoditas_id) == $item->id ? 'selected' : '' }}>
{{ $item->nama }}
</option>
@endforeach
</select>
</div>
<div class="filter-item">
<select id="filter-segmen" class="form-select form-select-sm" name="segmen">
<option value="">Semua Segmen</option>
@foreach ($segments as $segment)
<option value="{{ $segment['name'] }}" {{ old('segmen', $segmen) == $segment['name'] ? 'selected' : '' }}>
{{ $segment['name'] }}
</option>
@endforeach
</select>
</div>
<button type="submit" class="btn btn-outline-secondary btn-sm">
<i class="icon-base ti tabler-filter me-1"></i>
Filter
</button>
<button type="button" id="btn-reset-dashboard-filter" class="btn btn-outline-secondary btn-sm">
<i class="icon-base ti tabler-refresh me-1"></i>
Reset
</button>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="nav-align-top">
<ul class="nav nav-pills flex-column flex-md-row mb-6 row-gap-2 profile-farming-tabs" role="tablist">
<li class="nav-item">
<button
type="button"
class="nav-link {{ $activeTab === 'demografi-petani' ? 'active' : '' }}"
role="tab"
data-bs-toggle="tab"
data-bs-target="#profile-tab-demografi-petani"
aria-controls="profile-tab-demografi-petani"
aria-selected="{{ $activeTab === 'demografi-petani' ? 'true' : 'false' }}"
>
<i class="icon-base ti tabler-users icon-sm me-1_5"></i>
Karakteristik Petani
</button>
</li>
<li class="nav-item">
<button
type="button"
class="nav-link {{ $activeTab === 'indeks-petani' ? 'active' : '' }}"
role="tab"
data-bs-toggle="tab"
data-bs-target="#profile-tab-indeks-petani"
aria-controls="profile-tab-indeks-petani"
aria-selected="{{ $activeTab === 'indeks-petani' ? 'true' : 'false' }}"
>
<i class="icon-base ti tabler-chart-radar icon-sm me-1_5"></i>
Indeks Petani
</button>
</li>
</ul>
</div>
</div>
<div class="tab-content profile-farming-tab-content">
<div
class="tab-pane fade {{ $activeTab === 'demografi-petani' ? 'show active' : '' }}"
id="profile-tab-demografi-petani"
role="tabpanel"
>
<div class="container-xxl flex-grow-1 container-p-y">
<div class="row g-6">
<div class="col-xl-4 col-lg-6 col-sm-6">
<div class="card card-border-shadow-primary h-100">
<div class="card-body">
<div class="d-flex align-items-center gap-4">
<div class="avatar avatar-lg">
<span class="avatar-initial rounded bg-label-primary">
<i class="icon-base ti tabler-shovel-pitchforks icon-28px"></i>
</span>
</div>
<div>
<div class="d-flex align-items-baseline gap-2">
<h4 class="mb-0 demografi-kpi-value">
{{ $data['total_petani'] }}
</h4>
<small class="text-body-secondary">
petani
</small>
</div>
<p class="mb-0 mt-1">
Total Petani
</p>
<small class="text-body-secondary">
Petani yang telah terdata
</small>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-6 col-sm-6">
<div class="card card-border-shadow-secondary h-100">
<div class="card-body">
<div class="d-flex align-items-center gap-4">
<div class="avatar avatar-lg">
<span class="avatar-initial rounded bg-label-secondary">
<i class="icon-base ti tabler-plant-2 icon-28px"></i>
</span>
</div>
<div>
<div class="d-flex align-items-baseline gap-2">
<h4 class="mb-0 demografi-kpi-value">
{{ number_format($data['total_komoditas'] ?? 0, 0, ',', '.') }}
</h4>
<small class="text-body-secondary">
komoditas
</small>
</div>
<p class="mb-0 mt-1">
Komoditas Utama
</p>
<small class="text-body-secondary">
Komoditas utama yang dikelola
</small>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-6 col-sm-6">
<div class="card card-border-shadow-warning h-100">
<div class="card-body">
<div class="d-flex align-items-center gap-4">
<div class="avatar avatar-lg">
<span class="avatar-initial rounded bg-label-warning">
<i class="icon-base ti tabler-map-2 icon-28px"></i>
</span>
</div>
<div>
<div class="d-flex align-items-baseline gap-2">
<h4 class="mb-0 demografi-kpi-value">
{{ number_format($data['desa_sasaran']['total'] ?? 0, 0, ',', '.') }}
</h4>
<small class="text-body-secondary">
desa
</small>
</div>
<p class="mb-0 mt-1">
Desa Sasaran
</p>
<small class="text-body-secondary">
Asal desa/kelurahan petani
</small>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-6 col-sm-6">
<div class="card card-border-shadow-info h-100">
<div class="card-body">
<div class="d-flex align-items-center gap-4">
<div class="avatar avatar-lg">
<span class="avatar-initial rounded bg-label-info">
<i class="icon-base ti tabler-wallet icon-28px"></i>
</span>
</div>
<div>
<div class="d-flex align-items-baseline gap-2">
<h4 class="mb-0 demografi-kpi-value">
Rp {{ number_format($data['ratarata_penghasilan'] ?? 0, 0, ',', '.') }}
</h4>
</div>
<p class="mb-0 mt-1">
Rata-rata Penghasilan Petani
</p>
<small class="text-body-secondary">
Dari pendapatan komoditas tercatat
</small>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-6 col-sm-6">
<div class="card card-border-shadow-success h-100">
<div class="card-body">
<div class="d-flex align-items-center gap-4">
<div class="avatar avatar-lg">
<span class="avatar-initial rounded bg-label-success">
<i class="icon-base ti tabler-chart-area-line icon-28px"></i>
</span>
</div>
<div>
<div class="d-flex align-items-baseline gap-2">
<h4 class="mb-0 demografi-kpi-value">
{{ number_format($data['total_luas_lahan'], 2) }}
</h4>
<small class="text-body-secondary">
ha
</small>
</div>
<p class="mb-0 mt-1">
Total Luas Lahan
</p>
<small class="text-body-secondary">
Seluruh lahan petani
</small>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-6 col-sm-6">
<div class="card card-border-shadow-danger h-100">
<div class="card-body">
<div class="d-flex align-items-center gap-4">
<div class="avatar avatar-lg">
<span class="avatar-initial rounded bg-label-danger">
<i class="icon-base ti tabler-ruler-measure icon-28px"></i>
</span>
</div>
<div>
<div class="d-flex align-items-baseline gap-2">
<h4 class="mb-0 demografi-kpi-value">
{{ number_format($data['ratarata_luas_lahan'], 2) }}
</h4>
<small class="text-body-secondary">
ha
</small>
</div>
<p class="mb-0 mt-1">
Rata-rata Luas Lahan
</p>
<small class="text-body-secondary">
Rata-rata per petani
</small>
</div>
</div>
</div>
</div>
</div>
<!--/ Card Border Shadow -->
<!-- Vehicles overview -->
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header d-flex align-items-center justify-content-between">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Gender</h5>
<small class="text-body-secondary">Distribusi petani berdasarkan gender</small>
</div>
</div>
<div class="card-body">
<div id="genderChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Kelompok Umur</h5>
<small class="text-body-secondary">
Distribusi petani berdasarkan kelompok umur
</small>
</div>
</div>
<div class="card-body">
<div id="ageGroupChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Tingkat Pendidikan</h5>
<small class="text-body-secondary">
Distribusi petani berdasarkan pendidikan terakhir
</small>
</div>
</div>
<div class="card-body">
<div id="educationChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Jumlah Tanggungan</h5>
<small class="text-body-secondary">
Distribusi petani berdasarkan jumlah tanggungan
</small>
</div>
</div>
<div class="card-body">
<div id="dependentChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Karakteristik Petani</h5>
<small class="text-body-secondary">
Petani yang terdaftar di kelompok tani
</small>
</div>
</div>
<div class="card-body">
<div id="farmerGroupChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header d-flex align-items-center justify-content-between">
<div class="card-title mb-0">
<h5 class="m-0 me-2">
Komoditas Utama yang Dikelola
</h5>
<small class="text-body-secondary">
Jumlah petani berdasarkan komoditas utama
</small>
</div>
</div>
<div class="card-body">
<div id="commodityChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">
Luas Lahan yang Dimiliki
</h5>
<small class="text-body-secondary">
Distribusi petani berdasarkan luas lahan garapan
</small>
</div>
</div>
<div class="card-body">
<div id="landAreaChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">
Status Kepemilikan Lahan
</h5>
<small class="text-body-secondary">
Distribusi petani berdasarkan status lahan
</small>
</div>
</div>
<div class="card-body">
<div id="landOwnershipStatusChart"></div>
</div>
</div>
</div>
<div class="col-xxl-4 col-lg-6">
<div class="card h-100">
<div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">
Rentang Penghasilan per Bulan
</h5>
<small class="text-body-secondary">
Distribusi petani berdasarkan penghasilan dari usaha tani per musim
</small>
</div>
</div>
<div class="card-body">
<div id="incomeChart"></div>
</div>
</div>
</div>
<div class="col-xxl-12 col-lg-12">
<div class="card">
<div class="card-header d-flex flex-wrap justify-content-between align-items-center gap-3">
<div>
<div class="d-flex align-items-center gap-2">
<h5 class="card-title mb-0">
Daftar Petani
</h5>
<span
class="badge bg-label-primary"
id="farmerTotalBadge"
>
{{ $daftarPetani->total() }} petani
</span>
</div>
<small class="text-body-secondary">
Menampilkan data petani sesuai data yang tersedia
</small>
</div>
<div class="d-flex align-items-center gap-2">
<div
class="input-group input-group-merge"
style="width: 220px;"
>
<span class="input-group-text">
<i class="icon-base ti tabler-search"></i>
</span>
<input
type="text"
id="farmerSearch"
class="form-control"
placeholder="Cari petani..."
>
</div>
<button
type="button"
id="resetFarmerFilter"
class="btn btn-label-secondary"
>
Reset
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>No.</th>
<th>Nama Petani</th>
<th>Gender</th>
<th>Umur</th>
<th>Komoditas</th>
<th>Luas Lahan</th>
<th>Pendidikan</th>
<th>Rentang Pendapatan</th>
</tr>
</thead>
<tbody id="farmerTableBody">
@foreach ($daftarPetani as $petani)
{{-- isi tabel kamu yang sekarang --}}
@endforeach
</tbody>
</table>
</div>
<div class="card-footer d-flex justify-content-between align-items-center">
<small class="text-body-secondary" id="farmerTableInfo">
Menampilkan
{{ $daftarPetani->firstItem() ?? 0 }}
-
{{ $daftarPetani->lastItem() ?? 0 }}
dari
{{ $daftarPetani->total() }}
petani
</small>
<div id="farmerPagination">
{{ $daftarPetani
->onEachSide(1)
->links('pagination::bootstrap-5')
}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="tab-pane fade {{ $activeTab === 'indeks-petani' ? 'show active' : '' }}"
id="profile-tab-indeks-petani"
role="tabpanel"
>
@php($showIndeksFilter = false)
<div class="container-xxl flex-grow-1 container-p-y">
<div class="row g-6">
<div class="col-lg-3 col-sm-6">
<div class="card card-border-shadow-primary h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-primary">
<i class="icon-base ti tabler-user-check icon-28px"></i>
</span>
</div>
<h4 class="mb-0" id="count-petani">0</h4>
</div>
<p class="mb-1">Total Petani</p>
<p class="mb-0">
<span class="text-heading fw-medium me-2" id="count-komoditas">0</span>
<small class="text-body-secondary">komoditas utama</small>
</p>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="card card-border-shadow-warning h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-warning">
<i class="icon-base ti tabler-trees icon-28px"></i>
</span>
</div>
<h4 class="mb-0" id="sum-lahan">0</h4>
<small class="text-body-warning">ha</small>
</div>
<p class="mb-1">Total Luas Lahan</p>
<p class="mb-0">
<small class="text-body-warning">rata-rata</small>
<span class="text-heading fw-medium" id="avg-lahan"></span>
<small class="text-body-warning">ha/petani</small>
</p>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="card card-border-shadow-info h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-info">
<i class="icon-base ti tabler-star icon-28px"></i>
</span>
</div>
<h4 class="mb-0" id="avg-skor"></h4>
</div>
<p class="mb-1">Rata-rata Indeks Kesiapan Adopsi</p>
<p class="mb-0">
<small class="text-body-secondary">Segmentasi:</small>
<span class="text-heading fw-medium me-2" id="avg-segmen"></span>
</p>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="card card-border-shadow-success h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-success">
<i class="icon-base ti tabler-map-2 icon-28px"></i>
</span>
</div>
<h4 class="mb-0" id="count-desa">0</h4>
</div>
<p class="mb-1">Jumlah Desa Sasaran</p>
<p class="mb-0">
<span class="text-heading fw-medium me-2" id="count-kecamatan">0</span>
<small class="text-body-secondary">kecamatan sasaran</small>
</p>
</div>
</div>
</div>
</div>
<div class="row g-6 py-4">
<div class="col-lg-6 col-sm-12">
<div class="card card-border-shadow-primary h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Distribusi Segmentasi Petani</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<div class="segment-distribution">
<div class="segment-chart-shell">
<div id="chart-segmentasi-petani"></div>
</div>
<div class="segment-table-shell table-responsive">
<table class="table card-table table-border-top-0 table-border-bottom-0 segment-table mb-0">
<thead>
<tr>
<th>Segmen</th>
<th class="text-end">Petani</th>
<th class="text-end">%</th>
</tr>
</thead>
<tbody id="table-segmentasi-petani"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 col-sm-12">
<div class="card card-border-shadow-secondary h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Distribusi Segmentasi Petani</h5>
<p class="card-subtitle">per komoditas</p>
</div>
</div>
<div class="card-body">
<div class="segment-commodity-chart" id="chart-segmentasi-petani-komoditas"></div>
</div>
</div>
</div>
</div>
<div class="row g-6 py-4">
<div class="col-lg-6 col-sm-12">
<div class="card card-border-shadow-info h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Rata-rata Dimensi Kesiapan Adopsi</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<div id="chart-dimensi"></div>
<div class="d-flex flex-wrap gap-3 mt-3 small justify-content-center">
<div>
<span class="badge bg-label-primary">D1</span> Sistem &amp; Praktik Budidaya
</div>
<div>
<span class="badge bg-label-primary">D2</span> Sosial Ekonomi Rumah Tangga
</div>
<div>
<span class="badge bg-label-primary">D3</span> Rantai Nilai &amp; Akses Pasar
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 col-sm-12">
<div class="card card-border-shadow-warning h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Rata-rata Komponen Kesiapan Adopsi</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<div id="chart-komponen"></div>
<div class="d-flex flex-wrap gap-3 mt-3 small justify-content-center">
<div>
<span class="badge bg-label-primary">K1</span> Motivasi &amp; Kapasitas Adopsi
</div>
<div>
<span class="badge bg-label-primary">K2</span> Kondisi Ekonomi Rumah Tangga
</div>
<div>
<span class="badge bg-label-primary">K3</span> Praktik Budidaya &amp; GAP
</div>
<div>
<span class="badge bg-label-primary">K4</span> Keterlibatan Kelembagaan
</div>
<div>
<span class="badge bg-label-primary">K5</span> Akses &amp; Kebebasan Keuangan
</div>
<div>
<span class="badge bg-label-primary">K6</span> Rantai Nilai &amp; Akses Pasar
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-6 py-4">
<div class="col-lg-6 col-sm-12">
<div class="card card-border-shadow-danger h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Sebaran Segmentasi Petani</h5>
<p class="card-subtitle">berdasarkan sebaran wilayah untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<div id="map-sebaran-petani" style="height: 380px;"></div>
<span class="small text-muted">*klik pada desa untuk menampilkan detail informasi dan menyaring daftar petani</span>
</div>
</div>
</div>
<div class="col-lg-6 col-sm-12">
<div class="card card-border-shadow-success h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Distribusi Segmentasi Petani</h5>
<p class="card-subtitle">berdasarkan sebaran wilayah untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<table id="table-desa" class="table card-table table-border-top-0 table-border-bottom-0">
<thead>
<tr>
<th class="pe-0">Desa/Kelurahan</th>
<th class="text-end pe-0">Petani</th>
<th class="pe-0">Segmen Rata-rata</th>
<th class="pe-0">Segmen Dominan</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
<div class="row g-6 py-4">
<div class="col-lg-12 col-sm-12">
<div class="card card-border-shadow-primary h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Daftar Petani</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
<button type="button" id="btn-reset-filter" class="btn btn-outline-secondary btn-sm">
<i class="fas fa-sync-alt me-1"></i>
Reset Filter
</button>
</div>
<div class="card-body">
<table id="table-petani" class="table card-table table-border-top-0 table-border-bottom-0">
<thead>
<tr>
<th class="pe-0">Nama Petani</th>
<th class="pe-0">Desa/Kelurahan</th>
<th class="pe-0">Komoditas</th>
<th class="text-end pe-0">Luas Lahan (ha)</th>
<th class="text-end pe-0">Indeks Kesiapan Adopsi</th>
<th class="pe-0">Segmen</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script src="{{ asset('assets/vendor/libs/apex-charts/apexcharts.js') }}"></script>
<script>
'use strict';
document.addEventListener('DOMContentLoaded', function () {
const headingColor = config.colors.headingColor;
const legendColor = config.colors.bodyColor;
const fontFamily = config.fontFamily;
const farmerDataUrl = @json(route('dashboard.demografi-petani.data'));
const farmerProfileUrl = @json(url('/dashboard/profil/petani'));
let activeFilters = {
gender: null,
umur: null,
pendidikan: null,
jumlah_tanggungan: null,
kelompok_tani: null,
komoditas: null,
luas_lahan: null,
status_kepemilikan_lahan: null,
penghasilan: null
};
let searchTimer = null;
function escapeHtml(value) {
if (value === null || value === undefined) {
return '';
}
return String(value)
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#039;');
}
function formatLuas(value) {
const number = Number(value || 0);
if (number <= 0) {
return '-';
}
return number.toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' ha';
}
async function loadFarmerTable(page = 1) {
const searchInput = document.querySelector('#farmerSearch');
const search = searchInput ? searchInput.value.trim() : '';
const params = new URLSearchParams();
params.set('page', page);
const generalFilterForm = document.querySelector('#form-filter');
if (generalFilterForm) {
new FormData(generalFilterForm).forEach((value, key) => {
if (value !== null && value !== undefined && value !== '') {
params.set(key, value);
}
});
}
Object.entries(activeFilters).forEach(([key, value]) => {
if (value !== null && value !== undefined && value !== '') {
params.set(key, value);
}
});
if (search) {
params.set('search', search);
}
const tableBody = document.querySelector('#farmerTableBody');
if (tableBody) {
tableBody.innerHTML = `
<tr>
<td colspan="8" class="text-center py-5">
<div class="spinner-border spinner-border-sm text-primary me-2" role="status"></div>
<span class="text-body-secondary">Memuat data petani...</span>
</td>
</tr>
`;
}
try {
const response = await fetch(`${farmerDataUrl}?${params.toString()}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (!response.ok) {
throw new Error(`HTTP Error ${response.status}`);
}
const result = await response.json();
renderFarmerTable(result);
} catch (error) {
console.error('Gagal memuat tabel petani:', error);
}
}
function renderFarmerTable(result) {
const tbody = document.querySelector('#farmerTableBody');
if (!tbody) {
return;
}
const rows = result.data || [];
if (rows.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="8" class="text-center py-5 text-body-secondary">
Tidak ada data petani yang sesuai dengan filter.
</td>
</tr>
`;
updateFarmerPagination(result.pagination);
return;
}
tbody.innerHTML = rows.map((petani, index) => {
const rowNumber = ((result.pagination.current_page - 1) * result.pagination.per_page) + index + 1;
const genderBadge = Number(petani.jenis_kelamin) === 1
? `<span class="badge bg-label-info">Laki-laki</span>`
: `<span class="badge" style="background-color:#ffe8f1 !important; color:#ff5598 !important;">Perempuan</span>`;
const umur = (petani.umur !== null && petani.umur !== undefined) ? `${petani.umur} tahun` : '-';
return `
<tr class="farmer-row" data-id="${petani.id}" style="cursor: pointer;">
<td><span class="text-heading fw-medium">${rowNumber}</span></td>
<td><span class="text-heading fw-medium">${escapeHtml(petani.nama)}</span></td>
<td>${genderBadge}</td>
<td>${escapeHtml(umur)}</td>
<td>${escapeHtml(petani.komoditas || '-')}</td>
<td>${formatLuas(petani.luas_lahan)}</td>
<td>${escapeHtml(petani.pendidikan || '-')}</td>
<td>${escapeHtml(petani.rentang_penghasilan || '-')}</td>
</tr>
`;
}).join('');
updateFarmerPagination(result.pagination);
}
function updateFarmerPagination(pagination) {
if (!pagination) {
return;
}
const totalBadge = document.querySelector('#farmerTotalBadge');
if (totalBadge) {
totalBadge.textContent = `${pagination.total} petani`;
}
const tableInfo = document.querySelector('#farmerTableInfo');
if (tableInfo) {
tableInfo.textContent = `Menampilkan ${pagination.from ?? 0} - ${pagination.to ?? 0} dari ${pagination.total ?? 0} petani`;
}
const paginationEl = document.querySelector('#farmerPagination');
if (!paginationEl) {
return;
}
if (pagination.last_page <= 1) {
paginationEl.innerHTML = '';
return;
}
let html = `<nav><ul class="pagination pagination-sm mb-0">`;
html += `
<li class="page-item ${pagination.current_page === 1 ? 'disabled' : ''}">
<button type="button" class="page-link farmer-page" data-page="${pagination.current_page - 1}">
<i class="icon-base ti tabler-chevron-left"></i>
</button>
</li>
`;
const currentPage = pagination.current_page;
const lastPage = pagination.last_page;
const startPage = Math.max(1, currentPage - 2);
const endPage = Math.min(lastPage, currentPage + 2);
if (startPage > 1) {
html += `
<li class="page-item">
<button type="button" class="page-link farmer-page" data-page="1">1</button>
</li>
`;
if (startPage > 2) {
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
}
}
for (let page = startPage; page <= endPage; page++) {
html += `
<li class="page-item ${page === currentPage ? 'active' : ''}">
<button type="button" class="page-link farmer-page" data-page="${page}">${page}</button>
</li>
`;
}
if (endPage < lastPage) {
if (endPage < lastPage - 1) {
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
}
html += `
<li class="page-item">
<button type="button" class="page-link farmer-page" data-page="${lastPage}">${lastPage}</button>
</li>
`;
}
html += `
<li class="page-item ${currentPage === lastPage ? 'disabled' : ''}">
<button type="button" class="page-link farmer-page" data-page="${currentPage + 1}">
<i class="icon-base ti tabler-chevron-right"></i>
</button>
</li>
`;
html += `</ul></nav>`;
paginationEl.innerHTML = html;
}
function applyFarmerFilter(filter, value) {
if (activeFilters[filter] !== null && String(activeFilters[filter]) === String(value)) {
activeFilters[filter] = null;
} else {
activeFilters[filter] = value;
}
loadFarmerTable(1);
}
function resetFarmerFilter() {
activeFilters = {
gender: null,
umur: null,
pendidikan: null,
jumlah_tanggungan: null,
kelompok_tani: null,
komoditas: null,
luas_lahan: null,
status_kepemilikan_lahan: null,
penghasilan: null
};
const searchInput = document.querySelector('#farmerSearch');
if (searchInput) {
searchInput.value = '';
}
loadFarmerTable(1);
}
document.addEventListener('input', function (event) {
if (event.target.id !== 'farmerSearch') {
return;
}
clearTimeout(searchTimer);
searchTimer = setTimeout(function () {
loadFarmerTable(1);
}, 350);
});
document.addEventListener('click', function (event) {
const button = event.target.closest('.farmer-page');
if (!button) {
return;
}
if (button.closest('.page-item.disabled')) {
return;
}
const page = Number(button.dataset.page);
if (!page || page < 1) {
return;
}
loadFarmerTable(page);
});
document.addEventListener('click', function (event) {
const button = event.target.closest('#resetFarmerFilter');
if (!button) {
return;
}
resetFarmerFilter();
});
const genderChartEl = document.querySelector('#genderChart');
const lakiLaki = Number(@json($data['petani_lakilaki'] ?? 0));
const perempuan = Number(@json($data['petani_perempuan'] ?? 0));
const totalPetani = lakiLaki + perempuan;
if (genderChartEl) {
const genderChartConfig = {
chart: {
height: 365,
parentHeightOffset: 0,
type: 'pie',
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
const values = [1, 0];
applyFarmerFilter('gender', values[index]);
}
}
},
labels: ['Laki-laki', 'Perempuan'],
series: [lakiLaki, perempuan],
colors: [config.colors.info, '#ff5598'],
stroke: { width: 0 },
dataLabels: {
enabled: true,
formatter: function (value, options) {
const count = options.w.globals.series[options.seriesIndex] || 0;
if (count <= 0) {
return '';
}
return `${Number(value).toFixed(1)}%`;
},
style: {
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 600,
colors: ['#fff']
},
dropShadow: {
enabled: true,
top: 1,
left: 1,
blur: 2,
opacity: 0.45
}
},
legend: {
show: true,
position: 'bottom',
offsetY: 10,
markers: { size: 4, strokeWidth: 0 },
itemMargin: { horizontal: 15, vertical: 5 },
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 400,
labels: { colors: legendColor, useSeriesColors: false },
formatter: function (seriesName, options) {
const value = options.w.globals.series[options.seriesIndex];
const percentage = totalPetani > 0 ? ((value / totalPetani) * 100).toFixed(1) : '0.0';
return `${seriesName}: ${value} (${percentage}%)`;
}
},
tooltip: {
theme: 'dark',
y: {
formatter: function (value) {
const percentage = totalPetani > 0 ? ((value / totalPetani) * 100).toFixed(1) : '0.0';
return `${value} petani (${percentage}%)`;
}
}
},
grid: { padding: { top: 15 } },
plotOptions: {
pie: {
dataLabels: {
offset: -14,
minAngleToShowLabel: 8
}
}
},
responsive: [
{
breakpoint: 1025,
options: {
chart: { height: 380 }
}
}
]
};
const genderChart = new ApexCharts(genderChartEl, genderChartConfig);
genderChart.render();
}
const ageGroupChartEl = document.querySelector('#ageGroupChart');
if (ageGroupChartEl) {
const ageFilterValues = ['kurang_30', '30_39', '40_49', '50_59', '60_keatas'];
const ageGroupData = [
Number(@json($data['kelompok_umur']['kurang_30'] ?? 0)),
Number(@json($data['kelompok_umur']['30_39'] ?? 0)),
Number(@json($data['kelompok_umur']['40_49'] ?? 0)),
Number(@json($data['kelompok_umur']['50_59'] ?? 0)),
Number(@json($data['kelompok_umur']['60_keatas'] ?? 0))
];
const totalAgeGroup = ageGroupData.reduce((total, value) => total + value, 0);
const ageGroupChartConfig = {
chart: {
height: 320,
type: 'bar',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('umur', ageFilterValues[index]);
}
}
},
series: [
{
name: 'Petani',
data: ageGroupData
}
],
colors: [config.colors.primary],
plotOptions: {
bar: {
borderRadius: 4,
columnWidth: '45%',
distributed: false,
dataLabels: { position: 'top' }
}
},
dataLabels: {
enabled: true,
offsetY: -20,
style: {
fontSize: '12px',
fontFamily: fontFamily,
fontWeight: 500,
colors: [headingColor]
},
formatter: function (value) {
const percentage = totalAgeGroup > 0 ? (Number(value) / totalAgeGroup) * 100 : 0;
return `${value} (${percentage.toFixed(1)}%)`;
}
},
xaxis: {
categories: ['< 30', '30 - 39', '40 - 49', '50 - 59', '≥ 60'],
labels: {
style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily },
formatter: function (value) {
return value + ' tahun';
}
},
axisBorder: { show: false },
axisTicks: { show: false }
},
yaxis: {
min: 0,
labels: {
style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily },
formatter: function (value) {
return Math.floor(value);
}
},
title: {
text: 'Petani',
style: { color: legendColor, fontSize: '12px', fontFamily: fontFamily, fontWeight: 400 }
}
},
grid: {
borderColor: config.colors.borderColor,
strokeDashArray: 5,
xaxis: { lines: { show: false } },
padding: { top: 34 }
},
legend: { show: false },
tooltip: {
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
const value = series[seriesIndex][dataPointIndex];
const label = w.globals.labels[dataPointIndex];
const percentage = totalAgeGroup > 0 ? (Number(value) / totalAgeGroup) * 100 : 0;
return `
<div style="background:${config.colors.primary}; color:#fff; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
${label} tahun: <strong>${value} petani (${percentage.toFixed(1)}%)</strong>
</div>
`;
}
}
};
new ApexCharts(ageGroupChartEl, ageGroupChartConfig).render();
}
const educationChartEl = document.querySelector('#educationChart');
if (educationChartEl) {
const educationData = [
Number(@json($data['pendidikan']['tidak_sekolah'] ?? 0)),
Number(@json($data['pendidikan']['sd'] ?? 0)),
Number(@json($data['pendidikan']['smp'] ?? 0)),
Number(@json($data['pendidikan']['sma'] ?? 0)),
Number(@json($data['pendidikan']['diploma'] ?? 0)),
Number(@json($data['pendidikan']['s1_keatas'] ?? 0))
];
const educationFilters = ['tidak_sekolah', 'sd', 'smp', 'sma', 'diploma', 's1_keatas'];
const totalPendidikan = educationData.reduce((total, value) => total + value, 0);
const educationChartConfig = {
chart: {
height: 330,
type: 'bar',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('pendidikan', educationFilters[index]);
}
}
},
series: [{ name: 'Petani', data: educationData }],
colors: [config.colors.success],
plotOptions: {
bar: {
horizontal: true,
borderRadius: 4,
barHeight: '55%',
dataLabels: { position: 'top' }
}
},
dataLabels: {
enabled: true,
textAnchor: 'start',
offsetX: 6,
style: {
fontSize: '12px',
fontFamily: fontFamily,
fontWeight: 500,
colors: [headingColor]
},
formatter: function (value) {
const percentage = totalPendidikan > 0 ? ((value / totalPendidikan) * 100).toFixed(1) : '0.0';
return `${value} (${percentage}%)`;
}
},
xaxis: {
categories: ['Tidak Sekolah', 'SD / Sederajat', 'SMP / Sederajat', 'SMA / Sederajat', 'Diploma', 'S1 ke atas'],
labels: {
style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily },
formatter: function (value) {
return Math.floor(value);
}
},
axisBorder: { show: false },
axisTicks: { show: false },
title: {
text: 'Petani',
style: { color: legendColor, fontSize: '12px', fontFamily: fontFamily, fontWeight: 400 }
}
},
yaxis: {
labels: { style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily } }
},
grid: {
borderColor: config.colors.borderColor,
strokeDashArray: 5,
xaxis: { lines: { show: true } },
yaxis: { lines: { show: false } },
padding: { right: 55 }
},
legend: { show: false },
tooltip: {
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
const value = series[seriesIndex][dataPointIndex];
const label = w.globals.labels[dataPointIndex];
const percentage = totalPendidikan > 0 ? ((value / totalPendidikan) * 100).toFixed(1) : '0.0';
return `
<div style="background:${config.colors.success}; color:#fff; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
${label}: <strong>${value} petani (${percentage}%)</strong>
</div>
`;
}
}
};
new ApexCharts(educationChartEl, educationChartConfig).render();
}
const dependentChartEl = document.querySelector('#dependentChart');
if (dependentChartEl) {
const dependentData = [
Number(@json($data['jumlah_tanggungan']['0'] ?? 0)),
Number(@json($data['jumlah_tanggungan']['1_2'] ?? 0)),
Number(@json($data['jumlah_tanggungan']['3_4'] ?? 0)),
Number(@json($data['jumlah_tanggungan']['5_keatas'] ?? 0))
];
const dependentFilters = ['0', '1_2', '3_4', '5_keatas'];
const totalDependentsFarmers = dependentData.reduce((total, value) => total + value, 0);
const dependentChartConfig = {
chart: {
height: 330,
type: 'bar',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('jumlah_tanggungan', dependentFilters[index]);
}
}
},
series: [{ name: 'Petani', data: dependentData }],
colors: [config.colors.danger],
plotOptions: {
bar: {
horizontal: true,
borderRadius: 4,
barHeight: '50%',
dataLabels: { position: 'top' }
}
},
dataLabels: {
enabled: true,
textAnchor: 'start',
offsetX: 6,
style: {
fontSize: '12px',
fontFamily: fontFamily,
fontWeight: 500,
colors: [headingColor]
},
formatter: function (value) {
const percentage = totalDependentsFarmers > 0 ? ((value / totalDependentsFarmers) * 100).toFixed(1) : '0.0';
return `${value} (${percentage}%)`;
}
},
xaxis: {
categories: ['0 orang', '1 - 2 orang', '3 - 4 orang', '>= 5 orang'],
labels: {
style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily },
formatter: function (value) {
return Math.floor(value);
}
},
axisBorder: { show: false },
axisTicks: { show: false },
title: {
text: 'Petani',
style: { color: legendColor, fontSize: '12px', fontFamily: fontFamily, fontWeight: 400 }
}
},
yaxis: {
labels: { style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily } }
},
grid: {
borderColor: config.colors.borderColor,
strokeDashArray: 5,
xaxis: { lines: { show: true } },
yaxis: { lines: { show: false } },
padding: { right: 55 }
},
legend: { show: false },
tooltip: {
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
const value = series[seriesIndex][dataPointIndex];
const label = w.globals.labels[dataPointIndex];
const percentage = totalDependentsFarmers > 0 ? ((value / totalDependentsFarmers) * 100).toFixed(1) : '0.0';
return `
<div style="background:${config.colors.danger}; color:#fff; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
${label}: <strong>${value} petani (${percentage}%)</strong>
</div>
`;
}
}
};
new ApexCharts(dependentChartEl, dependentChartConfig).render();
}
const farmerGroupChartEl = document.querySelector('#farmerGroupChart');
if (farmerGroupChartEl) {
const farmerGroupData = [
Number(@json($data['kelompok_tani']['terdaftar'] ?? 0)),
Number(@json($data['kelompok_tani']['tidak_terdaftar'] ?? 0)),
Number(@json($data['kelompok_tani']['belum_terisi'] ?? 0))
];
const farmerGroupFilters = ['terdaftar', 'tidak_terdaftar', 'belum_terisi'];
const totalFarmerGroup = farmerGroupData.reduce((total, value) => total + value, 0);
const farmerGroupChartConfig = {
chart: {
height: 365,
type: 'pie',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('kelompok_tani', farmerGroupFilters[index]);
}
}
},
labels: ['Terdaftar', 'Tidak Terdaftar', 'Belum Terisi'],
series: farmerGroupData,
colors: [config.colors.success, config.colors.warning, config.colors.secondary],
stroke: { width: 0 },
dataLabels: {
enabled: true,
formatter: function (value, options) {
const count = options.w.globals.series[options.seriesIndex] || 0;
if (count <= 0) {
return '';
}
return `${Number(value).toFixed(1)}%`;
},
style: {
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 600,
colors: ['#fff']
},
dropShadow: {
enabled: true,
top: 1,
left: 1,
blur: 2,
opacity: 0.45
}
},
legend: {
show: true,
position: 'bottom',
offsetY: 10,
markers: { size: 4, strokeWidth: 0 },
itemMargin: { horizontal: 15, vertical: 5 },
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 400,
labels: { colors: legendColor, useSeriesColors: false },
formatter: function (seriesName, options) {
const value = options.w.globals.series[options.seriesIndex];
const percentage = totalFarmerGroup > 0 ? ((value / totalFarmerGroup) * 100).toFixed(1) : '0.0';
return `${seriesName}: ${value} (${percentage}%)`;
}
},
tooltip: {
theme: 'dark',
y: {
formatter: function (value) {
const percentage = totalFarmerGroup > 0 ? ((value / totalFarmerGroup) * 100).toFixed(1) : '0.0';
return `${value} petani (${percentage}%)`;
}
}
},
plotOptions: {
pie: {
dataLabels: {
offset: -14,
minAngleToShowLabel: 8
}
}
},
responsive: [
{
breakpoint: 1025,
options: {
chart: { height: 380 }
}
}
]
};
new ApexCharts(farmerGroupChartEl, farmerGroupChartConfig).render();
}
const commodityChartEl = document.querySelector('#commodityChart');
if (commodityChartEl) {
const commodityIds = @json($data['komoditas_utama']['ids'] ?? []);
const commodityLabels = @json($data['komoditas_utama']['labels'] ?? []);
const commoditySeries = @json($data['komoditas_utama']['series'] ?? []);
const totalCommodityFarmers = commoditySeries.reduce((total, value) => total + Number(value), 0);
const commodityChartConfig = {
chart: {
height: 365,
type: 'pie',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('komoditas', commodityIds[index]);
}
}
},
labels: commodityLabels,
series: commoditySeries.map(Number),
colors: [
config.colors.primary,
config.colors.warning,
config.colors.success,
config.colors.info,
config.colors.danger,
config.colors.secondary
],
stroke: { width: 0 },
dataLabels: {
enabled: true,
formatter: function (value, options) {
const count = options.w.globals.series[options.seriesIndex] || 0;
if (count <= 0) {
return '';
}
return `${Number(value).toFixed(1)}%`;
},
style: {
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 600,
colors: ['#fff']
},
dropShadow: {
enabled: true,
top: 1,
left: 1,
blur: 2,
opacity: 0.45
}
},
legend: {
show: true,
position: 'bottom',
offsetY: 10,
markers: { size: 4, strokeWidth: 0 },
itemMargin: { horizontal: 15, vertical: 5 },
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 400,
labels: { colors: legendColor, useSeriesColors: false },
formatter: function (seriesName, options) {
const value = options.w.globals.series[options.seriesIndex];
const percentage = totalCommodityFarmers > 0 ? ((value / totalCommodityFarmers) * 100).toFixed(1) : '0.0';
return `${seriesName}: ${value} (${percentage}%)`;
}
},
tooltip: {
custom: function ({ series, seriesIndex, w }) {
const value = series[seriesIndex];
const label = w.globals.labels[seriesIndex];
const percentage = totalCommodityFarmers > 0 ? ((value / totalCommodityFarmers) * 100).toFixed(1) : '0.0';
const color = w.globals.colors[seriesIndex];
return `
<div style="background:${color}; color:#fff; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
${label}: <strong>${value} petani (${percentage}%)</strong>
</div>
`;
}
},
plotOptions: {
pie: {
dataLabels: {
offset: -14,
minAngleToShowLabel: 8
}
}
},
responsive: [
{
breakpoint: 1400,
options: {
chart: { height: 390 },
legend: { position: 'bottom' }
}
},
{
breakpoint: 576,
options: {
chart: { height: 380 },
legend: { position: 'bottom' }
}
}
]
};
new ApexCharts(commodityChartEl, commodityChartConfig).render();
}
const landAreaChartEl = document.querySelector('#landAreaChart');
if (landAreaChartEl) {
const landAreaData = [
Number(@json($data['luas_lahan']['kurang_05'] ?? 0)),
Number(@json($data['luas_lahan']['05_1'] ?? 0)),
Number(@json($data['luas_lahan']['1_2'] ?? 0)),
Number(@json($data['luas_lahan']['lebih_2'] ?? 0))
];
const landAreaFilters = ['kurang_05', '05_1', '1_2', 'lebih_2'];
const totalLandFarmers = landAreaData.reduce((total, value) => total + value, 0);
const landAreaChartConfig = {
chart: {
height: 330,
type: 'bar',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('luas_lahan', landAreaFilters[index]);
}
}
},
series: [{ name: 'Petani', data: landAreaData }],
colors: [config.colors.warning],
plotOptions: {
bar: {
horizontal: true,
borderRadius: 4,
barHeight: '50%',
dataLabels: { position: 'top' }
}
},
dataLabels: {
enabled: true,
textAnchor: 'start',
offsetX: 6,
style: {
fontSize: '12px',
fontFamily: fontFamily,
fontWeight: 500,
colors: [headingColor]
},
formatter: function (value) {
const percentage = totalLandFarmers > 0 ? ((value / totalLandFarmers) * 100).toFixed(1) : '0.0';
return `${value} (${percentage}%)`;
}
},
xaxis: {
categories: ['< 0,5 ha', '0,5 - 1 ha', '1 - 2 ha', '> 2 ha'],
labels: {
style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily },
formatter: function (value) {
return Math.floor(value);
}
},
axisBorder: { show: false },
axisTicks: { show: false },
title: {
text: 'Petani',
style: { color: legendColor, fontSize: '12px', fontFamily: fontFamily, fontWeight: 400 }
}
},
yaxis: {
labels: { style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily } }
},
grid: {
borderColor: config.colors.borderColor,
strokeDashArray: 5,
xaxis: { lines: { show: true } },
yaxis: { lines: { show: false } },
padding: { right: 55 }
},
legend: { show: false },
tooltip: {
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
const value = series[seriesIndex][dataPointIndex];
const label = w.globals.labels[dataPointIndex];
const percentage = totalLandFarmers > 0 ? ((value / totalLandFarmers) * 100).toFixed(1) : '0.0';
return `
<div style="background:${config.colors.warning}; color:#fff; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
${label}: <strong>${value} petani (${percentage}%)</strong>
</div>
`;
}
}
};
new ApexCharts(landAreaChartEl, landAreaChartConfig).render();
}
const landOwnershipStatusChartEl = document.querySelector('#landOwnershipStatusChart');
if (landOwnershipStatusChartEl) {
const landOwnershipStatusKeys = @json($data['status_kepemilikan_lahan']['keys'] ?? []);
const landOwnershipStatusLabels = @json($data['status_kepemilikan_lahan']['labels'] ?? []);
const landOwnershipStatusSeries = (@json($data['status_kepemilikan_lahan']['series'] ?? [])).map(Number);
const totalLandOwnershipStatusFarmers = landOwnershipStatusSeries.reduce((total, value) => total + value, 0);
const landOwnershipStatusChartConfig = {
chart: {
height: 365,
type: 'pie',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('status_kepemilikan_lahan', landOwnershipStatusKeys[index]);
}
}
},
labels: landOwnershipStatusLabels,
series: landOwnershipStatusSeries,
colors: [
config.colors.success,
config.colors.warning,
config.colors.info,
config.colors.secondary
],
stroke: { width: 0 },
dataLabels: {
enabled: true,
formatter: function (value, options) {
const count = options.w.globals.series[options.seriesIndex] || 0;
if (count <= 0) {
return '';
}
return `${Number(value).toFixed(1)}%`;
},
style: {
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 600,
colors: ['#fff']
},
dropShadow: {
enabled: true,
top: 1,
left: 1,
blur: 2,
opacity: 0.45
}
},
legend: {
show: true,
position: 'bottom',
offsetY: 10,
markers: { size: 4, strokeWidth: 0 },
itemMargin: { horizontal: 15, vertical: 5 },
fontSize: '13px',
fontFamily: fontFamily,
fontWeight: 400,
labels: { colors: legendColor, useSeriesColors: false },
formatter: function (seriesName, options) {
const value = options.w.globals.series[options.seriesIndex];
const percentage = totalLandOwnershipStatusFarmers > 0 ? ((value / totalLandOwnershipStatusFarmers) * 100).toFixed(1) : '0.0';
return `${seriesName}: ${value} (${percentage}%)`;
}
},
tooltip: {
theme: 'dark',
y: {
formatter: function (value) {
const percentage = totalLandOwnershipStatusFarmers > 0 ? ((value / totalLandOwnershipStatusFarmers) * 100).toFixed(1) : '0.0';
return `${value} petani (${percentage}%)`;
}
}
},
plotOptions: {
pie: {
dataLabels: {
offset: -14,
minAngleToShowLabel: 8
}
}
},
responsive: [
{
breakpoint: 1025,
options: {
chart: { height: 380 }
}
}
]
};
new ApexCharts(landOwnershipStatusChartEl, landOwnershipStatusChartConfig).render();
}
const incomeChartEl = document.querySelector('#incomeChart');
if (incomeChartEl) {
const incomeData = [
Number(@json($data['penghasilan']['kurang_1'] ?? 0)),
Number(@json($data['penghasilan']['1_3'] ?? 0)),
Number(@json($data['penghasilan']['3_5'] ?? 0)),
Number(@json($data['penghasilan']['5_10'] ?? 0)),
Number(@json($data['penghasilan']['lebih_10'] ?? 0))
];
const incomeFilters = ['kurang_1', '1_3', '3_5', '5_10', 'lebih_10'];
const totalIncomeFarmers = incomeData.reduce((total, value) => total + value, 0);
const incomeChartConfig = {
chart: {
height: 330,
type: 'bar',
parentHeightOffset: 0,
toolbar: { show: false },
events: {
dataPointSelection: function (event, chartContext, options) {
const index = options.dataPointIndex;
if (index < 0) {
return;
}
applyFarmerFilter('penghasilan', incomeFilters[index]);
}
}
},
series: [{ name: 'Petani', data: incomeData }],
colors: [config.colors.info],
plotOptions: {
bar: {
horizontal: true,
borderRadius: 4,
barHeight: '50%',
dataLabels: { position: 'top' }
}
},
dataLabels: {
enabled: true,
textAnchor: 'start',
offsetX: 6,
style: {
fontSize: '12px',
fontFamily: fontFamily,
fontWeight: 500,
colors: [headingColor]
},
formatter: function (value) {
const percentage = totalIncomeFarmers > 0 ? ((value / totalIncomeFarmers) * 100).toFixed(1) : '0.0';
return `${value} (${percentage}%)`;
}
},
xaxis: {
categories: ['< Rp1 juta', 'Rp1 - 3 juta', 'Rp3 - 5 juta', 'Rp5 - 10 juta', '> Rp10 juta'],
labels: {
style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily },
formatter: function (value) {
return Math.floor(value);
}
},
axisBorder: { show: false },
axisTicks: { show: false },
title: {
text: 'Petani',
style: { color: legendColor, fontSize: '12px', fontFamily: fontFamily, fontWeight: 400 }
}
},
yaxis: {
labels: { style: { colors: legendColor, fontSize: '12px', fontFamily: fontFamily } }
},
grid: {
borderColor: config.colors.borderColor,
strokeDashArray: 5,
xaxis: { lines: { show: true } },
yaxis: { lines: { show: false } },
padding: { right: 55 }
},
legend: { show: false },
tooltip: {
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
const value = series[seriesIndex][dataPointIndex];
const label = w.globals.labels[dataPointIndex];
const percentage = totalIncomeFarmers > 0 ? ((value / totalIncomeFarmers) * 100).toFixed(1) : '0.0';
return `
<div style="background:${config.colors.info}; color:#fff; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
${label}: <strong>${value} petani (${percentage}%)</strong>
</div>
`;
}
}
};
new ApexCharts(incomeChartEl, incomeChartConfig).render();
}
loadFarmerTable(1);
document.addEventListener(
'click',
function (event) {
const row = event.target.closest('.farmer-row');
if (!row) { return; }
const petaniId = row.dataset.id;
if (!petaniId) { return; }
window.location.href = `${farmerProfileUrl}/${petaniId}`;
}
);
});
</script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<script>
const wilayah = @json($wilayah);
function fillSelect($select, data, valueField, textField, placeholder) {
$select.empty().append(
`<option value="">${placeholder}</option>`
);
data.forEach(function (item) {
$select.append(
`<option value="${item[valueField]}">${item[textField]}</option>`
);
});
$select.trigger('change.select2');
}
$('#filter-provinsi').select2().on('change', function () {
console.log('change provinsi');
let provinsiId = $(this).val();
fillSelect($('#filter-kabkota'), [], 'id', 'nama', 'Semua Kabupaten/Kota');
fillSelect($('#filter-kecamatan'), [], 'id', 'nama', 'Semua Kecamatan');
fillSelect($('#filter-desa'), [], 'id', 'nama', 'Semua Desa/Kelurahan');
if (!provinsiId) {
$('#filter-kabkota, #filter-kecamatan, #filter-desa')
.prop('disabled', true);
return;
}
let provinsi = wilayah.find(x => x.id == provinsiId);
if (!provinsi) {
return;
}
let kabupaten = provinsi.kabupaten || [];
fillSelect($('#filter-kabkota'), kabupaten, 'id', 'nama', 'Semua Kabupaten/Kota');
$('#filter-kabkota').prop('disabled', false);
$('#filter-kecamatan, #filter-desa').prop('disabled', true);
let defaultKabupaten = $('#filter-kabkota').data('default');
if (defaultKabupaten) {
$('#filter-kabkota').val(defaultKabupaten).trigger('change');
}
});
$('#filter-kabkota').select2().on('change', function () {
let kabupatenId = $(this).val();
fillSelect($('#filter-kecamatan'), [], 'id', 'nama', 'Semua Kecamatan');
fillSelect($('#filter-desa'), [], 'id', 'nama', 'Semua Desa/Kelurahan');
$('#filter-desa').prop('disabled', true);
if (!kabupatenId) {
$('#filter-kecamatan').prop('disabled', true);
return;
}
// Cari kabupaten di semua provinsi
let kabupaten = null;
wilayah.forEach(function (provinsi) {
let found = (provinsi.kabupaten || []).find(
x => x.id == kabupatenId
);
if (found) {
kabupaten = found;
}
});
if (!kabupaten) {
return;
}
let kecamatan = kabupaten.kecamatan || [];
fillSelect($('#filter-kecamatan'), kecamatan, 'id', 'nama', 'Semua Kecamatan');
$('#filter-kecamatan').prop('disabled', false);
let defaultKecamatan = $('#filter-kecamatan').data('default');
if (defaultKecamatan) {
console.log('defaultKecamatan', defaultKecamatan);
$('#filter-kecamatan').val(defaultKecamatan).trigger('change');
}
});
$('#filter-kecamatan').select2().on('change', function () {
let kecamatanId = $(this).val();
fillSelect($('#filter-desa'), [], 'id', 'nama', 'Semua Desa/Kelurahan');
if (!kecamatanId) {
$('#filter-desa').prop('disabled', true);
return;
}
let kecamatan = null;
wilayah.forEach(function (provinsi) {
(provinsi.kabupaten || []).forEach(function (kabupaten) {
let found = (kabupaten.kecamatan || []).find(
x => x.id == kecamatanId
);
if (found) {
kecamatan = found;
}
});
});
if (!kecamatan) {
return;
}
let desa = kecamatan.desa || [];
fillSelect($('#filter-desa'), desa, 'id', 'nama', 'Semua Desa/Kelurahan');
$('#filter-desa').prop('disabled', false);
let defaultDesa = $('#filter-desa').data('default');
if (defaultDesa) {
console.log('default desa', defaultDesa);
$('#filter-desa').val(defaultDesa).trigger('change');
}
});
$('#filter-desa, #filter-segmen, #filter-komoditas').select2();
let defaultProvinsi = $('#filter-provinsi').data('default');
if (defaultProvinsi) {
$('#filter-provinsi')
.val(defaultProvinsi)
.trigger('change');
}
$('#btn-reset-dashboard-filter').on('click', function () {
const $form = $('#form-filter');
const action = $form.attr('action') || window.location.pathname;
const url = new URL(action, window.location.origin);
const activeTab = $('#profile-filter-tab').val();
if (activeTab) {
url.searchParams.set('tab', activeTab);
}
window.location.href = url.toString();
});
$('.data-table').DataTable({
"paging": false,
"lengthChange": true,
"searching": false,
"ordering": false,
"info": false,
"autoWidth": false,
"responsive": false,
"scrollX": true
});
let selectedDesa = null;
let selectedKomoditas = null;
let selectedSegmen = null;
$('#btn-reset-filter').on('click', function () {
selectedDesa = null;
selectedKomoditas = null;
selectedSegmen = null;
// Reset chart
chartSegmentasiPetani.resetSeries();
chartSegmentasiPetaniByKomoditas.resetSeries();
});
// Chart Dimensi dan Komponen Kesiapan Adopsi
let cardColor, labelColor, fontFamily, headingColor, shadeColor, legendColor, borderColor, barBgColor;
if (isDarkStyle) {
barBgColor = '#3d4157';
shadeColor = 'dark';
} else {
barBgColor = '#efeef0';
shadeColor = '';
}
cardColor = config.colors.cardColor;
labelColor = config.colors.textMuted;
legendColor = config.colors.bodyColor;
borderColor = config.colors.borderColor;
headingColor = config.colors.headingColor;
</script>
<script>
$(document).ready(function () {
$.ajax({
url: '{{ route('dashboard.indeks-petani.summary') }}',
type: 'GET',
data: $('#form-filter').serialize(),
dataType: 'json',
success: function (data) {
$('#count-petani').text(data.petani);
$('#count-komoditas').text(data.komoditas);
$('#sum-lahan').text(new Intl.NumberFormat('id-ID', {minimumFractionDigits: 2, maximumFractionDigits: 2}).format(data.sum_lahan));
$('#avg-lahan').text(new Intl.NumberFormat('id-ID', {minimumFractionDigits: 2, maximumFractionDigits: 2}).format(data.avg_lahan));
$('#count-desa').text(data.desa);
$('#count-kecamatan').text(data.kecamatan);
$('#avg-skor').text(new Intl.NumberFormat('id-ID', {minimumFractionDigits: 2, maximumFractionDigits: 2}).format(data.skor));
$('#avg-segmen').text(data.segmen);
}
});
})
</script>
<script>
$(document).ready(function () {
const segments = @json($segments);
// Chart Segmentasi Petani
var chartSegmentasiPetani;
function loadChartSegmentasiPetani() {
$.ajax({
url: '{{ route("dashboard.indeks-petani.segmen") }}',
type: 'GET',
data: $('#form-filter').serialize(),
dataType: 'json',
success: function(response) {
if (chartSegmentasiPetani) {
chartSegmentasiPetani.destroy();
}
var optionsSegmentasiPetani = {
series: response.series,
chart: {
type: 'donut',
width: 240,
events: {
dataPointSelection: function(event, chartContext, config) {
const segmen =
chartContext.w.config.labels[
config.dataPointIndex
];
console.log('Segmen dipilih:', segmen);
// Set filter segmen
selectedSegmen = segmen;
}
}
},
labels: @json(collect($segments)->pluck('name')->values()),
colors: @json($colors),
plotOptions: {
pie: {
borderRadius: 12,
spacing: 5,
donut: {
size: '68%',
labels: {
show: true,
total: {
show: true,
label: 'Petani',
},
},
},
},
},
stroke: {
width: 0,
},
dataLabels: {
enabled: false,
},
legend: {
show: false,
},
responsive: [
{
breakpoint: 360,
options: {
chart: {
width: 220,
},
},
},
],
};
chartSegmentasiPetani = new ApexCharts(
document.querySelector('#chart-segmentasi-petani'),
optionsSegmentasiPetani
);
chartSegmentasiPetani.render();
let html = '';
segments.forEach(function(segment, index) {
const total = response.series[index] ?? 0;
const persen = response.persentase[index] ?? 0;
html += `
<tr>
<td>
<div class="d-flex justify-content-start align-items-center gap-2">
<div class="flex-shrink-0">
<i class="icon-base ti ${segment.icon} icon-lg text-${segment.color}"></i>
</div>
<span class="text-${segment.color}">
${segment.name}
</span>
</div>
</td>
<td class="text-end pe-0">
${Number(total).toLocaleString('id-ID')}
</td>
<td class="text-end pe-0">
${Number(persen).toLocaleString('id-ID', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}%
</td>
</tr>
`;
});
$('#table-segmentasi-petani').html(html);
},
error: function(xhr) {
console.error('Gagal mengambil data segmentasi:', xhr);
}
});
}
loadChartSegmentasiPetani();
})
</script>
<script>
$(document).ready(function () {
var optionsSegmentasiPetaniByKomoditas = {
series: [],
colors: @json($colors),
chart: {
type: 'bar',
height: 260,
stacked: true,
parentHeightOffset: 0,
toolbar: {
show: false
},
events: {
dataPointSelection: function(event, chartContext, config) {
const komoditas =
config.w.config.xaxis.categories[config.dataPointIndex];
console.log('Komoditas dipilih:', komoditas);
selectedKomoditas = komoditas;
}
}
},
plotOptions: {
bar: {
horizontal: true,
},
},
stroke: {
width: 1,
colors: ['#fff'],
},
title: {
show: false,
},
xaxis: {
categories: [],
labels: {
trim: true,
hideOverlappingLabels: true,
},
},
yaxis: {
labels: {
maxWidth: 118,
style: {
fontSize: '12px',
},
},
},
tooltip: {
y: {
formatter: function(val) {
return val + ' petani';
},
},
},
fill: {
opacity: 1,
},
legend: {
position: 'top',
horizontalAlign: 'left',
offsetX: 0,
fontSize: '12px',
itemMargin: {
horizontal: 8,
vertical: 2,
},
},
};
var chartSegmentasiPetaniByKomoditas =
new ApexCharts(
document.querySelector('#chart-segmentasi-petani-komoditas'),
optionsSegmentasiPetaniByKomoditas
);
chartSegmentasiPetaniByKomoditas.render();
function loadChartSegmentasiKomoditas() {
$.ajax({
url: "{{ route('dashboard.indeks-petani.segmen.komoditas') }}",
type: "GET",
data: $('#form-filter').serialize(),
dataType: "json",
beforeSend: function() {
// optional
// tampilkan loading
},
success: function(response) {
chartSegmentasiPetaniByKomoditas.updateOptions({
xaxis: {
categories: response.categories
}
});
chartSegmentasiPetaniByKomoditas.updateSeries(
response.series
);
},
error: function(xhr) {
console.error(
'Gagal mengambil data chart:',
xhr.responseText
);
}
});
}
loadChartSegmentasiKomoditas();
})
</script>
<script>
$(document).ready(function () {
var radarDimensi = new ApexCharts($("#chart-dimensi")[0], {
chart: {
height: 240,
type: 'radar',
toolbar: {
show: false
}
},
series: [{
name: "Rata-rata Dimensi Kesiapan Adopsi",
data: []
}],
labels: [
'Sistem & Praktik Budidaya',
'Sosial Ekonomi Rumah Tangga',
'Rantai Nilai & Akses Pasar'
],
plotOptions: {
radar: {
polygons: {
strokeColors: borderColor,
connectorColors: borderColor
}
}
},
stroke: {
width: 2
},
legend: {
show: true,
fontSize: '13px',
position: 'bottom',
labels: {
colors: legendColor,
useSeriesColors: false
},
markers: {
height: 12,
width: 12
},
itemMargin: {
horizontal: 10
},
onItemHover: {
highlightDataSeries: false
}
},
colors: [config.colors.primary],
fill: {
opacity: 0.85
},
markers: {
show: true,
width: 1
},
grid: {
show: false,
padding: {
top: -25,
bottom: -5
}
},
xaxis: {
categories: ['D1', 'D2', 'D3'],
labels: {
show: true,
style: {
colors: [labelColor, labelColor, labelColor],
fontSize: '13px',
fontFamily: fontFamily
}
}
},
yaxis: {
show: true,
min: 0,
max: 5,
tickAmount: 5
},
responsive: [{
breakpoint: 769,
options: {
chart: {
height: 400
}
}
}]
});
radarDimensi.render();
function loadChartRadarDimensi() {
$.ajax({
url: "{{ route('dashboard.indeks-petani.dimensi') }}",
type: "GET",
data: $('#form-filter').serialize(),
dataType: "json",
beforeSend: function() {
// optional
// tampilkan loading
},
success: function(response) {
radarDimensi.updateSeries([{
name: "Rata-rata Dimensi Kesiapan Adopsi",
data: response.radarDimensi
}]);
},
error: function(xhr) {
console.error(
'Gagal mengambil data chart:',
xhr.responseText
);
}
});
}
loadChartRadarDimensi();
})
</script>
<script>
$(document).ready(function () {
var radarKomponen = new ApexCharts($("#chart-komponen")[0], {
chart: {
height: 240,
type: 'radar',
toolbar: {
show: false
}
},
series: [{
name: "Rata-rata Komponen Kesiapan Adopsi",
data: []
}],
labels: [
'Sistem & Praktik Budidaya',
'Sosial Ekonomi Rumah Tangga',
'Rantai Nilai & Akses Pasar'
],
plotOptions: {
radar: {
polygons: {
strokeColors: borderColor,
connectorColors: borderColor
}
}
},
stroke: {
width: 2
},
legend: {
show: true,
fontSize: '13px',
position: 'bottom',
labels: {
colors: legendColor,
useSeriesColors: false
},
markers: {
height: 12,
width: 12
},
itemMargin: {
horizontal: 10
},
onItemHover: {
highlightDataSeries: false
}
},
colors: [config.colors.primary],
fill: {
opacity: 0.85
},
markers: {
show: true,
width: 1
},
grid: {
show: false,
padding: {
top: -25,
bottom: -5
}
},
xaxis: {
categories: ['K1', 'K2', 'K3', 'K4', 'K5', 'K6'],
labels: {
show: true,
style: {
colors: [labelColor, labelColor, labelColor, labelColor, labelColor, labelColor],
fontSize: '13px',
fontFamily: fontFamily
}
}
},
yaxis: {
show: true,
min: 0,
max: 5,
tickAmount: 5
},
responsive: [{
breakpoint: 769,
options: {
chart: {
height: 400
}
}
}]
});
radarKomponen.render();
function loadChartRadarKomponen() {
$.ajax({
url: "{{ route('dashboard.indeks-petani.komponen') }}",
type: "GET",
data: $('#form-filter').serialize(),
dataType: "json",
beforeSend: function() {
// optional
// tampilkan loading
},
success: function(response) {
radarKomponen.updateSeries([{
name: "Rata-rata Komponen Kesiapan Adopsi",
data: response.radarKomponen
}]);
},
error: function(xhr) {
console.error(
'Gagal mengambil data chart:',
xhr.responseText
);
}
});
}
loadChartRadarKomponen();
})
</script>
<script>
$(document).ready(function () {
// Map Sebaran Petani
var map = L.map('map-sebaran-petani').setView([-0.789, 113.921], 5);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
const warnaSegmen = {
@foreach($segments as $segment)
"{{ $segment['name'] }}": "var(--bs-{{ $segment['color'] }})",
@endforeach
};
let selectedDesa = null;
const group = L.featureGroup().addTo(map);
function loadMapDesa() {
$.ajax({
url: "{{ route('dashboard.indeks-petani.map') }}",
type: "GET",
data: $('#form-filter').serialize(),
beforeSend: function () {
// Optional
// $('#map-loading').show();
},
success: function (desaData) {
group.clearLayers();
if (!desaData || desaData.length === 0) {
return;
}
desaData.forEach(function (desa) {
if (!desa.path) {
return;
}
let coordinates;
try {
coordinates = typeof desa.path === 'string'
? JSON.parse(desa.path)
: desa.path;
} catch (error) {
console.error('Path polygon tidak valid:', desa);
return;
}
const polygon = L.polygon(coordinates, {
color: '#666',
weight: 1,
fillColor:
warnaSegmen[desa.segmentasi?.segmen] || '#ccc',
fillOpacity: 0.7
});
polygon.desaId = desa.desa_kelurahan_id;
polygon.bindPopup(`
<b>Desa/Kel.: ${desa.desa_kelurahan ?? '-'}</b><br>
Kec.: ${desa.kecamatan ?? '-'}<br>
Kab.: ${desa.kabupaten ?? '-'}<br>
<hr>
Petani: ${desa.segmentasi?.jumlah_petani ?? 0}<br>
Indeks:
${Number(desa.segmentasi?.skor ?? 0).toFixed(2)}
<br>
Segmen:
<b>${desa.segmentasi?.segmen ?? '-'}</b>
<br>
Segmen Dominan:
<b>${desa.segmentasi?.segmen_dominan ?? '-'}</b>
(${desa.segmentasi?.jumlah_dominan ?? 0} petani)
`);
polygon.addTo(group);
});
if (group.getLayers().length > 0) {
map.fitBounds(group.getBounds(), {
padding: [20, 20]
});
}
},
error: function (xhr) {
console.error(
'Gagal mengambil data map:',
xhr.responseText
);
},
complete: function () {
// Optional
// $('#map-loading').hide();
}
});
}
loadMapDesa();
})
</script>
<script>
$(document).ready(function () {
var tableDesa = $('#table-desa').DataTable({
"paging": true,
"pageLength": 5,
"lengthChange": false,
"searching": false,
"ordering": true,
"info": false,
"autoWidth": false,
"responsive": false,
"scrollX": true,
"serverSide": false,
"processing": true,
"ajax": {
"url": "{{ route('dashboard.indeks-petani.desa') }}",
"type": "GET",
"data": function (data) {
data = $('#form-filter').serialize();
return data;
},
"dataSrc": function(json) {
return json;
},
"dataType": "json"
},
columns: [
{
data: 'desa'
},
{
data: 'jumlah_petani',
className: 'text-end',
render: function(data) {
return Number(data).toLocaleString('id-ID');
}
},
{
data: null,
render: function(data) {
return `
<span class="badge bg-${data.color ?? 'secondary'}">
${data.segmen ?? '-'}
</span>
(${Number(data.skor).toLocaleString('id-ID', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})})
`;
}
},
{
data: null,
render: function(data) {
return `
<span class="badge bg-${data.color_dominan ?? 'secondary'}">
${data.segmen_dominan ?? '-'}
</span>
(${Number(data.jumlah_dominan ?? 0).toLocaleString('id-ID')} petani)
`;
}
}
]
});
})
</script>
<script>
$(document).ready(function () {
var tablePetani = $('#table-petani').DataTable({
"paging": true,
"pageLength": 10,
"lengthChange": false,
"searching": true,
"ordering": true,
"info": true,
"autoWidth": false,
"responsive": false,
"scrollX": true,
"serverSide": false,
"processing": true,
"ajax": {
"url": "{{ route('dashboard.indeks-petani.data') }}",
"type": "GET",
"data": function (data) {
data = $('#form-filter').serialize();
return data;
},
"dataSrc": function(json) {
return json;
},
"dataType": "json"
},
columns: [
{
data: 'nama',
name: 'nama',
className: 'pe-0'
},
{
data: 'desa',
name: 'desa',
className: 'pe-0'
},
{
data: 'komoditas',
name: 'komoditas',
className: 'pe-0'
},
{
data: 'luas_lahan',
name: 'luas_lahan',
className: 'text-end pe-0',
render: function(data) {
return Number(data ?? 0).toLocaleString('id-ID', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
},
{
data: 'skor',
name: 'skor',
className: 'text-end pe-0',
render: function(data) {
if (data === null || data === '') {
return '';
}
return Number(data).toLocaleString('id-ID', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
},
{
data: null,
name: 'segmen',
className: 'pe-0',
orderable: false,
render: function(data) {
if (!data.skor || !data.segmen) {
return '';
}
return `
<span class="badge bg-${data.color ?? 'secondary'}">
${data.segmen}
</span>
`;
}
}
],
order: [
[0, 'asc']
],
createdRow: function(row, data) {
$(row)
.addClass('clickable-row')
.attr('data-url', data.url);
}
});
$('#table-petani tbody').on('click', 'tr.clickable-row', function() {
const url = $(this).data('url');
if (url) {
window.location.href = url;
}
});
})
</script>
<script>
document.addEventListener('shown.bs.tab', function (event) {
const filterTab = document.getElementById('profile-filter-tab');
const target = event.target?.getAttribute('data-bs-target');
if (filterTab && target === '#profile-tab-demografi-petani') {
filterTab.value = 'demografi-petani';
}
if (filterTab && target === '#profile-tab-indeks-petani') {
filterTab.value = 'indeks-petani';
}
if (event.target?.getAttribute('data-bs-target') === '#profile-tab-indeks-petani') {
setTimeout(function () {
if (window.jQuery?.fn?.dataTable) {
window.jQuery.fn.dataTable.tables({ visible: true, api: true }).columns.adjust();
}
window.dispatchEvent(new Event('resize'));
}, 150);
}
});
</script>
@endpush