3672 lines
150 KiB
PHP
3672 lines
150 KiB
PHP
@extends('layout.main')
|
||
|
||
@push('style')
|
||
<link rel="stylesheet" href="{{ asset('assets/vendor/libs/apex-charts/apex-charts.css') }}" />
|
||
<style>
|
||
.chart-group-header-toggle {
|
||
cursor: pointer;
|
||
background-color: rgba(var(--bs-primary-rgb, 115, 103, 240), 0.08);
|
||
border-inline-start: 4px solid var(--bs-primary, #7367f0);
|
||
box-shadow: none;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
.chart-group-header-toggle:hover {
|
||
background-color: rgba(var(--bs-primary-rgb, 115, 103, 240), 0.13);
|
||
}
|
||
.chart-group-header-toggle .card-body {
|
||
padding: 12px 16px;
|
||
}
|
||
.chart-group-header-toggle h5 {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
margin-bottom: 2px;
|
||
}
|
||
.chart-group-header-toggle p {
|
||
font-size: 0.8125rem;
|
||
line-height: 1.4;
|
||
}
|
||
.chart-group-header-toggle:focus-visible {
|
||
outline: 2px solid var(--bs-primary);
|
||
outline-offset: 3px;
|
||
}
|
||
.chart-group-icon-toggle {
|
||
width: 34px;
|
||
height: 34px;
|
||
flex-shrink: 0;
|
||
}
|
||
.chart-group-icon-toggle .icon-base {
|
||
font-size: 24px;
|
||
width: 24px;
|
||
height: 24px;
|
||
}
|
||
.readiness-score-list { display: grid; gap: 12px; }
|
||
.readiness-score-row { display: flex; align-items: baseline; gap: 10px; font-size: 0.8125rem; line-height: 1.5; }
|
||
.readiness-score-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
||
.readiness-score-name { flex: 1; min-width: 0; }
|
||
.readiness-score-value { flex: 0 0 4ch; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--bs-heading-color); font-size: 0.875rem; font-weight: 600; }
|
||
|
||
#farmerPagination .page-link {
|
||
padding: 0.4809rem;
|
||
font-size: 0.9375rem;
|
||
line-height: 1.375;
|
||
border-radius: 0.375rem;
|
||
}
|
||
#farmerPagination .pagination {
|
||
flex-wrap: wrap;
|
||
}
|
||
@media (max-width: 575.98px) {
|
||
#farmerPagination .page-link {
|
||
font-size: 0.8125rem;
|
||
min-block-size: calc(1.7501875rem + 2px);
|
||
min-inline-size: calc(1.7509515rem + 2px);
|
||
padding-block: 0.211rem;
|
||
padding-inline: 0.1635rem;
|
||
}
|
||
}
|
||
.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>
|
||
#farmer-map-shell:fullscreen {
|
||
width: 100%;
|
||
height: 100%;
|
||
background: var(--bs-body-bg);
|
||
}
|
||
#farmer-map-shell:fullscreen #map-sebaran-petani {
|
||
height: 100% !important;
|
||
}
|
||
.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-shell {
|
||
max-width: none;
|
||
width: 100%;
|
||
}
|
||
|
||
|
||
.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">
|
||
@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>
|
||
Demografi 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-fluid flex-grow-1 container-p-y px-0">
|
||
<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-12">
|
||
<div class="card chart-group-header-toggle" role="button" tabindex="0"
|
||
data-bs-toggle="collapse" data-bs-target="#demografi-charts"
|
||
aria-expanded="true" aria-controls="demografi-charts" aria-label="Sembunyikan chart">
|
||
<div class="card-body d-flex justify-content-between align-items-center gap-3">
|
||
<div>
|
||
<h5>Profil Demografi</h5>
|
||
<p class="text-body-secondary mb-0">Komposisi petani berdasarkan gender, kelompok umur, dan pendidikan.</p>
|
||
</div>
|
||
<span class="btn btn-icon btn-label-secondary btn-sm chart-group-icon-toggle" aria-hidden="true">
|
||
<i class="icon-base ti tabler-chevron-up"></i>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="collapse show chart-group-panel" id="demografi-charts">
|
||
<div class="row g-6 pt-4">
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
<div class="card-body">
|
||
<div id="genderChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="ageGroupChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="educationChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12">
|
||
<div class="card chart-group-header-toggle" role="button" tabindex="0"
|
||
data-bs-toggle="collapse" data-bs-target="#rumah-tangga-charts"
|
||
aria-expanded="true" aria-controls="rumah-tangga-charts" aria-label="Sembunyikan chart">
|
||
<div class="card-body d-flex justify-content-between align-items-center gap-3">
|
||
<div>
|
||
<h5>Sosial Ekonomi</h5>
|
||
<p class="text-body-secondary mb-0">Tanggungan keluarga, penghasilan usaha tani, dan keanggotaan kelompok tani.</p>
|
||
</div>
|
||
<span class="btn btn-icon btn-label-secondary btn-sm chart-group-icon-toggle" aria-hidden="true">
|
||
<i class="icon-base ti tabler-chevron-up"></i>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="collapse show chart-group-panel" id="rumah-tangga-charts">
|
||
<div class="row g-6 pt-4">
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="dependentChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="incomeChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<div class="card-title mb-0">
|
||
<h5 class="m-0 me-2">Status Keanggotaan Kelompok Tani</h5>
|
||
|
||
<small class="text-body-secondary">
|
||
Petani yang terdaftar di kelompok tani
|
||
</small>
|
||
</div>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="farmerGroupChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12">
|
||
<div class="card chart-group-header-toggle" role="button" tabindex="0"
|
||
data-bs-toggle="collapse" data-bs-target="#usaha-tani-charts"
|
||
aria-expanded="true" aria-controls="usaha-tani-charts" aria-label="Sembunyikan chart">
|
||
<div class="card-body d-flex justify-content-between align-items-center gap-3">
|
||
<div>
|
||
<h5>Profil Lahan</h5>
|
||
<p class="text-body-secondary mb-0">Karakteristik lahan usaha tani berdasarkan komoditas utama, luas lahan garapan, dan status kepemilikan lahan.</p>
|
||
</div>
|
||
<span class="btn btn-icon btn-label-secondary btn-sm chart-group-icon-toggle" aria-hidden="true">
|
||
<i class="icon-base ti tabler-chevron-up"></i>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="collapse show chart-group-panel" id="usaha-tani-charts">
|
||
<div class="row g-6 pt-4">
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="commodityChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="landAreaChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12 col-md-6 col-xl-4">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex align-items-start justify-content-between gap-2">
|
||
<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>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih." aria-label="Klik bagian grafik untuk memfilter Daftar Petani di bawah sesuai kategori yang dipilih.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div id="landOwnershipStatusChart"></div>
|
||
</div>
|
||
</div>
|
||
</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"
|
||
>
|
||
{{ $data['total_petani'] }} 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="clearFarmerTableFilter" class="btn btn-label-secondary d-none text-nowrap"><i class="icon-base ti tabler-filter-off me-1" aria-hidden="true"></i>Bersihkan Filter</button>
|
||
<button type="button" class="btn btn-label-secondary btn-icon" data-bs-toggle="collapse" data-bs-target="#demografi-table-filter-panel" aria-expanded="false" aria-controls="demografi-table-filter-panel" aria-label="Filter tabel" title="Filter tabel"><i class="icon-base ti tabler-filter"></i></button>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="collapse" id="demografi-table-filter-panel"><div class="card-body border-top">
|
||
<div class="row g-3">
|
||
@foreach ($tableFilters as $key => [$label, $options])
|
||
<div class="col-12 col-sm-6 col-lg-4">
|
||
<label class="form-label" for="farmer-filter-{{ $key }}">{{ $label }}</label>
|
||
<select id="farmer-filter-{{ $key }}" class="form-select form-select-sm farmer-table-filter" data-filter="{{ $key }}">
|
||
<option value="">Semua</option>
|
||
@foreach ($options as $value => $text)
|
||
<option value="{{ $value }}">{{ $text }}</option>
|
||
@endforeach
|
||
</select>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
<small class="text-body-secondary d-block mt-3">Filter tabel mengikuti filter dashboard yang telah diterapkan.</small>
|
||
<div class="d-flex justify-content-end mt-3"><button type="button" id="applyFarmerFilter" class="btn btn-primary btn-sm">Terapkan Filter</button></div>
|
||
</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">
|
||
|
||
<tr><td colspan="8" class="text-center text-body-secondary py-5">Memuat data petani...</td></tr>
|
||
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="card-footer d-flex flex-wrap justify-content-between align-items-center gap-3">
|
||
<small class="text-body-secondary" id="farmerTableInfo">Memuat data petani...</small>
|
||
|
||
<div id="farmerPagination"></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-fluid flex-grow-1 container-p-y px-0">
|
||
<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">Kategori Indeks:</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="py-4">
|
||
<div class="card chart-group-header-toggle" role="button" tabindex="0"
|
||
data-bs-toggle="collapse" data-bs-target="#indeks-segmentasi-charts"
|
||
aria-expanded="true" aria-controls="indeks-segmentasi-charts" aria-label="Sembunyikan chart">
|
||
<div class="card-body d-flex justify-content-between align-items-center gap-3">
|
||
<div>
|
||
<h5>Indeks Petani</h5>
|
||
<p class="text-body-secondary mb-0">Komposisi petani menurut tingkat kesiapan adopsi, secara keseluruhan dan pada setiap komoditas.</p>
|
||
</div>
|
||
<span class="btn btn-icon btn-label-secondary btn-sm chart-group-icon-toggle" aria-hidden="true">
|
||
<i class="icon-base ti tabler-chevron-up"></i>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="collapse show chart-group-panel" id="indeks-segmentasi-charts">
|
||
<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-start gap-2">
|
||
<div class="card-title mb-0">
|
||
<h5 class="m-0 me-2">Distribusi Indeks Petani</h5>
|
||
<p class="card-subtitle">Jumlah dan proporsi petani pada setiap segmen kesiapan adopsi.</p>
|
||
</div>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik segmen pada grafik untuk memfilter Daftar Petani di bawah." aria-label="Klik segmen pada grafik untuk memfilter Daftar Petani di bawah.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</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-start gap-2">
|
||
<div class="card-title mb-0">
|
||
<h5 class="m-0 me-2">Distribusi Indeks Petani</h5>
|
||
<p class="card-subtitle">Perbandingan komposisi segmen kesiapan adopsi petani antar-komoditas.</p>
|
||
|
||
</div>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik bagian batang untuk memfilter Daftar Petani di bawah berdasarkan komoditas dan segmen." aria-label="Klik bagian batang untuk memfilter Daftar Petani di bawah berdasarkan komoditas dan segmen.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="segment-commodity-chart" id="chart-segmentasi-petani-komoditas"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="py-4">
|
||
<div class="card chart-group-header-toggle" role="button" tabindex="0"
|
||
data-bs-toggle="collapse" data-bs-target="#indeks-kesiapan-charts"
|
||
aria-expanded="true" aria-controls="indeks-kesiapan-charts" aria-label="Sembunyikan chart">
|
||
<div class="card-body d-flex justify-content-between align-items-center gap-3">
|
||
<div>
|
||
<h5>Dimensi dan Komponen Kesiapan Adopsi</h5>
|
||
<p class="text-body-secondary mb-0">Perbandingan skor dimensi dan komponen kesiapan adopsi petani.</p>
|
||
</div>
|
||
<span class="btn btn-icon btn-label-secondary btn-sm chart-group-icon-toggle" aria-hidden="true">
|
||
<i class="icon-base ti tabler-chevron-up"></i>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="collapse show chart-group-panel" id="indeks-kesiapan-charts">
|
||
<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">Dimensi Kesiapan Adopsi</h5>
|
||
<p class="card-subtitle">Rata-rata skor budidaya, sosial ekonomi rumah tangga, serta rantai nilai dan akses pasar.</p>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div id="chart-dimensi"></div>
|
||
<p class="small text-body-secondary text-center mb-0">Skala skor 0–5</p>
|
||
<div id="chart-dimensi-scores" class="readiness-score-list mt-3" aria-live="polite"><p class="text-body-secondary small mb-0">Memuat informasi skor…</p></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">Komponen Kesiapan Adopsi</h5>
|
||
<p class="card-subtitle">Rata-rata skor enam komponen yang membentuk kesiapan adopsi petani.</p>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div id="chart-komponen"></div>
|
||
<p class="small text-body-secondary text-center mb-0">Skala skor 0–5</p>
|
||
<div id="chart-komponen-scores" class="readiness-score-list mt-3" aria-live="polite"><p class="text-body-secondary small mb-0">Memuat informasi skor…</p></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="py-4">
|
||
<div class="card chart-group-header-toggle" role="button" tabindex="0"
|
||
data-bs-toggle="collapse" data-bs-target="#indeks-wilayah-charts"
|
||
aria-expanded="true" aria-controls="indeks-wilayah-charts" aria-label="Sembunyikan chart">
|
||
<div class="card-body d-flex justify-content-between align-items-center gap-3">
|
||
<div>
|
||
<h5>Sebaran wilayah petani</h5>
|
||
<p class="text-body-secondary mb-0">Peta dan komposisi segmen kesiapan adopsi petani per desa/kelurahan.</p>
|
||
</div>
|
||
<span class="btn btn-icon btn-label-secondary btn-sm chart-group-icon-toggle" aria-hidden="true">
|
||
<i class="icon-base ti tabler-chevron-up"></i>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="collapse show chart-group-panel" id="indeks-wilayah-charts">
|
||
<div class="row g-6 py-4">
|
||
<div class="col-lg-12 col-sm-12">
|
||
<div class="card card-border-shadow-danger h-100">
|
||
<div class="card-header d-flex justify-content-between align-items-start gap-2">
|
||
<div class="card-title mb-0">
|
||
<h5 class="m-0 me-2">Peta Sebaran</h5>
|
||
<p class="card-subtitle">Warna wilayah menunjukkan kategori rata-rata indeks kesiapan adopsi petani di setiap desa/kelurahan.</p>
|
||
</div>
|
||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary chart-filter-help flex-shrink-0"
|
||
data-bs-toggle="tooltip" data-bs-trigger="hover focus click" data-bs-placement="top"
|
||
title="Klik wilayah desa/kelurahan untuk melihat rincian dan memfilter Daftar Petani di bawah." aria-label="Klik wilayah desa/kelurahan untuk melihat rincian dan memfilter Daftar Petani di bawah.">
|
||
<i class="icon-base ti tabler-help-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
<div class="card-body">
|
||
<div id="farmer-map-shell" class="position-relative">
|
||
<button type="button" id="farmer-map-fullscreen" class="btn btn-light btn-sm shadow-sm position-absolute top-0 end-0 m-3" style="z-index: 1000;" aria-label="Buka peta layar penuh" title="Buka peta layar penuh">
|
||
<i class="icon-base ti tabler-maximize"></i>
|
||
</button>
|
||
<div id="map-sebaran-petani" style="height: 430px;"></div>
|
||
</div>
|
||
<span class="small text-muted">Klik wilayah desa/kelurahan untuk melihat rincian dan menyaring daftar petani.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-12 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">Tabel Sebaran</h5>
|
||
<p class="card-subtitle">Jumlah dan persentase petani pada setiap segmen kesiapan adopsi serta kategori belum lengkap, dikelompokkan menurut desa/kelurahan.</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">Total Petani</th>
|
||
<th class="text-end text-danger pe-0">Pemula</th>
|
||
<th class="text-end text-info pe-0">Perintis</th>
|
||
<th class="text-end text-warning pe-0">Pemerhati</th>
|
||
<th class="text-end text-success pe-0">Penggerak</th>
|
||
<th class="text-end text-secondary pe-0">Belum lengkap</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</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 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="indexFarmerTotalBadge">0 petani</span>
|
||
</div>
|
||
<small class="text-body-secondary">Rincian wilayah, komoditas, luas lahan, skor kesiapan adopsi, dan segmen setiap petani.</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="search" id="indexFarmerSearch" class="form-control" placeholder="Cari petani..." aria-label="Cari petani pada tabel indeks">
|
||
</div>
|
||
<button type="button" id="btn-reset-filter" class="btn btn-label-secondary d-none text-nowrap"><i class="icon-base ti tabler-filter-off me-1" aria-hidden="true"></i>Bersihkan Filter</button>
|
||
<button type="button" class="btn btn-label-secondary btn-icon" data-bs-toggle="collapse" data-bs-target="#index-table-filter-panel" aria-expanded="false" aria-controls="index-table-filter-panel" aria-label="Filter tabel" title="Filter tabel"><i class="icon-base ti tabler-filter"></i></button>
|
||
</div>
|
||
</div>
|
||
<div class="collapse" id="index-table-filter-panel"><div class="card-body border-top">
|
||
<div class="row g-3">
|
||
<div class="col-12 col-md-4">
|
||
<label class="form-label" for="index-table-desa">Desa/Kelurahan</label>
|
||
<select id="index-table-desa" class="form-select form-select-sm index-table-filter" data-column="1"><option value="">Semua Desa/Kelurahan</option></select>
|
||
</div>
|
||
<div class="col-12 col-md-4">
|
||
<label class="form-label" for="index-table-komoditas">Komoditas</label>
|
||
<select id="index-table-komoditas" class="form-select form-select-sm index-table-filter" data-column="2"><option value="">Semua Komoditas</option></select>
|
||
</div>
|
||
<div class="col-12 col-md-4">
|
||
<label class="form-label" for="index-table-segmen">Segmen</label>
|
||
<select id="index-table-segmen" class="form-select form-select-sm index-table-filter" data-column="5"><option value="">Semua Segmen</option></select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="d-flex justify-content-end mt-3"><button type="button" id="applyIndexTableFilter" class="btn btn-primary btn-sm">Terapkan Filter</button></div></div>
|
||
<div class="card-body">
|
||
<table id="table-petani" class="table table-hover">
|
||
<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>
|
||
'use strict';
|
||
|
||
const dashboardFilters = @json($dashboardFilters);
|
||
const dashboardFilterParams = new URLSearchParams();
|
||
Object.entries(dashboardFilters).forEach(([key, value]) => {
|
||
if (value !== null && value !== '') {
|
||
dashboardFilterParams.set(key, value);
|
||
}
|
||
});
|
||
|
||
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
|
||
};
|
||
|
||
const farmerSearchInput = document.querySelector('#farmerSearch');
|
||
const farmerFilterSelects = document.querySelectorAll('.farmer-table-filter');
|
||
const farmerClearButton = document.querySelector('#clearFarmerTableFilter');
|
||
|
||
let searchTimer = null;
|
||
let farmerTableRequest = null;
|
||
|
||
function escapeHtml(value) {
|
||
if (value === null || value === undefined) {
|
||
return '';
|
||
}
|
||
return String(value)
|
||
.replaceAll('&', '&')
|
||
.replaceAll('<', '<')
|
||
.replaceAll('>', '>')
|
||
.replaceAll('"', '"')
|
||
.replaceAll("'", ''');
|
||
}
|
||
|
||
function formatLuas(value) {
|
||
const number = Number(value || 0);
|
||
if (number <= 0) {
|
||
return '-';
|
||
}
|
||
return number.toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' ha';
|
||
}
|
||
|
||
function updateFarmerClearFilter() {
|
||
const hasFilters = Object.values(activeFilters).some((value) => value !== null && value !== undefined && value !== '');
|
||
const hasSearch = Boolean(farmerSearchInput?.value.trim());
|
||
farmerClearButton.classList.toggle('d-none', !hasFilters && !hasSearch);
|
||
}
|
||
|
||
async function loadFarmerTable(page = 1) {
|
||
updateFarmerClearFilter();
|
||
farmerTableRequest?.abort();
|
||
const request = new AbortController();
|
||
farmerTableRequest = request;
|
||
const searchInput = farmerSearchInput;
|
||
const search = searchInput ? searchInput.value.trim() : '';
|
||
const params = new URLSearchParams();
|
||
|
||
params.set('page', page);
|
||
|
||
dashboardFilterParams.forEach((value, key) => 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',
|
||
signal: request.signal,
|
||
headers: {
|
||
'Accept': 'application/json',
|
||
'X-Requested-With': 'XMLHttpRequest'
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP Error ${response.status}`);
|
||
}
|
||
|
||
const result = await response.json();
|
||
if (!request.signal.aborted) renderFarmerTable(result);
|
||
} catch (error) {
|
||
if (error.name === 'AbortError') return;
|
||
console.error('Gagal memuat tabel petani:', error);
|
||
if (tableBody) {
|
||
tableBody.innerHTML = '<tr><td colspan="8" class="text-center text-danger py-5">Data gagal dimuat. Silakan coba kembali.</td></tr>';
|
||
}
|
||
}
|
||
}
|
||
|
||
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 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>
|
||
`;
|
||
|
||
html = html.replace('<ul class="pagination mb-0">', '<ul class="pagination mb-0">' +
|
||
'<li class="page-item ' + (pagination.current_page === 1 ? 'disabled' : '') + '">' +
|
||
'<button type="button" class="page-link farmer-page" data-page="1" aria-label="Halaman pertama"><i class="icon-base ti tabler-chevrons-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 += '<li class="page-item ' + (currentPage === lastPage ? 'disabled' : '') + '">' +
|
||
'<button type="button" class="page-link farmer-page" data-page="' + lastPage + '" aria-label="Ke halaman terakhir" title="Ke halaman terakhir"><i class="icon-base ti tabler-chevrons-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;
|
||
}
|
||
|
||
farmerFilterSelects.forEach((select) => {
|
||
select.value = activeFilters[select.dataset.filter] ?? '';
|
||
});
|
||
loadFarmerTable(1);
|
||
}
|
||
|
||
function resetFarmerFilter() {
|
||
clearTimeout(searchTimer);
|
||
Object.keys(activeFilters).forEach((key) => { activeFilters[key] = null; });
|
||
|
||
const searchInput = farmerSearchInput;
|
||
if (searchInput) {
|
||
searchInput.value = '';
|
||
}
|
||
|
||
farmerFilterSelects.forEach((select) => {
|
||
select.value = activeFilters[select.dataset.filter] ?? '';
|
||
});
|
||
loadFarmerTable(1);
|
||
}
|
||
|
||
document.querySelector('#applyFarmerFilter').addEventListener('click', function () {
|
||
farmerFilterSelects.forEach((select) => {
|
||
activeFilters[select.dataset.filter] = select.value || null;
|
||
});
|
||
loadFarmerTable(1);
|
||
});
|
||
|
||
document.addEventListener('input', function (event) {
|
||
if (event.target.id !== 'farmerSearch') {
|
||
return;
|
||
}
|
||
updateFarmerClearFilter();
|
||
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('#clearFarmerTableFilter');
|
||
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: ['#c7c2f9', '#9d94f4', '#7367f0', '#5048a8', '#2e2960'],
|
||
plotOptions: {
|
||
bar: {
|
||
borderRadius: 4,
|
||
columnWidth: '45%',
|
||
distributed: true,
|
||
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:${w.config.colors[dataPointIndex % w.config.colors.length]}; 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: ['#e9f9f0', '#a9e8c5', '#68d79a', '#28c76f', '#1c8b4d', '#104f2c'],
|
||
plotOptions: {
|
||
bar: {
|
||
distributed: true,
|
||
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:${w.config.colors[dataPointIndex % w.config.colors.length]}; 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: ['#ffb7b9', '#ff4c51', '#b23538', '#661e20'],
|
||
plotOptions: {
|
||
bar: {
|
||
distributed: true,
|
||
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:${w.config.colors[dataPointIndex % w.config.colors.length]}; 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: ['#ffbb7b', '#ff9f43', '#b26f2e', '#663f1a'],
|
||
plotOptions: {
|
||
bar: {
|
||
distributed: true,
|
||
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:${w.config.colors[dataPointIndex % w.config.colors.length]}; 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: ['#99e3ec', '#4ccede', '#00bad1', '#008292', '#004a53'],
|
||
plotOptions: {
|
||
bar: {
|
||
distributed: true,
|
||
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:${w.config.colors[dataPointIndex % w.config.colors.length]}; 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://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');
|
||
$('#filter-kabkota').removeData('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');
|
||
$('#filter-kecamatan').removeData('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');
|
||
$('#filter-desa').removeData('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
|
||
});
|
||
|
||
|
||
|
||
|
||
|
||
// 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: dashboardFilterParams.toString(),
|
||
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;
|
||
let distributionLoading = false;
|
||
|
||
function loadChartSegmentasiPetani() {
|
||
const container = document.querySelector('#chart-segmentasi-petani');
|
||
if (!container.clientWidth || distributionLoading || chartSegmentasiPetani) return;
|
||
distributionLoading = true;
|
||
$.ajax({
|
||
url: '{{ route("dashboard.indeks-petani.segmen") }}',
|
||
type: 'GET',
|
||
data: dashboardFilterParams.toString(),
|
||
dataType: 'json',
|
||
success: function(response) {
|
||
if (chartSegmentasiPetani) {
|
||
chartSegmentasiPetani.destroy();
|
||
}
|
||
var optionsSegmentasiPetani = {
|
||
series: response.series.map((value) => Number(value) || 0),
|
||
chart: {
|
||
type: 'donut',
|
||
width: '100%',
|
||
height: 280,
|
||
events: {
|
||
dataPointSelection: function(event, chartContext, config) {
|
||
|
||
const segmen =
|
||
chartContext.w.config.labels[
|
||
config.dataPointIndex
|
||
];
|
||
|
||
|
||
|
||
window.applyIndexFarmerFilter?.(5, 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().catch(function (error) {
|
||
chartSegmentasiPetani = null;
|
||
console.error('Gagal merender distribusi indeks:', error);
|
||
});
|
||
|
||
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) {
|
||
distributionLoading = false;
|
||
console.error('Gagal mengambil data segmentasi:', xhr);
|
||
}
|
||
});
|
||
}
|
||
|
||
document.addEventListener('shown.bs.tab', loadChartSegmentasiPetani);
|
||
document.getElementById('indeks-segmentasi-charts').addEventListener('shown.bs.collapse', loadChartSegmentasiPetani);
|
||
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];
|
||
|
||
|
||
const segmen = chartContext.w.config.series[config.seriesIndex]?.name;
|
||
window.applyIndexFarmerFilter?.(2, komoditas, segmen);
|
||
}
|
||
}
|
||
},
|
||
|
||
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,
|
||
},
|
||
},
|
||
};
|
||
|
||
let chartSegmentasiPetaniByKomoditas;
|
||
|
||
function loadChartSegmentasiKomoditas() {
|
||
|
||
$.ajax({
|
||
url: "{{ route('dashboard.indeks-petani.segmen.komoditas') }}",
|
||
type: "GET",
|
||
data: dashboardFilterParams.toString(),
|
||
dataType: "json",
|
||
beforeSend: function() {
|
||
// optional
|
||
// tampilkan loading
|
||
},
|
||
success: function(response) {
|
||
|
||
chartSegmentasiPetaniByKomoditas.updateOptions({
|
||
xaxis: { categories: response.categories },
|
||
series: response.series.map((series) => ({
|
||
...series,
|
||
data: series.data.map((value) => Number(value) || 0)
|
||
}))
|
||
});
|
||
},
|
||
error: function(xhr) {
|
||
console.error(
|
||
'Gagal mengambil data chart:',
|
||
xhr.responseText
|
||
);
|
||
}
|
||
});
|
||
}
|
||
|
||
function initializeCommodityDistribution() {
|
||
const container = document.querySelector('#chart-segmentasi-petani-komoditas');
|
||
if (!container.clientWidth || chartSegmentasiPetaniByKomoditas) return;
|
||
chartSegmentasiPetaniByKomoditas = new ApexCharts(container, optionsSegmentasiPetaniByKomoditas);
|
||
chartSegmentasiPetaniByKomoditas.render().then(loadChartSegmentasiKomoditas).catch(function (error) {
|
||
chartSegmentasiPetaniByKomoditas = null;
|
||
console.error('Gagal merender distribusi indeks per komoditas:', error);
|
||
});
|
||
}
|
||
document.addEventListener('shown.bs.tab', initializeCommodityDistribution);
|
||
document.getElementById('indeks-segmentasi-charts').addEventListener('shown.bs.collapse', initializeCommodityDistribution);
|
||
initializeCommodityDistribution();
|
||
})
|
||
</script>
|
||
<script>
|
||
function formatReadinessScore(value) {
|
||
if (value === null || value === undefined || value === '' || !Number.isFinite(Number(value))) return '—';
|
||
return Number(value).toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||
}
|
||
|
||
function spaceReadinessRadarLabels(chart) {
|
||
chart.el.querySelectorAll('.apexcharts-radar-series .apexcharts-xaxis-label').forEach(function (label) {
|
||
var x = Number(label.getAttribute('x')) || 0;
|
||
var y = Number(label.getAttribute('y')) || 0;
|
||
var dx = Math.abs(x) > 10 ? (x > 0 ? 16 : -16) : 0;
|
||
var dy = Math.abs(x) <= 10 ? (y > 0 ? 20 : -20) : 0;
|
||
label.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
|
||
});
|
||
var categoryBoxes = Array.from(chart.el.querySelectorAll('.apexcharts-radar-series .apexcharts-xaxis-label'), function (label) { return label.getBoundingClientRect(); });
|
||
var scoreLabels = chart.el.querySelectorAll('.apexcharts-datalabels .apexcharts-datalabel');
|
||
scoreLabels.forEach(function (label, index) {
|
||
var angle = (2 * Math.PI * index / chart.w.config.labels.length) - Math.PI / 2;
|
||
var x = Number(label.getAttribute('x')) || 0;
|
||
var y = Number(label.getAttribute('y')) || 0;
|
||
var radius = Math.sqrt(x * x + y * y);
|
||
var distance = Math.max(18, 30 - radius);
|
||
var dx = Math.cos(angle) * distance;
|
||
var dy = Math.sin(angle) * distance;
|
||
label.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
|
||
label.setAttribute('text-anchor', Math.abs(dx) < 5 ? 'middle' : (dx > 0 ? 'start' : 'end'));
|
||
label.style.paintOrder = 'stroke';
|
||
label.style.stroke = config.colors.cardColor;
|
||
label.style.strokeWidth = '3px';
|
||
label.style.strokeLinejoin = 'round';
|
||
label.style.pointerEvents = 'none';
|
||
// ApexCharts moves the score group outside the series after rendering.
|
||
// Keep a clear gap from category labels even when a score reaches 5.
|
||
for (var attempt = 0; attempt < 7; attempt++) {
|
||
var scoreBox = label.getBoundingClientRect();
|
||
var overlapsCategory = categoryBoxes.some(function (box) {
|
||
return scoreBox.left < box.right + 10 && scoreBox.right > box.left - 10 &&
|
||
scoreBox.top < box.bottom + 10 && scoreBox.bottom > box.top - 10;
|
||
});
|
||
if (!overlapsCategory || distance <= 12) break;
|
||
distance = Math.max(12, distance - 4);
|
||
dx = Math.cos(angle) * distance;
|
||
dy = Math.sin(angle) * distance;
|
||
label.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
|
||
}
|
||
});
|
||
}
|
||
|
||
function readinessRadarOptions(title, labels, categories, pointColors) {
|
||
return {
|
||
chart: {
|
||
height: 420, type: 'radar', toolbar: { show: false }, animations: { enabled: false },
|
||
events: { mounted: spaceReadinessRadarLabels, updated: spaceReadinessRadarLabels }
|
||
},
|
||
series: [{ name: title, data: [] }],
|
||
labels: labels,
|
||
plotOptions: { radar: { polygons: { strokeColors: borderColor, connectorColors: borderColor } } },
|
||
stroke: { width: 2 },
|
||
legend: { show: false },
|
||
colors: [config.colors.primary],
|
||
fill: { opacity: 0.12 },
|
||
markers: {
|
||
size: 5, strokeWidth: 2, strokeColors: config.colors.cardColor, hover: { sizeOffset: 2 },
|
||
discrete: pointColors.map(function (color, index) {
|
||
return { seriesIndex: 0, dataPointIndex: index, fillColor: color, strokeColor: config.colors.cardColor, size: 6 };
|
||
})
|
||
},
|
||
dataLabels: {
|
||
enabled: true,
|
||
formatter: formatReadinessScore,
|
||
offsetX: 0, offsetY: 0,
|
||
style: { fontSize: '12px', fontFamily: fontFamily, fontWeight: 600, colors: [config.colors.headingColor] },
|
||
background: { enabled: false },
|
||
dropShadow: { enabled: false }
|
||
},
|
||
tooltip: { enabled: false },
|
||
grid: { show: false, padding: { top: 28, bottom: 24 } },
|
||
xaxis: { categories: categories, labels: { show: true, style: { colors: labels.map(function () { return legendColor; }), fontSize: '13px', fontFamily: fontFamily, fontWeight: 500 } } },
|
||
yaxis: {
|
||
show: false, min: 0, max: 5, tickAmount: 5,
|
||
labels: { show: false }
|
||
},
|
||
responsive: [{ breakpoint: 769, options: { chart: { height: 420 }, xaxis: { labels: { style: { fontSize: '11px' } } } } }]
|
||
};
|
||
}
|
||
|
||
function updateReadinessScoreLegend(chart, containerId, values, colors) {
|
||
var container = document.getElementById(containerId);
|
||
var fragment = document.createDocumentFragment();
|
||
chart.w.config.labels.forEach(function (label, index) {
|
||
var row = document.createElement('div');
|
||
row.className = 'readiness-score-row';
|
||
var dot = document.createElement('span');
|
||
dot.className = 'readiness-score-dot';
|
||
dot.style.backgroundColor = colors[index];
|
||
dot.setAttribute('aria-hidden', 'true');
|
||
var name = document.createElement('span');
|
||
name.className = 'readiness-score-name';
|
||
name.textContent = label;
|
||
var score = document.createElement('strong');
|
||
score.className = 'readiness-score-value';
|
||
score.textContent = formatReadinessScore(values[index]);
|
||
row.append(dot, name, score);
|
||
fragment.appendChild(row);
|
||
});
|
||
container.replaceChildren(fragment);
|
||
}
|
||
</script>
|
||
<script>
|
||
$(document).ready(function () {
|
||
var palette = [config.colors.success, config.colors.primary, config.colors.warning, config.colors.info, config.colors.danger, config.colors.secondary];
|
||
[
|
||
{ id: 'dimensi', key: 'radarDimensi', url: "{{ route('dashboard.indeks-petani.dimensi') }}", title: "Dimensi Kesiapan Adopsi", labels: ["Sistem & Praktik Budidaya","Sosial Ekonomi Rumah Tangga","Rantai Nilai & Akses Pasar"], categories: [["Sistem & Praktik","Budidaya"],["Sosial Ekonomi","Rumah Tangga"],["Rantai Nilai &","Akses Pasar"]] },
|
||
{ id: 'komponen', key: 'radarKomponen', url: "{{ route('dashboard.indeks-petani.komponen') }}", title: "Komponen Kesiapan Adopsi", labels: ["Motivasi & Kapasitas Adopsi","Kondisi Ekonomi Rumah Tangga","Praktik Budidaya & GAP","Keterlibatan Kelembagaan","Akses & Kebebasan Keuangan","Rantai Nilai & Akses Pasar"], categories: [["Motivasi & Kapasitas","Adopsi"],["Kondisi Ekonomi","Rumah Tangga"],["Praktik Budidaya","& GAP"],["Keterlibatan","Kelembagaan"],["Akses & Kebebasan","Keuangan"],["Rantai Nilai &","Akses Pasar"]] }
|
||
].forEach(function (definition) {
|
||
var pointColors = palette.slice(0, definition.labels.length);
|
||
var chart = new ApexCharts(document.getElementById('chart-' + definition.id), readinessRadarOptions(definition.title, definition.labels, definition.categories, pointColors));
|
||
chart.render().then(function () {
|
||
return $.ajax({
|
||
url: definition.url,
|
||
type: 'GET',
|
||
data: dashboardFilterParams.toString(),
|
||
dataType: 'json'
|
||
}).then(function (response) {
|
||
var values = response[definition.key];
|
||
if (!Array.isArray(values)) throw new Error('Data radar tidak valid');
|
||
updateReadinessScoreLegend(chart, 'chart-' + definition.id + '-scores', values, pointColors);
|
||
return chart.updateSeries([{ name: definition.title, data: values }]);
|
||
});
|
||
}).catch(function (error) {
|
||
document.getElementById('chart-' + definition.id + '-scores').textContent = 'Informasi skor belum dapat dimuat.';
|
||
console.error('Gagal memuat radar ' + definition.id + ':', error);
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
<script>
|
||
$(document).ready(function () {
|
||
// Map Sebaran Petani
|
||
var map = L.map('map-sebaran-petani').setView([-0.789, 113.921], 5);
|
||
const mapShell = document.getElementById('farmer-map-shell');
|
||
const fullscreenButton = document.getElementById('farmer-map-fullscreen');
|
||
if (!document.fullscreenEnabled || !mapShell.requestFullscreen) {
|
||
fullscreenButton.hidden = true;
|
||
}
|
||
fullscreenButton.addEventListener('click', async function () {
|
||
try {
|
||
if (document.fullscreenElement === mapShell) {
|
||
await document.exitFullscreen();
|
||
} else {
|
||
await mapShell.requestFullscreen();
|
||
}
|
||
} catch (error) {
|
||
console.error('Tidak dapat membuka peta layar penuh:', error);
|
||
}
|
||
});
|
||
document.addEventListener('fullscreenchange', function () {
|
||
const isFullscreen = document.fullscreenElement === mapShell;
|
||
fullscreenButton.innerHTML = '<i class="icon-base ti ' + (isFullscreen ? 'tabler-minimize' : 'tabler-maximize') + '"></i>';
|
||
const label = isFullscreen ? 'Keluar dari layar penuh' : 'Buka peta layar penuh';
|
||
fullscreenButton.setAttribute('aria-label', label);
|
||
fullscreenButton.title = label;
|
||
requestAnimationFrame(focusMapData);
|
||
});
|
||
|
||
document.getElementById('indeks-wilayah-charts').addEventListener('shown.bs.collapse', function () {
|
||
focusMapData();
|
||
if (window.jQuery?.fn?.dataTable) {
|
||
window.jQuery.fn.dataTable.tables({ visible: true, api: true }).columns.adjust();
|
||
}
|
||
});
|
||
document.addEventListener('shown.bs.tab', function (event) {
|
||
if (event.target.getAttribute('data-bs-target') === '#profile-tab-indeks-petani') {
|
||
focusMapData();
|
||
}
|
||
});
|
||
|
||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||
maxZoom: 19,
|
||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||
}).addTo(map);
|
||
|
||
const warnaSegmen = {
|
||
@foreach($segments as $segment)
|
||
"{{ $segment['name'] }}": "var(--bs-{{ $segment['color'] }})",
|
||
@endforeach
|
||
};
|
||
|
||
|
||
const group = L.featureGroup().addTo(map);
|
||
|
||
function focusMapData() {
|
||
const container = map.getContainer();
|
||
if (!container.clientWidth || !container.clientHeight) {
|
||
return;
|
||
}
|
||
map.invalidateSize();
|
||
const bounds = group.getBounds();
|
||
if (bounds.isValid()) {
|
||
map.fitBounds(bounds, {
|
||
padding: [32, 32],
|
||
maxZoom: 14,
|
||
animate: false
|
||
});
|
||
}
|
||
}
|
||
|
||
function loadMapDesa() {
|
||
|
||
$.ajax({
|
||
url: "{{ route('dashboard.indeks-petani.map') }}",
|
||
type: "GET",
|
||
data: dashboardFilterParams.toString(),
|
||
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.on('click', function () {
|
||
window.applyIndexFarmerFilter?.(1, desa.desa_kelurahan);
|
||
});
|
||
polygon.addTo(group);
|
||
});
|
||
|
||
requestAnimationFrame(focusMapData);
|
||
},
|
||
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 = dashboardFilterParams.toString();
|
||
return data;
|
||
},
|
||
"dataSrc": function(json) {
|
||
return json;
|
||
},
|
||
"dataType": "json"
|
||
},
|
||
columns: [
|
||
{ data: 'desa', render: $.fn.dataTable.render.text() },
|
||
{
|
||
data: 'jumlah_petani', className: 'text-end',
|
||
render: function (data, type) {
|
||
return type === 'display' ? Number(data).toLocaleString('id-ID') : Number(data);
|
||
}
|
||
}
|
||
].concat(['pemula', 'perintis', 'pemerhati', 'penggerak', 'belum_lengkap'].map(function (segment) {
|
||
return {
|
||
data: 'segments.' + segment,
|
||
className: 'text-end text-nowrap',
|
||
render: function (data, type) {
|
||
var count = Number(data && data.count) || 0;
|
||
if (type !== 'display') return count;
|
||
var percentage = Number(data && data.percentage || 0).toLocaleString('id-ID', { maximumFractionDigits: 2 });
|
||
return '<span class="fw-semibold text-' + (data && data.color || 'secondary') + '">' + count.toLocaleString('id-ID') +
|
||
'</span> <span class="text-body-secondary small">(' + percentage + '%)</span>';
|
||
}
|
||
};
|
||
}))
|
||
});
|
||
})
|
||
</script>
|
||
<script>
|
||
$(document).ready(function () {
|
||
var tablePetani = $('#table-petani').DataTable({
|
||
dom: 'rt<"card-footer d-flex flex-wrap justify-content-between align-items-center gap-3"ip>',
|
||
pagingType: 'full_numbers',
|
||
language: {
|
||
info: 'Menampilkan _START_ - _END_ dari _TOTAL_ petani',
|
||
infoEmpty: 'Menampilkan 0 - 0 dari 0 petani',
|
||
infoFiltered: '',
|
||
emptyTable: 'Tidak ada data petani sesuai filter.',
|
||
zeroRecords: 'Tidak ada data petani sesuai filter.',
|
||
paginate: {
|
||
first: '<i class="icon-base ti tabler-chevrons-left"></i>',
|
||
previous: '<i class="icon-base ti tabler-chevron-left"></i>',
|
||
next: '<i class="icon-base ti tabler-chevron-right"></i>',
|
||
last: '<i class="icon-base ti tabler-chevrons-right"></i>'
|
||
}
|
||
},
|
||
drawCallback: function () {
|
||
const api = this.api();
|
||
const hasFilter = Boolean(api.search()) || api.columns().search().toArray().some(Boolean);
|
||
$('#btn-reset-filter').toggleClass('d-none', !hasFilter);
|
||
const info = api.page.info();
|
||
$('#indexFarmerTotalBadge').text(info.recordsDisplay + ' petani');
|
||
},
|
||
"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 = dashboardFilterParams.toString();
|
||
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, type) {
|
||
if (type !== 'display') {
|
||
return data.segmen ?? '';
|
||
}
|
||
|
||
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);
|
||
}
|
||
});
|
||
|
||
window.applyIndexFarmerFilter = function (column, value, segmen) {
|
||
if (value === null || value === undefined) return;
|
||
const escaped = $.fn.dataTable.util.escapeRegex(String(value));
|
||
const search = '^' + escaped + '$';
|
||
const nextValue = tablePetani.column(column).search() === search ? '' : String(value);
|
||
tablePetani.column(column).search(nextValue ? search : '', true, false);
|
||
$('.index-table-filter[data-column="' + column + '"]').val(nextValue);
|
||
if (segmen !== undefined) {
|
||
tablePetani.column(5).search('^' + $.fn.dataTable.util.escapeRegex(segmen) + '$', true, false);
|
||
$('#index-table-segmen').val(segmen);
|
||
}
|
||
tablePetani.draw();
|
||
};
|
||
|
||
$('#indexFarmerSearch').on('input', function () { tablePetani.search(this.value).draw(); });
|
||
tablePetani.on('xhr.dt', function (event, settings, rows) {
|
||
if (!Array.isArray(rows)) return;
|
||
const fields = { 1: 'desa', 2: 'komoditas', 5: 'segmen' };
|
||
document.querySelectorAll('.index-table-filter').forEach((select) => {
|
||
const placeholder = select.options[0].text;
|
||
select.replaceChildren(new Option(placeholder, ''));
|
||
const values = [...new Set(rows.map((row) => row[fields[select.dataset.column]]).filter(Boolean))];
|
||
values.sort((a, b) => a.localeCompare(b, 'id')).forEach((value) => {
|
||
select.add(new Option(value, value));
|
||
});
|
||
});
|
||
});
|
||
$('#applyIndexTableFilter').on('click', function () {
|
||
$('.index-table-filter').each(function () {
|
||
const value = $.fn.dataTable.util.escapeRegex(this.value);
|
||
tablePetani.column(Number(this.dataset.column)).search(value ? '^' + value + '$' : '', true, false);
|
||
});
|
||
tablePetani.draw();
|
||
});
|
||
$('#btn-reset-filter').on('click', function () {
|
||
$('.index-table-filter').val('');
|
||
$('#indexFarmerSearch').val('');
|
||
|
||
|
||
|
||
tablePetani.search('').columns().search('').draw();
|
||
});
|
||
|
||
$('#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>
|
||
<script>
|
||
document.querySelectorAll('.chart-group-header-toggle').forEach((header) => {
|
||
header.addEventListener('keydown', function (event) {
|
||
if (event.target !== header || !['Enter', ' '].includes(event.key)) return;
|
||
event.preventDefault();
|
||
header.click();
|
||
});
|
||
});
|
||
document.querySelectorAll('.chart-group-panel').forEach((panel) => {
|
||
const control = document.querySelector('.chart-group-header-toggle[aria-controls="' + panel.id + '"]');
|
||
if (!control) return;
|
||
const icon = control.querySelector('.chart-group-icon-toggle i');
|
||
const syncState = () => {
|
||
const expanded = panel.classList.contains('show');
|
||
const label = expanded ? 'Sembunyikan chart' : 'Tampilkan chart';
|
||
control.setAttribute('aria-expanded', String(expanded));
|
||
control.setAttribute('aria-label', label);
|
||
control.title = label;
|
||
icon.classList.toggle('tabler-chevron-up', expanded);
|
||
icon.classList.toggle('tabler-chevron-down', !expanded);
|
||
};
|
||
syncState();
|
||
['hidden.bs.collapse', 'shown.bs.collapse'].forEach((eventName) => {
|
||
panel.addEventListener(eventName, (event) => {
|
||
if (event.target !== panel) return;
|
||
syncState();
|
||
if (eventName === 'shown.bs.collapse') window.dispatchEvent(new Event('resize'));
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
@endpush
|