Compare commits

...

10 Commits

Author SHA1 Message Date
daffarahman11 794e2af471 First Commit 2025-06-11 13:02:35 +07:00
daffarahman11 33cff2186a Revisi Bu Bitari PERTAMA rentang nilai k dan hapus CRUD Kecamatan klaster 2025-05-28 14:56:48 +07:00
daffarahman11 c3165955c1 Tambah Normalisasi pada kmeans controller 2025-05-26 02:18:34 +07:00
daffarahman11 df989d1551 FIX BUAT SIDANG 2025-05-18 21:47:21 +07:00
daffarahman11 7cfe92dcec fixing kecamatan, klaster, kmeans, sse 2025-05-13 23:59:17 +07:00
daffarahman11 ae72f2717e update k-means random bukan uniq lagi 2025-05-10 23:59:44 +07:00
daffarahman11 7b20b29157 Tampilan Dashboard 2025-05-05 15:54:30 +07:00
daffarahman11 b309e56152 Fixing -means v1 2025-05-02 14:15:03 +07:00
daffarahman11 5dd6f4a297 Update Service Kmeans dan Kmeans Controller 2025-05-01 13:05:37 +07:00
daffarahman11 967b012cf1 update tanggal update landing 2 2025-04-25 01:27:24 +07:00
31 changed files with 1548 additions and 655 deletions

View File

@ -5,10 +5,11 @@
use App\Models\Klaster; use App\Models\Klaster;
use App\Models\Curanmor; use App\Models\Curanmor;
use App\Models\Kecamatan; use App\Models\Kecamatan;
use App\Models\Detail_Curanmor;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\Detail_Curanmor;
use App\Services\KMeansService; use App\Services\KMeansService;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
class CuranmorController extends Controller class CuranmorController extends Controller
{ {
@ -17,7 +18,7 @@ class CuranmorController extends Controller
*/ */
public function index() public function index()
{ {
$curanmors = Curanmor::orderBy('jumlah_curanmor', 'desc')->get(); $curanmors = Curanmor::orderBy('id', 'asc')->get();
return view('admin.dashboardListCuranmor', compact('curanmors')); return view('admin.dashboardListCuranmor', compact('curanmors'));
} }
@ -35,12 +36,13 @@ public function create()
*/ */
public function store(Request $request) public function store(Request $request)
{ {
try{
$request->validate([ $request->validate([
'kecamatan_id' => 'required|exists:kecamatans,id', 'kecamatan_id' => 'required|exists:kecamatans,id',
'jumlah_curanmor' => 'required|numeric', 'jumlah_curanmor' => 'required|numeric',
]); ]);
try{
DB::beginTransaction();
$kecamatan_id = $request->kecamatan_id; $kecamatan_id = $request->kecamatan_id;
$tambahan_curanmor = $request->jumlah_curanmor; $tambahan_curanmor = $request->jumlah_curanmor;
@ -72,18 +74,14 @@ public function store(Request $request)
$hasil = $service->hitungKMeansCuranmor(); $hasil = $service->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasil)); file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasil));
// =====CODE TAMBAH SEBELUMNYA========= $serviceSSECuranmor = new KMeansService();
// $validateData = $request->validate([ $serviceSSECuranmor->SSEElbowCuranmor();
// 'kecamatan_id' =>'required|max:255|exists:kecamatans,id|unique:curanmors,kecamatan_id',
// 'jumlah_curanmor' =>'required',
// 'klaster_id' =>'required|max:255|exists:klasters,id',
// ]); DB::commit();
// Curanmor::create($validateData);
return redirect('/dashboard/curanmor')->with('succes', 'Berhasil Menambahkan Data Curanmor Baru'); return redirect('/dashboard/curanmor')->with('succes', 'Berhasil Menambahkan Data Curanmor Baru');
}catch (\Exception $e){ }catch (\Exception $e){
return redirect('/dashboard/curanmor')->with('error', 'Gagal Menambahkan Data Curanmor Baru'); DB::rollBack();
return redirect('/dashboard/curanmor')->with('error', 'Gagal Menambahkan Data Curanmor Baru '. $e->getMessage());
} }
} }
@ -100,18 +98,6 @@ public function show(Curanmor $curanmor)
*/ */
public function edit($curanmor) public function edit($curanmor)
{ {
try {
$edit = Curanmor::find($curanmor);
return view('admin.dashboardEditCuranmor', [
'curanmor' => $edit,
'kecamatans' => Kecamatan::all(),
'klasters' => Klaster::all(),
]);
} catch (\Exception $e) {
abort(404);
}
} }
/** /**
@ -119,36 +105,7 @@ public function edit($curanmor)
*/ */
public function update(Request $request, Curanmor $curanmor) public function update(Request $request, Curanmor $curanmor)
{ {
try {
// Validasi input
$request->validate([
'kecamatan_id' => [
'required',
'exists:kecamatans,id',
Rule::unique('curanmors')->ignore($curanmor->id),
],
'klaster_id' => 'required|exists:klasters,id',
'jumlah_curanmor' => 'required|numeric|min:0',
]);
// Update data
$curanmor->update([
'kecamatan_id' => $request->kecamatan_id,
'klaster_id' => $request->klaster_id,
'jumlah_curanmor' => $request->jumlah_curanmor,
]);
$service = new KMeansService();
$hasil = $service->hitungKMeansCuranmor();
// simpan hasil ke file json
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasil));
return redirect('/dashboard/curanmor')->with('succes', 'Data Kecamatan Berhasil Diubah');
} catch (\Exception $e) {
return redirect('/dashboard/curanmor')->with('error', 'Data Kecamatan Gagal Diubah: ' . $e->getMessage());
}
} }
/** /**
@ -156,22 +113,6 @@ public function update(Request $request, Curanmor $curanmor)
*/ */
public function destroy($curanmor) public function destroy($curanmor)
{ {
try {
// Cari data berdasarkan ID
$hapus = Curanmor::find($curanmor);
// Pastikan data ditemukan sebelum menghapus
if (!$hapus) {
return redirect('/dashboard/curanmor')->with('error', 'Data tidak ditemukan.');
}
// Hapus data
$hapus->delete();
return redirect('/dashboard/curanmor')->with('succes', 'Data Curanmor Berhasil Dihapus');
} catch (\Exception $e) {
return redirect('/dashboard/curanmor')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
}
} }
} }

View File

@ -9,6 +9,7 @@
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Services\KMeansService; use App\Services\KMeansService;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
class CurasController extends Controller class CurasController extends Controller
{ {
@ -17,7 +18,7 @@ class CurasController extends Controller
*/ */
public function index() public function index()
{ {
$curases = Curas::orderBy('jumlah_curas', 'desc')->get(); $curases = Curas::orderBy('id', 'asc')->get();
return view('admin.dashboardListCuras', compact('curases')); return view('admin.dashboardListCuras', compact('curases'));
} }
@ -36,12 +37,13 @@ public function create()
*/ */
public function store(Request $request) public function store(Request $request)
{ {
try{
$request->validate([ $request->validate([
'kecamatan_id' => 'required|exists:kecamatans,id', 'kecamatan_id' => 'required|exists:kecamatans,id',
'jumlah_curas' => 'required|numeric', 'jumlah_curas' => 'required|numeric',
]); ]);
try{
DB::beginTransaction();
$kecamatan_id = $request->kecamatan_id; $kecamatan_id = $request->kecamatan_id;
$tambahan_curas = $request->jumlah_curas; $tambahan_curas = $request->jumlah_curas;
@ -75,12 +77,18 @@ public function store(Request $request)
$service = new KMeansService(); $service = new KMeansService();
$hasil = $service->hitungKMeansCuras(); $hasil = $service->hitungKMeansCuras();
// simpan hasil ke file json
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasil)); file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasil));
$serviceSSECuras = new KMeansService();
$serviceSSECuras->SSEElbowCuras();
DB::commit();
return redirect('/dashboard/curas')->with('succes', 'Data curas berhasil ditambahkan.'); return redirect('/dashboard/curas')->with('succes', 'Data curas berhasil ditambahkan.');
}catch (\Exception $e){ }catch (\Exception $e){
return redirect('/dashboard/curas')->with('error', 'Gagal Menambahkan Data Curas Baru');
DB::rollBack();
return redirect('/dashboard/curas')->with('error', 'Gagal Menambahkan Data Curas Baru'. $e->getMessage());
} }
} }
@ -97,18 +105,6 @@ public function show(Curas $curas)
*/ */
public function edit($curas) public function edit($curas)
{ {
try {
$edit = Curas::find($curas);
return view('admin.dashboardEditCuras', [
'curas' => $edit,
'kecamatans' => Kecamatan::all(),
'klasters' => Klaster::all(),
]);
} catch (\Exception $e) {
abort(404);
}
} }
/** /**
@ -116,68 +112,13 @@ public function edit($curas)
*/ */
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
try {
// Cari data berdasarkan ID yang dikirim
$curas = Curas::findOrFail($id);
// Debugging untuk memastikan data ditemukan
// dd($curas->toArray()); // Jika berhasil, ini akan menampilkan data curas
// Validasi input
$request->validate([
'kecamatan_id' => [
'required',
'exists:kecamatans,id',
Rule::unique('curas')->ignore($curas->id),
],
'klaster_id' => 'required|exists:klasters,id',
'jumlah_curas' => 'required|integer|min:0',
]);
// Update data
$curas->update([
'kecamatan_id' => $request->kecamatan_id,
'klaster_id' => $request->klaster_id,
'jumlah_curas' => $request->jumlah_curas,
]);
$service = new KMeansService();
$hasil = $service->hitungKMeansCuras();
// simpan hasil ke file json
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasil));
return redirect('/dashboard/curas')->with('succes', 'Data Kecamatan Berhasil Diubah');
} catch (\Exception $e) {
return redirect('/dashboard/curas')->with('error', 'Data Kecamatan Gagal Diubah: ' . $e->getMessage());
} }
}
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
*/ */
public function destroy($curas) public function destroy($curas)
{ {
try {
// Cari data berdasarkan ID
$hapus = Curas::find($curas);
// Pastikan data ditemukan sebelum menghapus
if (!$hapus) {
return redirect('/dashboard/curas')->with('error', 'Data tidak ditemukan.');
}
// Hapus data
$hapus->delete();
return redirect('/dashboard/curas')->with('succes', 'Data Curas Berhasil Dihapus');
} catch (\Exception $e) {
return redirect('/dashboard/curas')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
}
} }

View File

@ -6,6 +6,7 @@
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\Detail_Curanmor; use App\Models\Detail_Curanmor;
use App\Services\KMeansService; use App\Services\KMeansService;
use Illuminate\Support\Facades\DB;
class DetailCuranmorController extends Controller class DetailCuranmorController extends Controller
{ {
@ -65,6 +66,8 @@ public function update(Request $request, Detail_Curanmor $detail_Curanmor)
public function destroy($id) public function destroy($id)
{ {
try { try {
DB::beginTransaction();
$detail = Detail_Curanmor::findOrFail($id); $detail = Detail_Curanmor::findOrFail($id);
$curanmor = Curanmor::findOrFail($detail->curanmor_id); $curanmor = Curanmor::findOrFail($detail->curanmor_id);
@ -86,8 +89,15 @@ public function destroy($id)
// simpan hasil ke file json // simpan hasil ke file json
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasil)); file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasil));
$serviceSSECuranmor = new KMeansService();
$serviceSSECuranmor->SSEElbowCuranmor();
DB::commit();
return redirect('/dashboard/detail-curanmor')->with('succes', 'Data berhasil dihapus dan curanmor diperbarui.'); return redirect('/dashboard/detail-curanmor')->with('succes', 'Data berhasil dihapus dan curanmor diperbarui.');
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollback();
return redirect('/dashboard/detail-curanmor')->with('error', 'Terjadi kesalahan Ketika Menghapus Data : ' . $e->getMessage()); return redirect('/dashboard/detail-curanmor')->with('error', 'Terjadi kesalahan Ketika Menghapus Data : ' . $e->getMessage());
} }
} }

View File

@ -6,6 +6,7 @@
use App\Models\Detail_Curas; use App\Models\Detail_Curas;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Services\KMeansService; use App\Services\KMeansService;
use Illuminate\Support\Facades\DB;
class DetailCurasController extends Controller class DetailCurasController extends Controller
{ {
@ -65,6 +66,9 @@ public function update(Request $request, Detail_Curas $detail_Curas)
public function destroy($id) public function destroy($id)
{ {
try { try {
DB::beginTransaction();
$detail = Detail_Curas::findOrFail($id); $detail = Detail_Curas::findOrFail($id);
// Ambil curas terkait // Ambil curas terkait
@ -89,8 +93,15 @@ public function destroy($id)
// simpan hasil ke file json // simpan hasil ke file json
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasil)); file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasil));
$serviceSSECuras = new KMeansService();
$serviceSSECuras->SSEElbowCuras();
DB::commit();
return redirect('/dashboard/detail-curas')->with('succes', 'Data berhasil dihapus dan curas diperbarui.'); return redirect('/dashboard/detail-curas')->with('succes', 'Data berhasil dihapus dan curas diperbarui.');
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack();
return redirect('/dashboard/detail-curas')->with('error', 'Terjadi kesalahan Ketika Menghapus Data : ' . $e->getMessage()); return redirect('/dashboard/detail-curas')->with('error', 'Terjadi kesalahan Ketika Menghapus Data : ' . $e->getMessage());
} }

View File

@ -4,6 +4,8 @@
use App\Models\Kecamatan; use App\Models\Kecamatan;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Services\KMeansService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Crypt;
class KecamatanController extends Controller class KecamatanController extends Controller
@ -30,14 +32,28 @@ public function create()
*/ */
public function store(Request $request) public function store(Request $request)
{ {
try{
$validateData = $request->validate([ $validateData = $request->validate([
'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan', 'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan',
]); ]);
try{
DB::beginTransaction();
Kecamatan::create($validateData); Kecamatan::create($validateData);
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
DB::commit();
return redirect('/dashboard/kecamatan')->with('succes', 'Berhasil Menambahkan Data Kecamatan Baru'); return redirect('/dashboard/kecamatan')->with('succes', 'Berhasil Menambahkan Data Kecamatan Baru');
}catch (\Exception $e){ }catch (\Exception $e){
DB::rollBack();
return redirect('/dashboard/kecamatan')->with('error', 'Gagal Menambahkan Data Kecamatan Baru'); return redirect('/dashboard/kecamatan')->with('error', 'Gagal Menambahkan Data Kecamatan Baru');
} }
@ -71,14 +87,28 @@ public function edit(Kecamatan $kecamatan)
*/ */
public function update(Request $request, Kecamatan $kecamatan) public function update(Request $request, Kecamatan $kecamatan)
{ {
try{
$validateData = $request->validate([ $validateData = $request->validate([
'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan', 'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan',
]); ]);
try{
DB::beginTransaction();
Kecamatan::where('id', $kecamatan->id)->update($validateData); Kecamatan::where('id', $kecamatan->id)->update($validateData);
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
DB::commit();
return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Ubah'); return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Ubah');
}catch (\Exception $e){ }catch (\Exception $e){
DB::rollBack();
return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan Gagal Di Ubah'); return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan Gagal Di Ubah');
} }
@ -91,10 +121,24 @@ public function update(Request $request, Kecamatan $kecamatan)
public function destroy(Kecamatan $kecamatan) public function destroy(Kecamatan $kecamatan)
{ {
try{ try{
DB::beginTransaction();
Kecamatan::destroy($kecamatan->id); Kecamatan::destroy($kecamatan->id);
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
DB::commit();
return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Hapus'); return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Hapus');
}catch (\Exception $e){ }catch (\Exception $e){
DB::rollBack();
return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan '. $kecamatan->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Kecamatan '. $kecamatan->nama_kecamatan.' Terlebih Dahulu'); return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan '. $kecamatan->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Kecamatan '. $kecamatan->nama_kecamatan.' Terlebih Dahulu');
} }

View File

@ -4,6 +4,8 @@
use App\Models\Klaster; use App\Models\Klaster;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Services\KMeansService;
use Illuminate\Support\Facades\DB;
class KlasterController extends Controller class KlasterController extends Controller
{ {
@ -28,18 +30,36 @@ public function create()
*/ */
public function store(Request $request) public function store(Request $request)
{ {
try{
$validateData = $request->validate([ $validateData = $request->validate([
'nama_klaster' =>'required|max:255|unique:klasters,nama_klaster', 'nama_klaster' =>'required|max:255|unique:klasters,nama_klaster',
'warna' =>'required|max:255', 'warna' =>'required|max:255',
]); ]);
DB::beginTransaction();
try{
Klaster::create($validateData); Klaster::create($validateData);
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
DB::commit();
return redirect('/dashboard/klaster')->with('succes', 'Berhasil Menambahkan Klaster Baru'); return redirect('/dashboard/klaster')->with('succes', 'Berhasil Menambahkan Klaster Baru');
}catch (\Exception $e){ }catch (\Exception $e){
return redirect('/dashboard/klaster')->with('error', 'Gagal Menambahkan Klaster Baru'); DB::rollBack();
return redirect('/dashboard/klaster')->with('error', 'Gagal Menambahkan Klaster Baru ' .$e->getMessage());
} }
} }
@ -71,17 +91,32 @@ public function edit(Klaster $klaster)
*/ */
public function update(Request $request, Klaster $klaster) public function update(Request $request, Klaster $klaster)
{ {
try {
$validateData = $request->validate([ $validateData = $request->validate([
'nama_klaster' => 'sometimes|required|max:255|unique:klasters,nama_klaster,' . $klaster->id, 'nama_klaster' => 'sometimes|required|max:255|unique:klasters,nama_klaster,' . $klaster->id,
'warna' => 'sometimes|required|max:255', 'warna' => 'sometimes|required|max:255',
]); ]);
try {
DB::beginTransaction();
// Hanya update data yang diisi (tidak mengganti dengan null) // Hanya update data yang diisi (tidak mengganti dengan null)
Klaster::where('id', $klaster->id)->update(array_filter($validateData)); Klaster::where('id', $klaster->id)->update(array_filter($validateData));
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
DB::commit();
return redirect('/dashboard/klaster')->with('success', 'Data Klaster Berhasil Diubah'); return redirect('/dashboard/klaster')->with('success', 'Data Klaster Berhasil Diubah');
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack();
return redirect('/dashboard/klaster')->with('error', 'Data Klaster Gagal Diubah'); return redirect('/dashboard/klaster')->with('error', 'Data Klaster Gagal Diubah');
} }
@ -93,11 +128,27 @@ public function update(Request $request, Klaster $klaster)
public function destroy(Klaster $klaster) public function destroy(Klaster $klaster)
{ {
try{ try{
DB::beginTransaction();
Klaster::destroy($klaster->id); Klaster::destroy($klaster->id);
DB::commit();
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
$hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
return redirect('/dashboard/klaster')->with('succes', 'Data Klaster Berhasil Di Hapus'); return redirect('/dashboard/klaster')->with('succes', 'Data Klaster Berhasil Di Hapus');
}catch (\Exception $e){ }catch (\Exception $e){
return redirect('/dashboard/klaster')->with('error', 'Data Klaster '. $klaster->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Klaster '. $klaster->nama_kecamatan.' Terlebih Dahulu');
DB::rollBack();
return redirect('/dashboard/klaster')->with('error', 'Data Klaster '. $klaster->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Klaster '. $klaster->nama_kecamatan.' Terlebih Dahulu '. $e->getMessage());
} }
} }
} }

View File

@ -9,27 +9,34 @@
class KmeansController extends Controller class KmeansController extends Controller
{ {
public function KMeansCuras() public function KMeansCuras()
{ {
$data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')
->orderBy('jumlah_curas', 'asc')->get();
$data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')->orderBy('jumlah_curas', 'asc')->get(); // Hitung min dan max untuk normalisasi
$min = $data->min('jumlah_curas');
$max = $data->max('jumlah_curas');
$k = Klaster::count('id'); // Normalisasi jumlah_curas ke skala 01
$maxIterasi = 100; $data = $data->map(function ($item) use ($min, $max) {
$item->jumlah_curas_normalized = $max == $min
// Simpan centroid awal ke variabel terpisah ? 1
$uniqueJumlahCuras = $data->pluck('jumlah_curas')->unique()->shuffle()->take($k)->values(); : round(($item->jumlah_curas - $min) / ($max - $min), 2);
$initialCentroids = $uniqueJumlahCuras->map(function ($jumlah) {
return ['jumlah_curas' => $jumlah];
});
// Salin untuk digunakan dalam proses iterasi
$centroids = $initialCentroids->map(function ($item) {
return $item; return $item;
}); });
$maxIterasi = 100;
// Centroid awal langsung dalam skala 01
$centroidManual = [0.0, 0.5, 1];
$centroids = collect($centroidManual)->map(function ($value) {
return ['C' => round($value, 2)];
});
$centroidAwal = $centroids->toArray();
$iterasi = []; $iterasi = [];
$prevAssignment = []; $prevAssignment = [];
@ -41,14 +48,17 @@ public function KMeansCuras()
$jarak = []; $jarak = [];
foreach ($centroids as $idx => $centroid) { foreach ($centroids as $idx => $centroid) {
$dist = abs($item->jumlah_curas - $centroid['jumlah_curas']); $dist = abs($item->jumlah_curas_normalized - $centroid['C']);
$jarak["jarakC" . ($idx + 1)] = $dist; $jarak["C" . ($idx + 1)] = round($dist, 2);
} }
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak); $iterasi[$i][] = array_merge([
'kecamatan_id' => $item->kecamatan_id,
'normal' => round($item->jumlah_curas_normalized, 2)
], $jarak);
$minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2" $minIndex = array_keys($jarak, min($jarak))[0];
$clusterNumber = (int) str_replace("jarakC", "", $minIndex); $clusterNumber = (int) str_replace("C", "", $minIndex);
$clustered[$clusterNumber][] = $item; $clustered[$clusterNumber][] = $item;
$item->temp_klaster = $clusterNumber; $item->temp_klaster = $clusterNumber;
@ -61,25 +71,26 @@ public function KMeansCuras()
$prevAssignment = $currentAssignment; $prevAssignment = $currentAssignment;
// Update centroid berdasarkan rata-rata // Update centroid dengan rata-rata nilai normalized
foreach ($clustered as $key => $group) { foreach ($clustered as $key => $group) {
$avg = collect($group)->avg('jumlah_curas'); $avg = collect($group)->avg('jumlah_curas_normalized');
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) { $centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
return $index === ($key - 1) return $index === ($key - 1)
? ['jumlah_curas' => $avg] ? ['C' => round($avg, 2)]
: $item; : $item;
}); });
} }
} }
// Final mapping centroid ke klaster_id // Mapping centroid ke klaster_id
$finalCentroids = $centroids->map(function ($item, $index) { $finalCentroids = $centroids->map(function ($item, $index) {
return ['index' => $index + 1, 'jumlah_curas' => $item['jumlah_curas']]; return ['index' => $index + 1, 'C' => round($item['C'], 2)];
})->sortBy('jumlah_curas')->values(); })->sortBy('C')->values();
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
$centroidToKlaster = [];
foreach ($finalCentroids as $i => $centroid) { foreach ($finalCentroids as $i => $centroid) {
$centroidToKlaster[$centroid['index']] = $i + 1; $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
} }
foreach ($data as $item) { foreach ($data as $item) {
@ -88,87 +99,57 @@ public function KMeansCuras()
]); ]);
} }
// Simpan hasil iterasi dan centroid awal ke session $centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
session([ return ['C' . ($index + 1) => round($item['C'], 2)];
'hasil_iterasi' => $iterasi, });
'centroid_awal' => $initialCentroids
]);
// Format ulang centroid awal dengan label 'Centroid 1', dst. $centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
$formattedInitialCentroids = []; return ['C' . ($index + 1) => round($item['C'], 2)];
foreach ($initialCentroids as $i => $centroid) { });
$formattedInitialCentroids['Centroid ' . ($i + 1)] = $centroid['jumlah_curas'];
$hasilKMeansCuras = [
'centroid_awal' => $centroidAwalFormatted,
'centroid_akhir' => $centroidAkhirFormatted,
'iterasi' => $iterasi,
'min' => $min,
'max' => $max
];
file_put_contents(
storage_path('app/public/hasil_kmeans_curas.json'),
json_encode($hasilKMeansCuras, JSON_PRETTY_PRINT)
);
return redirect('/dashboard/TampilHitungCuras');
} }
return response()->json([
'centroid_awal' => $formattedInitialCentroids,
'hasil_iterasi' => $iterasi,
]);
}
public function KMeansCuranmor() public function KMeansCuranmor()
{ {
$data = Curanmor::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curanmor')->orderBy('jumlah_curanmor', 'asc')->get(); // Ambil data awal
$data = Curanmor::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curanmor')
->orderBy('jumlah_curanmor', 'asc')->get();
// Hitung min dan max untuk normalisasi Min-Max
$min = $data->min('jumlah_curanmor');
$max = $data->max('jumlah_curanmor');
// Normalisasi jumlah_curanmor ke skala 1-100
$data = $data->map(function ($item) use ($min, $max) {
$item->jumlah_curanmor_normalized = $max == $min
? 1
: round((($item->jumlah_curanmor - $min) / ($max - $min)), 2);
return $item;
});
$maxIterasi = 100; $maxIterasi = 100;
$hasilElbow = [];
for ($k = 1; $k <= 10; $k++) { // Centroid awal dalam skala 1100
// Ambil centroid awal secara acak $centroidManual = [0.2, 0.5, 0.8];
$centroids = $data->random($k)->values()->map(function ($item) { $centroids = collect($centroidManual)->map(function ($value) {
return ['jumlah_curanmor' => $item->jumlah_curanmor]; return ['C' => round($value, 2)];
}); });
$prevAssignment = []; $centroidAwal = $centroids->toArray();
for ($i = 0; $i < $maxIterasi; $i++) {
$clustered = [];
$currentAssignment = [];
foreach ($data as $item) {
$jarak = [];
foreach ($centroids as $idx => $centroid) {
$dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']);
$jarak[$idx] = $dist;
}
$minIndex = array_keys($jarak, min($jarak))[0];
$clustered[$minIndex][] = $item;
$currentAssignment[$item->id] = $minIndex;
$item->temp_klaster = $minIndex;
}
if ($currentAssignment === $prevAssignment) break;
$prevAssignment = $currentAssignment;
foreach ($clustered as $key => $group) {
$avg = collect($group)->avg('jumlah_curanmor');
$centroids[$key] = ['jumlah_curanmor' => $avg];
}
}
// Hitung SSE (Sum of Squared Errors)
$sse = 0;
foreach ($data as $item) {
$centroidVal = $centroids[$item->temp_klaster]['jumlah_curanmor'];
$sse += pow($item->jumlah_curanmor - $centroidVal, 2);
}
$hasilElbow[] = ['k' => $k, 'sse' => $sse];
}
// Simpan hasil Elbow Method ke file
file_put_contents(storage_path('app/public/hasil_elbow_curanmor.json'), json_encode($hasilElbow, JSON_PRETTY_PRINT));
// ===================== //
// === Hitung k akhir === //
// ===================== //
$k = Klaster::count(); // misalnya 3
$centroids = $data->random($k)->values()->map(function ($item) {
return ['jumlah_curanmor' => $item->jumlah_curanmor];
});
$iterasi = []; $iterasi = [];
$prevAssignment = []; $prevAssignment = [];
@ -181,54 +162,86 @@ public function KMeansCuranmor()
$jarak = []; $jarak = [];
foreach ($centroids as $idx => $centroid) { foreach ($centroids as $idx => $centroid) {
$dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']); $dist = abs($item->jumlah_curanmor_normalized - $centroid['C']);
$jarak["jarakC" . ($idx + 1)] = $dist; $jarak["C" . ($idx + 1)] = round($dist, 2); // Dua angka di belakang koma
} }
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak); $iterasi[$i][] = array_merge([
'kecamatan_id' => $item->kecamatan_id,
'normal' => round($item->jumlah_curanmor_normalized, 2)
], $jarak);
$minIndex = array_keys($jarak, min($jarak))[0]; $minIndex = array_keys($jarak, min($jarak))[0];
$clusterNumber = (int) str_replace("jarakC", "", $minIndex); $clusterNumber = (int) str_replace("C", "", $minIndex);
$clustered[$clusterNumber][] = $item; $clustered[$clusterNumber][] = $item;
$item->temp_klaster = $clusterNumber; $item->temp_klaster = $clusterNumber;
$currentAssignment[$item->id] = $clusterNumber; $currentAssignment[$item->id] = $clusterNumber;
} }
// Cek konvergensi
if ($currentAssignment === $prevAssignment) { if ($currentAssignment === $prevAssignment) {
break; break;
} }
$prevAssignment = $currentAssignment; $prevAssignment = $currentAssignment;
// Update centroid berdasarkan rata-rata nilai yang sudah dinormalisasi
foreach ($clustered as $key => $group) { foreach ($clustered as $key => $group) {
$avg = collect($group)->avg('jumlah_curanmor'); $avg = collect($group)->avg('jumlah_curanmor_normalized');
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) { $centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
return $index === ($key - 1) return $index === ($key - 1)
? ['jumlah_curanmor' => $avg] ? ['C' => round($avg, 2)]
: $item; : $item;
}); });
} }
} }
// Final mapping centroid ke klaster_id
$finalCentroids = $centroids->map(function ($item, $index) { $finalCentroids = $centroids->map(function ($item, $index) {
return ['index' => $index + 1, 'jumlah_curanmor' => $item['jumlah_curanmor']]; return ['index' => $index + 1, 'C' => round($item['C'], 2)];
})->sortBy('jumlah_curanmor')->values(); })->sortBy('C')->values();
$centroidToKlaster = []; $availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
foreach ($finalCentroids as $i => $centroid) { foreach ($finalCentroids as $i => $centroid) {
$centroidToKlaster[$centroid['index']] = $i + 1; $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
} }
// Update hasil clustering ke database
foreach ($data as $item) { foreach ($data as $item) {
Curanmor::where('id', $item->id)->update([ Curanmor::where('id', $item->id)->update([
'klaster_id' => $centroidToKlaster[$item->temp_klaster], 'klaster_id' => $centroidToKlaster[$item->temp_klaster],
]); ]);
} }
session(['hasil_iterasi' => $iterasi]); // Format centroid awal
return $iterasi; $centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
} return ['C' . ($index + 1) => round($item['C'], 2)];
});
// Format centroid akhir
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
return ['C' . ($index + 1) => round($item['C'], 2)];
});
$hasilKMeansCuranmor = [
'centroid_awal' => $centroidAwalFormatted,
'centroid_akhir' => $centroidAkhirFormatted,
'iterasi' => $iterasi,
'min' => $min,
'max' => $max
];
file_put_contents(
storage_path('app/public/hasil_kmeans_curanmor.json'),
json_encode($hasilKMeansCuranmor, JSON_PRETTY_PRINT)
);
return redirect('/dashboard/TampilHitungCuranmor');
}
} }

View File

@ -6,6 +6,7 @@
use App\Models\Klaster; use App\Models\Klaster;
use App\Models\Curanmor; use App\Models\Curanmor;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Services\KMeansService;
class LandingController extends Controller class LandingController extends Controller
{ {
@ -18,5 +19,26 @@ public function index()
$tanggalCuranmor = \Carbon\Carbon::parse($updateCuranmor->updated_at)->translatedFormat('d F Y'); $tanggalCuranmor = \Carbon\Carbon::parse($updateCuranmor->updated_at)->translatedFormat('d F Y');
return view('landing', compact('klasters', 'tanggalCuras', 'tanggalCuranmor')); return view('landing', compact('klasters', 'tanggalCuras', 'tanggalCuranmor'));
} }
public function runKmeans()
{
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$serviceKMeans->hitungDBSCANManual();
$serviceKMeans->kmeansWithSilhouetteSingleMethod();
$serviceKMeansCuras = new KMeansService();
$hasilKMeansCuras = $serviceKMeansCuras->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));
$serviceKmeansCuranmor = new KMeansService();
$hasilKMeansCuranmor = $serviceKmeansCuranmor->hitungKMeansCuranmor();
file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor));
return redirect('/dashboard');
}
} }

View File

@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers;
use App\Models\Kecamatan;
use Illuminate\Http\Request;
class TampilHitunganController extends Controller
{
public function TampilHitungCuras()
{
$file = storage_path('app/public/hasil_kmeans_curas.json');
if (!file_exists($file)) {
return abort(404, 'File hasil KMeans tidak ditemukan.');
}
$data = json_decode(file_get_contents($file), true);
// Ambil nama kecamatan berdasarkan ID
$kecamatan = Kecamatan::pluck('nama_kecamatan', 'id')->toArray();
return view('admin.HitungKmeans.HitunganCuras', compact('data', 'kecamatan'));
}
public function TampilHitungCuranmor()
{
$file = storage_path('app/public/hasil_kmeans_curanmor.json');
if (!file_exists($file)) {
return abort(404, 'File hasil KMeans tidak ditemukan.');
}
$data = json_decode(file_get_contents($file), true);
// Ambil nama kecamatan berdasarkan ID
$kecamatan = Kecamatan::pluck('nama_kecamatan', 'id')->toArray();
return view('admin.HitungKmeans.HitunganCuranmor', compact('data', 'kecamatan'));
}
}

View File

@ -14,12 +14,19 @@ public function index()
{ {
$jumlahRawanCuras = Curas::where('klaster_id', '3')->count(); $jumlahRawanCuras = Curas::where('klaster_id', '3')->count();
$jumlahTotalCuras = Curas::count(); $jumlahTotalCuras = Curas::count();
$prosentaseCuras = ($jumlahRawanCuras / $jumlahTotalCuras) * 100;
$jumlahRawanCuranmor = Curanmor::where('klaster_id', '3')->count(); $jumlahRawanCuranmor = Curanmor::where('klaster_id', '3')->count();
$jumlahTotalCuranmor = Curanmor::count(); $jumlahTotalCuranmor = Curanmor::count();
$namaUser = Auth::user()->nama;
$prosentaseCuras = ($jumlahRawanCuras / $jumlahTotalCuras) * 100;
$prosentaseCuranmor = ($jumlahRawanCuranmor / $jumlahTotalCuranmor) * 100; $prosentaseCuranmor = ($jumlahRawanCuranmor / $jumlahTotalCuranmor) * 100;
$totalKecamatan = Kecamatan::count(); $totalKecamatan = Kecamatan::count();
return view('admin.dashboardAdmin', compact('jumlahRawanCuras', 'jumlahRawanCuranmor', 'namaUser', 'prosentaseCuras', 'prosentaseCuranmor', 'totalKecamatan'));
$curasTertinggis = Curas::orderBy('jumlah_curas', 'desc')->take(5)->get();
$curanmorTertinggis = Curanmor::orderBy('jumlah_curanmor', 'desc')->take(5)->get();
$namaUser = Auth::user()->nama;
return view('admin.dashboardAdmin', compact('jumlahRawanCuras', 'jumlahRawanCuranmor', 'namaUser', 'prosentaseCuras', 'prosentaseCuranmor', 'totalKecamatan', 'curasTertinggis', 'curanmorTertinggis'));
} }
} }

View File

@ -1,17 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class hasilIterasiController extends Controller
{
public function iterasiCuras()
{
$iterasi = session('hasil_iterasi');
dd($iterasi);
// Kirim ke view atau proses lainnya
return view('admin.dashboarditerasiCuras', compact('iterasi'));
}
}

View File

@ -5,6 +5,7 @@
use App\Models\Curas; use App\Models\Curas;
use App\Models\Klaster; use App\Models\Klaster;
use App\Models\Curanmor; use App\Models\Curanmor;
use Illuminate\Support\Facades\Storage;
class KMeansService class KMeansService
@ -12,15 +13,32 @@ class KMeansService
public function hitungKMeansCuras() public function hitungKMeansCuras()
{ {
$data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')->orderBy('jumlah_curas', 'asc')->get(); $data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')->orderBy('jumlah_curas', 'asc')->get();
$k = Klaster::count('id'); $k = Klaster::count('id');
$maxIterasi = 100; $maxIterasi = 100;
$centroids = $data->random($k)->values()->map(function ($item) {
return [ // Hitung min dan max untuk normalisasi
'jumlah_curas' => $item->jumlah_curas, $minValue = $data->min('jumlah_curas');
]; $maxValue = $data->max('jumlah_curas');
// Normalisasi data dan simpan hasilnya ke dalam array baru
$normalizedData = $data->map(function ($item) use ($minValue, $maxValue) {
$normalized = ($item->jumlah_curas - $minValue) / ($maxValue - $minValue);
$item->normalized_curas = round($normalized, 2); // 2 angka di belakang koma
return $item;
}); });
// Inisialisasi centroid dengan nilai acak dari rentang normalisasi [0, 1]
$generated = collect();
while ($generated->count() < $k) {
$random = round(mt_rand(0, 100) / 100, 2); // Random 0.001.00
if (!$generated->contains($random)) {
$generated->push($random);
}
}
$centroids = $generated->map(fn($value) => ['C' => $value]);
$centroidAwal = $centroids->toArray();
$iterasi = []; $iterasi = [];
$prevAssignment = []; $prevAssignment = [];
@ -28,58 +46,57 @@ public function hitungKMeansCuras()
$clustered = []; $clustered = [];
$currentAssignment = []; $currentAssignment = [];
foreach ($data as $item) { foreach ($normalizedData as $item) {
$jarak = []; $jarak = [];
foreach ($centroids as $idx => $centroid) { foreach ($centroids as $idx => $centroid) {
$dist = abs($item->jumlah_curas - $centroid['jumlah_curas']); $dist = abs($item->normalized_curas - $centroid['C']);
$jarak["jarakC" . ($idx + 1)] = $dist; $jarak["C" . ($idx + 1)] = round($dist, 2); // Format 2 angka koma
} }
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak); $minIndex = array_keys($jarak, min($jarak))[0];
$clusterNumber = (int) str_replace("C", "", $minIndex);
$minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2"
$clusterNumber = (int) str_replace("jarakC", "", $minIndex);
$clustered[$clusterNumber][] = $item; $clustered[$clusterNumber][] = $item;
$item->temp_klaster = $clusterNumber; $item->temp_klaster = $clusterNumber;
$currentAssignment[$item->id] = $clusterNumber; $currentAssignment[$item->id] = $clusterNumber;
// Tambahkan nilai normalisasi ke dalam iterasi
$iterasi[$i][] = array_merge(
['kecamatan_id' => $item->kecamatan_id],
['normal' => round($item->normalized_curas, 2)],
$jarak
);
} }
// ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break
if ($currentAssignment === $prevAssignment) { if ($currentAssignment === $prevAssignment) {
break; break;
} }
$prevAssignment = $currentAssignment; $prevAssignment = $currentAssignment;
// Update centroid
// Update centroid berdasarkan rata-rata
foreach ($clustered as $key => $group) { foreach ($clustered as $key => $group) {
$avg = collect($group)->avg('jumlah_curas'); $avg = collect($group)->avg('normalized_curas');
$avg = round($avg, 2); // Format 2 angka koma
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) { $centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
return $index === ($key - 1) return $index === ($key - 1)
? ['jumlah_curas' => $avg] ? ['C' => $avg]
: $item; : $item;
}); });
} }
} }
// Final mapping centroid ke klaster_id
// Final mapping centroid ke klaster_id (aman/sedang/rawan)
$finalCentroids = $centroids->map(function ($item, $index) { $finalCentroids = $centroids->map(function ($item, $index) {
return ['index' => $index + 1, 'jumlah_curas' => $item['jumlah_curas']]; return ['index' => $index + 1, 'C' => round($item['C'], 2)];
})->sortBy('jumlah_curas')->values(); })->sortBy('C')->values();
$centroidToKlaster = [];
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
foreach ($finalCentroids as $i => $centroid) { foreach ($finalCentroids as $i => $centroid) {
// Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...) $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
$centroidToKlaster[$centroid['index']] = $i + 1;
} }
// Update ke database // Update ke database
foreach ($data as $item) { foreach ($data as $item) {
Curas::where('id', $item->id)->update([ Curas::where('id', $item->id)->update([
@ -87,8 +104,23 @@ public function hitungKMeansCuras()
]); ]);
} }
// Format centroid awal
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
return ['C' . ($index + 1) => round($item['C'], 2)];
});
// Format centroid akhir
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
return ['C' . ($index + 1) => round($item['C'], 2)];
});
// Simpan hasil ke file JSON (opsional)
return [
'centroid_awal' => $centroidAwalFormatted,
'centroid_akhir' => $centroidAkhirFormatted,
'iterasi' => $iterasi
];
return $iterasi;
} }
@ -98,12 +130,31 @@ public function hitungKMeansCuranmor()
$k = Klaster::count('id'); $k = Klaster::count('id');
$maxIterasi = 100; $maxIterasi = 100;
$centroids = $data->random($k)->values()->map(function ($item) {
return [ // Hitung min dan max untuk normalisasi
'jumlah_curanmor' => $item->jumlah_curanmor, $minValue = $data->min('jumlah_curanmor');
]; $maxValue = $data->max('jumlah_curanmor');
// Normalisasi data dan simpan hasilnya ke dalam property baru
$normalizedData = $data->map(function ($item) use ($minValue, $maxValue) {
$normalized = ($maxValue - $minValue) == 0 ? 0 : ($item->jumlah_curanmor - $minValue) / ($maxValue - $minValue);
$item->normalized_curanmor = round($normalized, 2);
return $item;
}); });
// Generate centroid awal unik dari data ter-normalisasi
$generated = collect();
while ($generated->count() < $k) {
$rand = mt_rand(0, 100) / 100; // antara 0 dan 1 dengan 2 desimal
$rand = round($rand, 2);
if (!$generated->contains($rand)) {
$generated->push($rand);
}
}
$centroids = $generated->map(fn($val) => ['C' => $val]);
$centroidAwal = $centroids->toArray();
$iterasi = []; $iterasi = [];
$prevAssignment = []; $prevAssignment = [];
@ -111,67 +162,497 @@ public function hitungKMeansCuranmor()
$clustered = []; $clustered = [];
$currentAssignment = []; $currentAssignment = [];
foreach ($data as $item) { foreach ($normalizedData as $item) {
$jarak = []; $jarak = [];
foreach ($centroids as $idx => $centroid) { foreach ($centroids as $idx => $centroid) {
$dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']); $dist = abs($item->normalized_curanmor - $centroid['C']);
$jarak["jarakC" . ($idx + 1)] = $dist; $jarak["C" . ($idx + 1)] = round($dist, 2);
} }
$iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak); // Tambahkan data ke iterasi, termasuk nilai normalisasi
$iterasi[$i][] = array_merge(
['kecamatan_id' => $item->kecamatan_id],
['normal' => $item->normalized_curanmor], // tampilkan nilai normalisasi
$jarak
);
$minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2" $minIndex = array_keys($jarak, min($jarak))[0];
$clusterNumber = (int) str_replace("jarakC", "", $minIndex); $clusterNumber = (int) str_replace("C", "", $minIndex);
$clustered[$clusterNumber][] = $item; $clustered[$clusterNumber][] = $item;
$item->temp_klaster = $clusterNumber; $item->temp_klaster = $clusterNumber;
$currentAssignment[$item->id] = $clusterNumber; $currentAssignment[$item->id] = $clusterNumber;
} }
// ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break
if ($currentAssignment === $prevAssignment) { if ($currentAssignment === $prevAssignment) {
break; break;
} }
$prevAssignment = $currentAssignment; $prevAssignment = $currentAssignment;
// Update centroid berdasarkan rata-rata normalisasi
// Update centroid berdasarkan rata-rata
foreach ($clustered as $key => $group) { foreach ($clustered as $key => $group) {
$avg = collect($group)->avg('jumlah_curanmor'); $avg = collect($group)->avg('normalized_curanmor');
$avg = round($avg, 2);
$centroids = $centroids->map(function ($item, $index) use ($key, $avg) { $centroids = $centroids->map(function ($item, $index) use ($key, $avg) {
return $index === ($key - 1) return $index === ($key - 1)
? ['jumlah_curanmor' => $avg] ? ['C' => $avg]
: $item; : $item;
}); });
} }
} }
// Final mapping centroid ke klaster_id
// Final mapping centroid ke klaster_id (aman/sedang/rawan)
$finalCentroids = $centroids->map(function ($item, $index) { $finalCentroids = $centroids->map(function ($item, $index) {
return ['index' => $index + 1, 'jumlah_curanmor' => $item['jumlah_curanmor']]; return ['index' => $index + 1, 'C' => round($item['C'], 2)];
})->sortBy('jumlah_curanmor')->values(); })->sortBy('C')->values();
$availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values();
$centroidToKlaster = []; $centroidToKlaster = [];
foreach ($finalCentroids as $i => $centroid) { foreach ($finalCentroids as $i => $centroid) {
// Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...) $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i];
$centroidToKlaster[$centroid['index']] = $i + 1;
} }
// Update database
// Update ke database
foreach ($data as $item) { foreach ($data as $item) {
Curanmor::where('id', $item->id)->update([ Curanmor::where('id', $item->id)->update([
'klaster_id' => $centroidToKlaster[$item->temp_klaster], 'klaster_id' => $centroidToKlaster[$item->temp_klaster],
]); ]);
} }
session(['hasil_iterasi' => $iterasi]); // Format centroid awal
$centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) {
return ['C' . ($index + 1) => round($item['C'], 2)];
});
return $iterasi; // Format centroid akhir
$centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) {
return ['C' . ($index + 1) => round($item['C'], 2)];
});
return [
'centroid_awal' => $centroidAwalFormatted,
'centroid_akhir' => $centroidAkhirFormatted,
'iterasi' => $iterasi
];
} }
public function SSEElbowCuranmor()
{
$data = Curanmor::select('id', 'jumlah_curanmor')->get();
$maxK = 15;
$maxIterasi = 100;
$elbowData = [];
$min = $data->min('jumlah_curanmor');
$max = $data->max('jumlah_curanmor');
// Normalisasi jumlah_curanmor
$normalizedData = $data->map(function ($item) use ($min, $max) {
$item->normalized = ($max - $min) == 0 ? 0 : round(($item->jumlah_curanmor - $min) / ($max - $min), 2);
return $item;
});
for ($k = 2; $k <= $maxK; $k++) {
$usedValues = [];
$centroids = collect();
// Inisialisasi centroid secara acak dari nilai 0 sampai 1 dengan 2 desimal
while ($centroids->count() < $k) {
$randVal = round(mt_rand(0, 10000) / 10000, 2); // 2 angka desimal
if (!in_array($randVal, $usedValues)) {
$centroids->push(['normalized' => $randVal]);
$usedValues[] = $randVal;
}
}
$prevAssignment = [];
for ($iter = 0; $iter < $maxIterasi; $iter++) {
$clustered = [];
$currentAssignment = [];
foreach ($normalizedData as $item) {
$jarak = [];
foreach ($centroids as $idx => $centroid) {
$dist = abs($item->normalized - $centroid['normalized']);
$jarak[$idx] = $dist;
}
$minIndex = array_keys($jarak, min($jarak))[0];
$clustered[$minIndex][] = $item;
$currentAssignment[$item->id] = $minIndex;
}
if ($currentAssignment === $prevAssignment) {
break;
}
$prevAssignment = $currentAssignment;
foreach ($clustered as $key => $group) {
$avg = round(collect($group)->avg('normalized'), 2); // 2 angka desimal
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
return $idx == $key
? ['normalized' => $avg]
: $centroid;
});
}
}
// Hitung SSE
$sse = 0;
foreach ($clustered as $key => $group) {
$centroidVal = $centroids[$key]['normalized'];
foreach ($group as $item) {
$sse += pow($item->normalized - $centroidVal, 2);
}
}
$elbowData[] = [
'k' => $k,
'sse' => round($sse, 2) // 2 angka desimal
];
}
file_put_contents(
storage_path('app/public/sse_elbow_curanmor.json'),
json_encode($elbowData, JSON_PRETTY_PRINT)
);
}
public function SSEElbowCuras()
{
$data = Curas::select('id', 'jumlah_curas')->get();
$maxK = 4;
$maxIterasi = 100;
$elbowData = [];
$min = $data->min('jumlah_curas');
$max = $data->max('jumlah_curas');
// Normalisasi nilai jumlah_curas
$normalizedData = $data->map(function ($item) use ($min, $max) {
$item->normalized = ($max - $min) == 0 ? 0 : round(($item->jumlah_curas - $min) / ($max - $min), 2);
return $item;
});
for ($k = 2; $k <= $maxK; $k++) {
$usedValues = [];
$centroids = collect();
// Inisialisasi centroid secara acak dari nilai 0 sampai 1 dengan 2 desimal
while ($centroids->count() < $k) {
$randVal = round(mt_rand(0, 10000) / 10000, 2); // 0.00 - 1.00
if (!in_array($randVal, $usedValues)) {
$centroids->push(['normalized' => $randVal]);
$usedValues[] = $randVal;
}
}
$prevAssignment = [];
for ($iter = 0; $iter < $maxIterasi; $iter++) {
$clustered = [];
$currentAssignment = [];
foreach ($normalizedData as $item) {
$jarak = [];
// Hitung jarak absolut (Manhattan Distance)
foreach ($centroids as $idx => $centroid) {
$dist = abs($item->normalized - $centroid['normalized']);
$jarak[$idx] = $dist;
}
$minIndex = array_keys($jarak, min($jarak))[0];
$clustered[$minIndex][] = $item;
$currentAssignment[$item->id] = $minIndex;
}
if ($currentAssignment === $prevAssignment) {
break;
}
$prevAssignment = $currentAssignment;
// Update centroid
foreach ($clustered as $key => $group) {
$avg = round(collect($group)->avg('normalized'), 2);
$centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) {
return $idx == $key
? ['normalized' => $avg]
: $centroid;
});
}
}
// Hitung SSE
$sse = 0;
foreach ($clustered as $key => $group) {
$centroidVal = $centroids[$key]['normalized'];
foreach ($group as $item) {
$sse += pow($item->normalized - $centroidVal, 2);
}
}
$elbowData[] = [
'k' => $k,
'sse' => round($sse, 2) // dibulatkan ke 2 desimal
];
}
file_put_contents(
storage_path('app/public/sse_elbow_curas.json'),
json_encode($elbowData, JSON_PRETTY_PRINT)
);
}
public function hitungDBSCANManual()
{
$eps = 1.5; // Jarak maksimum antar titik
$minPts = 3; // Minimum tetangga agar jadi core point
$data = Curas::select('jumlah_curas')->get()->pluck('jumlah_curas')->map(fn($v) => (float)$v)->toArray();
$n = count($data);
$visited = array_fill(0, $n, false);
$labels = array_fill(0, $n, null);
$clusterId = 0;
// Fungsi cari tetangga
$regionQuery = function ($pointIndex) use ($data, $eps) {
$neighbors = [];
foreach ($data as $i => $val) {
if (abs($val - $data[$pointIndex]) <= $eps) {
$neighbors[] = $i;
}
}
return $neighbors;
};
// DBSCAN Proses
for ($i = 0; $i < $n; $i++) {
if ($visited[$i]) continue;
$visited[$i] = true;
$neighbors = $regionQuery($i);
if (count($neighbors) < $minPts) {
$labels[$i] = -1; // noise
continue;
}
$labels[$i] = $clusterId;
$seeds = array_diff($neighbors, [$i]);
foreach ($seeds as $seed) {
if (!$visited[$seed]) {
$visited[$seed] = true;
$newNeighbors = $regionQuery($seed);
if (count($newNeighbors) >= $minPts) {
$seeds = array_unique(array_merge($seeds, $newNeighbors));
}
}
if ($labels[$seed] === null || $labels[$seed] === -1) {
$labels[$seed] = $clusterId;
}
}
$clusterId++;
}
// Hitung silhouette (manual satu dimensi)
$silhouetteScores = [];
foreach ($data as $i => $val) {
$label = $labels[$i];
if ($label === -1) continue; // skip noise
$sameCluster = [];
$otherClusters = [];
foreach ($data as $j => $otherVal) {
if ($i === $j || $labels[$j] === -1) continue;
if ($labels[$j] === $label) {
$sameCluster[] = abs($val - $otherVal);
} else {
$otherClusters[$labels[$j]][] = abs($val - $otherVal);
}
}
$a = count($sameCluster) > 0 ? array_sum($sameCluster) / count($sameCluster) : 0;
$b = count($otherClusters) > 0 ? min(array_map(fn($d) => array_sum($d) / count($d), $otherClusters)) : 0;
$s = ($a === $b && $a === 0) ? 0 : ($b - $a) / max($a, $b);
$silhouetteScores[] = $s;
}
$meanSilhouette = count($silhouetteScores) > 0 ? round(array_sum($silhouetteScores) / count($silhouetteScores), 4) : 0;
// Susun hasil anggota klaster
$anggotaKlaster = [];
foreach ($labels as $i => $label) {
$anggotaKlaster[$label][] = $data[$i];
}
$jumlahKlaster = count(array_filter(array_keys($anggotaKlaster), fn($k) => $k !== -1));
$hasil = [
'silhouette' => $meanSilhouette,
'jumlah_klaster' => $jumlahKlaster,
'anggota_klaster' => $anggotaKlaster,
];
file_put_contents(
storage_path('app/public/dbscan_curas.json'),
json_encode($hasil, JSON_PRETTY_PRINT)
);
return $hasil;
}
public function kmeansWithSilhouetteSingleMethod(int $k = 2, int $maxIter = 100): array
{
// Ambil data dari tabel curas
$data = \App\Models\Curas::select('kecamatan_id', 'jumlah_curas')
->get()
->pluck('jumlah_curas', 'kecamatan_id')
->toArray();
$ids = array_keys($data);
$values = array_values($data);
// Inisialisasi centroid secara random
// Ambil nilai min dan max dari data
$minValue = min($values);
$maxValue = max($values);
$centroids = [];
if ($k == 1) {
// Jika cuma 1 klaster, centroid random antara min dan max
$centroids[] = rand($minValue, $maxValue);
} else {
// Untuk k >= 2, inisialisasi centroid unik integer dalam rentang min-max
$centroids = [];
while (count($centroids) < $k) {
$randCentroid = rand($minValue, $maxValue);
if (!in_array($randCentroid, $centroids)) {
$centroids[] = $randCentroid;
}
}
}
$clusters = [];
$iter = 0;
do {
$clusters = array_fill(0, $k, []);
// Assign ke klaster terdekat (jarak absolut 1 dimensi)
foreach ($values as $idx => $val) {
$distances = [];
foreach ($centroids as $cidx => $centroid) {
$distances[$cidx] = abs($val - $centroid);
}
asort($distances);
$nearestCluster = key($distances);
$clusters[$nearestCluster][] = $idx;
}
// Hitung centroid baru
$newCentroids = [];
foreach ($clusters as $cluster) {
if (count($cluster) > 0) {
$sum = 0;
foreach ($cluster as $i) {
$sum += $values[$i];
}
$newCentroids[] = $sum / count($cluster);
} else {
// Jika cluster kosong, pilih centroid random
$newCentroids[] = $values[array_rand($values)];
}
}
$iter++;
if ($newCentroids === $centroids) break;
if ($iter >= $maxIter) break;
$centroids = $newCentroids;
} while (true);
// Fungsi hitung rata-rata jarak
$avgDistance = function(int $i, array $cluster) use ($values): float {
if (count($cluster) <= 1) return 0;
$sum = 0;
foreach ($cluster as $idx) {
if ($idx == $i) continue;
$sum += abs($values[$i] - $values[$idx]);
}
return $sum / (count($cluster) - 1);
};
// Hitung silhouette untuk setiap data
$silhouetteScores = [];
for ($i = 0; $i < count($values); $i++) {
// Cari klaster data ke-i
$clusterIdx = null;
foreach ($clusters as $cidx => $cluster) {
if (in_array($i, $cluster)) {
$clusterIdx = $cidx;
break;
}
}
$a = $avgDistance($i, $clusters[$clusterIdx]);
$b = INF;
foreach ($clusters as $cidx => $cluster) {
if ($cidx == $clusterIdx) continue;
$dist = $avgDistance($i, $cluster);
if ($dist < $b) $b = $dist;
}
$silhouetteScores[] = ($b - $a) / max($a, $b);
}
$silhouette = array_sum($silhouetteScores) / count($silhouetteScores);
// Bentuk output anggota klaster dengan kecamatan_id
$clusterMembers = [];
foreach ($clusters as $cidx => $cluster) {
$clusterMembers[$cidx] = [];
foreach ($cluster as $idx) {
$clusterMembers[$cidx][] = $ids[$idx];
}
}
$hasil = [
'silhouette' => $silhouette,
'jumlah_klaster' => $k,
'anggota_klaster' => $clusterMembers,
'iterasi' => $iter,
'centroid' => $centroids,
];
// Simpan ke file JSON
file_put_contents(
storage_path('app/public/silhoute_kmeans_curas.json'),
json_encode($hasil, JSON_PRETTY_PRINT)
);
return $hasil;
}
} }

View File

@ -17,7 +17,7 @@ public function up(): void
table: 'kecamatans', indexName: 'curas_kecamatan_id'); table: 'kecamatans', indexName: 'curas_kecamatan_id');
$table->float('jumlah_curas'); $table->float('jumlah_curas');
$table->foreignId('klaster_id')->nullable()->constrained( $table->foreignId('klaster_id')->nullable()->constrained(
table: 'klasters', indexName: 'curas_klaster_id'); table: 'klasters', indexName: 'curas_klaster_id')->nullOnDelete();
$table->timestamps(); $table->timestamps();
}); });
} }

View File

@ -17,7 +17,7 @@ public function up(): void
table: 'kecamatans', indexName: 'curanmor_kecamatan_id'); table: 'kecamatans', indexName: 'curanmor_kecamatan_id');
$table->float('jumlah_curanmor'); $table->float('jumlah_curanmor');
$table->foreignId('klaster_id')->nullable()->constrained( $table->foreignId('klaster_id')->nullable()->constrained(
table: 'klasters', indexName: 'klaster_kecamatan_id'); table: 'klasters', indexName: 'klaster_kecamatan_id')->nullOnDelete();
$table->timestamps(); $table->timestamps();
}); });
} }

View File

@ -19,38 +19,68 @@ public function run(): void
// Data jumlah curanmor untuk setiap kecamatan // Data jumlah curanmor untuk setiap kecamatan
$dataCuranmor= [ $dataCuranmor= [
1 => 5, 1 => 11,
2 => 4, 2 => 14,
3 => 2, 3 => 21,
4 => 22, 4 => 59,
5 => 4, 5 => 8,
6 => 18, 6 => 42,
7 => 0, 7 => 13,
8 => 37, 8 => 188,
9 => 9, 9 => 30,
10 => 3, 10 => 13,
11 => 2, 11 => 4,
12 => 13, 12 => 33,
13 => 1, 13 => 3,
14 => 21, 14 => 48,
15 => 14, 15 => 53,
16 => 4, 16 => 12,
17 => 10, 17 => 30,
18 => 0, 18 => 5,
19 => 1, 19 => 4,
20 => 10, 20 => 10,
21 => 1, 21 => 5,
22 => 2, 22 => 7,
23 => 15, 23 => 15,
24 => 4, 24 => 4,
]; ];
// $dataCuranmor= [
// 1 => 5,
// 2 => 4,
// 3 => 2,
// 4 => 22,
// 5 => 4,
// 6 => 18,
// 7 => 0,
// 8 => 37,
// 9 => 9,
// 10 => 3,
// 11 => 2,
// 12 => 13,
// 13 => 1,
// 14 => 21,
// 15 => 14,
// 16 => 4,
// 17 => 10,
// 18 => 0,
// 19 => 1,
// 20 => 5,
// 21 => 1,
// 22 => 2,
// 23 => 5,
// 24 => 2,
// ];
$defaultDate = '2024-12-31 00:00:00';
// Looping untuk membuat data curanmor berdasarkan kecamatan // Looping untuk membuat data curanmor berdasarkan kecamatan
foreach ($kecamatanIds as $kecamatanId) { foreach ($kecamatanIds as $kecamatanId) {
Curanmor::create([ Curanmor::create([
'kecamatan_id' => $kecamatanId, 'kecamatan_id' => $kecamatanId,
'jumlah_curanmor' => $dataCuranmor[$kecamatanId], // Gunakan nilai default jika tidak ada data 'jumlah_curanmor' => $dataCuranmor[$kecamatanId], // Gunakan nilai default jika tidak ada data
'klaster_id' => $klasterIds->random(), // Pilih klaster secara acak 'klaster_id' => $klasterIds->random(), // Pilih klaster secara acak
'created_at' => $defaultDate,
'updated_at' => $defaultDate,
]); ]);
} }
} }

View File

@ -17,20 +17,20 @@ public function run(): void
$dataCuras = [ $dataCuras = [
1 => 0, 1 => 0,
2 => 0, 2 => 1,
3 => 0, 3 => 2,
4 => 0, 4 => 1,
5 => 1, 5 => 1,
6 => 1, 6 => 1,
7 => 0, 7 => 0,
8 => 0, 8 => 1,
9 => 0, 9 => 1,
10 => 0, 10 => 0,
11 => 0, 11 => 0,
12 => 0, 12 => 0,
13 => 0, 13 => 0,
14 => 0, 14 => 0,
15 => 0, 15 => 1,
16 => 0, 16 => 0,
17 => 0, 17 => 0,
18 => 0, 18 => 0,
@ -42,6 +42,33 @@ public function run(): void
24 => 2, 24 => 2,
]; ];
// $dataCuras = [
// 1 => 0,
// 2 => 0,
// 3 => 0,
// 4 => 0,
// 5 => 1,
// 6 => 1,
// 7 => 0,
// 8 => 0,
// 9 => 0,
// 10 => 0,
// 11 => 0,
// 12 => 0,
// 13 => 0,
// 14 => 0,
// 15 => 0,
// 16 => 0,
// 17 => 0,
// 18 => 0,
// 19 => 0,
// 20 => 1,
// 21 => 0,
// 22 => 0,
// 23 => 3,
// 24 => 2,
// ];
$defaultDate = '2024-12-31 00:00:00'; // Default date to be used for both created_at and updated_at $defaultDate = '2024-12-31 00:00:00'; // Default date to be used for both created_at and updated_at

View File

@ -25,6 +25,10 @@ public function run(): void
CuranmorSeeder::class, CuranmorSeeder::class,
]); ]);
$serviceKMeans = new KMeansService();
$serviceKMeans->SSEElbowCuranmor();
$serviceKMeans->SSEElbowCuras();
$serviceKMeansCuras = new KMeansService(); $serviceKMeansCuras = new KMeansService();
$hasilKMeansCuras = $serviceKMeansCuras->hitungKMeansCuras(); $hasilKMeansCuras = $serviceKMeansCuras->hitungKMeansCuras();
file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras)); file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras));

View File

@ -15,17 +15,17 @@ public function run(): void
{ {
Klaster::create([ Klaster::create([
'nama_klaster'=> 'Aman', 'nama_klaster'=> 'Aman',
'warna'=> '#00FF00', 'warna'=> '#27AE60',
]); ]);
Klaster::create([ Klaster::create([
'nama_klaster'=> 'Sedang', 'nama_klaster'=> 'Sedang',
'warna'=> '#FFFF00', 'warna'=> '#F1C40F',
]); ]);
Klaster::create([ Klaster::create([
'nama_klaster'=> 'Rawan', 'nama_klaster'=> 'Rawan',
'warna'=> '#FF0000', 'warna'=> '#E74C3C',
]); ]);
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1012,6 +1012,7 @@ if (jQuery("#radar-multiple-chart").length) {
// Create series // Create series
var series = chart.series.push(new am4charts.ColumnSeries()); var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "visits"; series.dataFields.valueY = "visits";
series.dataFields.categoryX = "country"; series.dataFields.categoryX = "country";
series.name = "Visits"; series.name = "Visits";
@ -5193,135 +5194,69 @@ if (jQuery("#editor").length) {
apexChartUpdate(chart, e.detail) apexChartUpdate(chart, e.detail)
}) })
} }
if(jQuery('#layout1-chart-2').length){
if (jQuery('#layout1-chart-2').length) {
am4core.ready(function() { am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated); am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance // Buat chart instance
var chart = am4core.create("layout1-chart-2", am4charts.XYChart); var chart = am4core.create("layout1-chart-2", am4charts.XYChart);
chart.colors.list = [
am4core.color("#32BDEA"),
am4core.color("#32BDEA"),
am4core.color("#32BDEA"),
am4core.color("#32BDEA"),
am4core.color("#32BDEA"),
am4core.color("#32BDEA"),
am4core.color("#32BDEA"),
am4core.color("#32BDEA"),
am4core.color("#32BDEA")
];
chart.scrollbarX = new am4core.Scrollbar();
// Add data // Inisialisasi axes & series di luar agar tidak duplikat
chart.data = [{ let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
"country": "Jan", categoryAxis.dataFields.category = "k";
"visits": 3025
}, {
"country": "Feb",
"visits": 1882
}, {
"country": "Mar",
"visits": 1809
}, {
"country": "Apr",
"visits": 1322
}, {
"country": "May",
"visits": 1122
}, {
"country": "Jun",
"visits": 1114
}, {
"country": "Jul",
"visits": 984
}, {
"country": "Aug",
"visits": 711
}];
prepareParetoData();
function prepareParetoData(){
var total = 0;
for(var i = 0; i < chart.data.length; i++){
var value = chart.data[i].visits;
total += value;
}
var sum = 0;
for(var i = 0; i < chart.data.length; i++){
var value = chart.data[i].visits;
sum += value;
chart.data[i].pareto = sum / total * 100;
}
}
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "country";
categoryAxis.renderer.grid.template.location = 0; categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 60; categoryAxis.renderer.minGridDistance = 30;
categoryAxis.tooltip.disabled = true; categoryAxis.title.text = "Jumlah Klaster (K)";
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.minWidth = 50; valueAxis.title.text = "Nilai SSE";
valueAxis.min = 0;
valueAxis.cursorTooltipEnabled = false;
// Create series let lineSeries = chart.series.push(new am4charts.LineSeries());
var series = chart.series.push(new am4charts.ColumnSeries()); lineSeries.dataFields.valueY = "sse";
series.sequencedInterpolation = true; lineSeries.dataFields.categoryX = "k";
series.dataFields.valueY = "visits"; lineSeries.name = "SSE";
series.dataFields.categoryX = "country"; lineSeries.strokeWidth = 2;
series.tooltipText = "[{categoryX}: bold]{valueY}[/]"; lineSeries.tooltipText = "K={categoryX}\nSSE={valueY}"; // Tooltip tanpa centroid_awal
series.columns.template.strokeWidth = 0; lineSeries.tensionX = 1;
series.tooltip.pointerOrientation = "vertical"; let bullet = lineSeries.bullets.push(new am4charts.CircleBullet());
bullet.circle.radius = 4;
series.columns.template.column.cornerRadiusTopLeft = 10;
series.columns.template.column.cornerRadiusTopRight = 10;
series.columns.template.column.fillOpacity = 0.8;
// on hover, make corner radiuses bigger
var hoverState = series.columns.template.column.states.create("hover");
hoverState.properties.cornerRadiusTopLeft = 0;
hoverState.properties.cornerRadiusTopRight = 0;
hoverState.properties.fillOpacity = 1;
series.columns.template.adapter.add("fill", function(fill, target) {
return chart.colors.getIndex(target.dataItem.index);
})
var paretoValueAxis = chart.yAxes.push(new am4charts.ValueAxis());
paretoValueAxis.renderer.opposite = true;
paretoValueAxis.min = 0;
paretoValueAxis.max = 100;
paretoValueAxis.strictMinMax = true;
paretoValueAxis.renderer.grid.template.disabled = true;
paretoValueAxis.numberFormatter = new am4core.NumberFormatter();
paretoValueAxis.numberFormatter.numberFormat = "#'%'"
paretoValueAxis.cursorTooltipEnabled = false;
var paretoSeries = chart.series.push(new am4charts.LineSeries())
paretoSeries.dataFields.valueY = "pareto";
paretoSeries.dataFields.categoryX = "country";
paretoSeries.yAxis = paretoValueAxis;
paretoSeries.tooltipText = "pareto: {valueY.formatNumber('#.0')}%[/]";
paretoSeries.bullets.push(new am4charts.CircleBullet());
paretoSeries.strokeWidth = 2;
paretoSeries.stroke = new am4core.InterfaceColorSet().getFor("alternativeBackground");
paretoSeries.strokeOpacity = 0.5;
// Cursor
chart.cursor = new am4charts.XYCursor(); chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = "panX"; chart.cursor.behavior = "panX";
chart.cursor.lineX.disabled = false;
chart.cursor.lineY.disabled = false;
}); // end am4core.ready() chart.scrollbarX = new am4core.Scrollbar();
// Fungsi untuk load data berdasarkan tipe
function loadChartData(type) {
fetch(`/storage/sse_elbow_${type}.json`)
.then(response => response.json())
.then(data => {
// Format data untuk chart
chart.data = data.map(item => ({
k: item.k,
sse: item.sse
}));
console.log("Data yang dimuat ke chart:", chart.data);
});
}
// Load data default saat pertama kali (curanmor)
loadChartData('curanmor');
// Event listener dropdown untuk memilih tipe data
document.querySelectorAll('.chart-option').forEach(item => {
item.addEventListener('click', function(e) {
e.preventDefault();
const selected = this.getAttribute('data-value');
loadChartData(selected);
document.getElementById('dropdownMenuButton002').innerHTML = this.innerText + '<i class="ri-arrow-down-s-line ml-1"></i>';
});
});
});
} }
if (jQuery("#layout1-chart-3").length) { if (jQuery("#layout1-chart-3").length) {
options = { options = {

View File

@ -0,0 +1,91 @@
<x-layoutAdmin>
<div class="content-page">
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<div class="d-flex flex-wrap align-items-center justify-content-between mb-4">
<div>
<h4 class="mb-3">Detail Perhitungan Curanmor</h4>
<p class="mb-0">Berikut merupakan detail perhitungan jarak antar setiap data terhadap setiap centroid pada masing masing iterasi. </p>
</div>
</div>
@if (session()->has('succes'))
<div class="alert alert-success" role="alert">
{{ session('succes') }}
</div>
@endif
@if (session()->has('error'))
<div class="alert alert-danger" role="alert">
{{ session('error') }}
</div>
@endif
</div>
<div class="col-lg-12">
<h5>Nilai Centroid Awal</h5>
<table class="data-table table mb-0 tbl-server-info">
<thead class="bg-white text-uppercase">
<tr class="ligth ligth-data">
@foreach ($data['centroid_awal'] as $centroid)
<th class="text-center">{{ array_key_first($centroid) }}</th>
@endforeach
</tr>
</thead>
<tbody class="ligth-body">
<tr>
@foreach ($data['centroid_awal'] as $centroid)
<td class="text-center">{{ array_values($centroid)[0] }}</td>
@endforeach
</tr>
</tbody>
</table>
</div>
<div class="col-lg-12">
<br><br><br>
@foreach ($data['iterasi'] as $index => $iterasi)
<h5>Iterasi ke-{{ $index + 1 }}</h5>
<div class="table-responsive rounded mb-3">
<table class="data-table table mb-0 tbl-server-info">
<thead class="bg-white text-uppercase">
<tr class="ligth ligth-data">
<th>Nama Kecamatan</th>
@foreach (array_keys($iterasi[0]) as $key)
@if ($key !== 'kecamatan_id')
<th class="text-center">{{ $key }}</th>
@endif
@endforeach
<th>Hasil</th>
</tr>
</thead>
<tbody class="ligth-body">
@foreach ($iterasi as $row)
@php
$minKey = null;
$minVal = INF;
foreach ($row as $key => $val) {
if (strpos($key, 'C') === 0 && $val < $minVal) {
$minVal = $val;
$minKey = $key;
}
}
@endphp
<tr>
<td class="text-left">{{ $kecamatan[$row['kecamatan_id']] ?? 'Tidak Diketahui' }}</td>
@foreach ($row as $key => $val)
@if ($key !== 'kecamatan_id')
<td class="text-center">{{ $val }}</td>
@endif
@endforeach
<td><strong>{{ strtoupper($minKey) }}</strong></td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endforeach
</div>
</div>
<!-- Page end -->
</div>
</div>
</x-layoutAdmin>

View File

@ -0,0 +1,91 @@
<x-layoutAdmin>
<div class="content-page">
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<div class="d-flex flex-wrap align-items-center justify-content-between mb-4">
<div>
<h4 class="mb-3">Detail Perhitungan Curas</h4>
<p class="mb-0">Berikut merupakan detail perhitungan jarak antar setiap data terhadap setiap centroid pada masing masing iterasi. </p>
</div>
</div>
@if (session()->has('succes'))
<div class="alert alert-success" role="alert">
{{ session('succes') }}
</div>
@endif
@if (session()->has('error'))
<div class="alert alert-danger" role="alert">
{{ session('error') }}
</div>
@endif
</div>
<div class="col-lg-12">
<h5>Nilai Centroid Awal</h5>
<table class="data-table table mb-0 tbl-server-info">
<thead class="bg-white text-uppercase">
<tr class="ligth ligth-data">
@foreach ($data['centroid_awal'] as $centroid)
<th class="text-center">{{ array_key_first($centroid) }}</th>
@endforeach
</tr>
</thead>
<tbody class="ligth-body">
<tr>
@foreach ($data['centroid_awal'] as $centroid)
<td class="text-center">{{ array_values($centroid)[0] }}</td>
@endforeach
</tr>
</tbody>
</table>
</div>
<div class="col-lg-12">
<br><br><br>
@foreach ($data['iterasi'] as $index => $iterasi)
<h5>Iterasi ke-{{ $index + 1 }}</h5>
<div class="table-responsive rounded mb-3">
<table class="data-table table mb-0 tbl-server-info">
<thead class="bg-white text-uppercase">
<tr class="ligth ligth-data">
<th>Nama Kecamatan</th>
@foreach (array_keys($iterasi[0]) as $key)
@if ($key !== 'kecamatan_id')
<th class="text-center">{{ $key }}</th>
@endif
@endforeach
<th>Hasil</th>
</tr>
</thead>
<tbody class="ligth-body">
@foreach ($iterasi as $row)
@php
$minKey = null;
$minVal = INF;
foreach ($row as $key => $val) {
if (strpos($key, 'C') === 0 && $val < $minVal) {
$minVal = $val;
$minKey = $key;
}
}
@endphp
<tr>
<td class="text-left">{{ $kecamatan[$row['kecamatan_id']] ?? 'Tidak Diketahui' }}</td>
@foreach ($row as $key => $val)
@if ($key !== 'kecamatan_id')
<td class="text-center">{{ $val }}</td>
@endif
@endforeach
<td><strong>{{ strtoupper($minKey) }}</strong></td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endforeach
</div>
</div>
<!-- Page end -->
</div>
</div>
</x-layoutAdmin>

View File

@ -77,11 +77,72 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-sm-12 col-lg-6">
<div class="card">
<div class="card-header d-flex justify-content-between">
<div class="header-title">
<h4 class="card-title">5 Kecamatan Tertinggi Kasus Curas</h4>
</div>
</div>
<div class="card-body">
<p>Berikut merupakan 5 Kecamatan yang memiliki kasus CURAS tertinggi</p>
<table class="table">
<thead>
<tr class="ligth">
<th scope="col">Nama Kecamatan</th>
<th scope="col">Jumlah Curas</th>
<th scope="col">Klaster</th>
</tr>
</thead>
<tbody>
@foreach ( $curasTertinggis as $curasTertinggi )
<tr style="background-color: {{ $curasTertinggi->punyaKlasterCuras->warna }}">
<td>{{ $curasTertinggi->punyaKecamatanCuras->nama_kecamatan }}</td>
<td>{{ $curasTertinggi->jumlah_curas }}</td>
<td>{{ $curasTertinggi->punyaKlasterCuras->nama_klaster }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-12 col-lg-6">
<div class="card">
<div class="card-header d-flex justify-content-between">
<div class="header-title">
<h4 class="card-title">5 Kecamatan Tertinggi Kasus Curanmor</h4>
</div>
</div>
<div class="card-body">
<p>Berikut merupakan 5 Kecamatan yang memiliki kasus CURANMOR tertinggi</p>
<table class="table">
<thead>
<tr class="ligth">
<th scope="col">Nama Kecamatan</th>
<th scope="col">Jumlah Curanmor</th>
<th scope="col">Klaster</th>
</tr>
</thead>
<tbody>
@foreach ( $curanmorTertinggis as $curanmorTertinggi )
<tr style="background-color: {{ $curanmorTertinggi->punyaKlasterCuranmor->warna }}">
<td>{{ $curanmorTertinggi->punyaKecamatanCuranmor->nama_kecamatan }}</td>
<td>{{ $curanmorTertinggi->jumlah_curanmor }}</td>
<td>{{ $curanmorTertinggi->punyaKlasterCuranmor->nama_klaster }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
<div class="col-lg-12"> <div class="col-lg-12">
<div class="card card-block card-stretch card-height"> <div class="card card-block card-stretch card-height">
<div class="card-header d-flex justify-content-between"> <div class="card-header d-flex justify-content-between">
<div class="header-title"> <div class="header-title">
<h4 class="card-title">Pemetaan Curas dan Curanmor Kab Probolinggo</h4> <h4 class="card-title" id="map-card-title">Pemetaan Curas dan Curanmor Kab Probolinggo</h4>
</div> </div>
<div class="card-header-toolbar d-flex align-items-center"> <div class="card-header-toolbar d-flex align-items-center">
<div class="dropdown"> <div class="dropdown">
@ -103,7 +164,33 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-12">
<div class="card card-block card-stretch card-height">
<div class="card-header d-flex align-items-center justify-content-between">
<div class="header-title">
<h4 class="card-title">Nilai K Terbaik</h4>
</div> </div>
<div class="card-header-toolbar d-flex align-items-center">
<div class="dropdown">
<span class="dropdown-toggle dropdown-bg btn" id="dropdownMenuButton002"
data-toggle="dropdown">
Curanmor<i class="ri-arrow-down-s-line ml-1"></i>
</span>
<div class="dropdown-menu dropdown-menu-right shadow-none"
aria-labelledby="dropdownMenuButton002">
<a class="dropdown-item chart-option" data-value="curanmor" href="#">Curanmor</a>
<a class="dropdown-item chart-option" data-value="curas" href="#">Curas</a>
</div>
</div>
</div>
</div>
<div class="card-body">
<p>Perhitungan Nilai K terbaik menggunakan rumus Sum of Squared Errors (SSE) dengan nilai k = 1 sampa k = 10. Kemudian nilai SSE tersebut ditampilkan dalam Grafik Elbow Method</p>
<div id="layout1-chart-2" style="min-height: 360px;"></div>
</div>
</div>
</div>
<!-- Page end --> <!-- Page end -->
@ -112,7 +199,7 @@
<script> <script>
let map; let map;
let geoLayer; let geoLayer;
let mapTitle = document.querySelector('.card-title'); let mapTitle = document.getElementById('map-card-title');
let apiUrl = "{{ url('/api/map/curas') }}"; // default awal curas let apiUrl = "{{ url('/api/map/curas') }}"; // default awal curas
let curasData = {}; let curasData = {};
@ -177,6 +264,7 @@ function loadInitialMap() {
map = L.map('map').setView([-7.843271790154591, 113.2990930356143], 10); map = L.map('map').setView([-7.843271790154591, 113.2990930356143], 10);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19, maxZoom: 19,
minZoom: 10,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map); }).addTo(map);
fetchAndLoadMap(apiUrl, 'Pemetaan Curas Kab Probolinggo'); fetchAndLoadMap(apiUrl, 'Pemetaan Curas Kab Probolinggo');

View File

@ -11,6 +11,7 @@
</div> </div>
<a href="/dashboard/curas/create" class="btn btn-primary add-list"><i class="las la-plus mr-3"></i>Tambah Kasus Curas</a> <a href="/dashboard/curas/create" class="btn btn-primary add-list"><i class="las la-plus mr-3"></i>Tambah Kasus Curas</a>
</div> </div>
</div>
@if (session()->has('succes')) @if (session()->has('succes'))
<div class="alert alert-success" role="alert"> <div class="alert alert-success" role="alert">
{{ session('succes') }} {{ session('succes') }}
@ -21,7 +22,7 @@
{{ session('error') }} {{ session('error') }}
</div> </div>
@endif @endif
</div>
<div class="col-lg-12"> <div class="col-lg-12">
<div class="table-responsive rounded mb-3"> <div class="table-responsive rounded mb-3">
<table class="data-table table mb-0 tbl-server-info"> <table class="data-table table mb-0 tbl-server-info">

View File

@ -10,7 +10,7 @@
Kabupaten Probolinggo. </p> Kabupaten Probolinggo. </p>
</div> </div>
<a href="/dashboard/kecamatan/create" class="btn btn-primary add-list"><i class="las la-plus mr-3"></i>Tambah Kecamatan</a> {{-- <a href="/dashboard/kecamatan/create" class="btn btn-primary add-list"><i class="las la-plus mr-3"></i>Tambah Kecamatan</a> --}}
</div> </div>
@if (session()->has('succes')) @if (session()->has('succes'))
<div class="alert alert-success" role="alert"> <div class="alert alert-success" role="alert">
@ -35,8 +35,8 @@
</div> </div>
</th> </th>
<th>No</th> <th>No</th>
<th>Nama Kecamatan</th> <th class="text-center">Nama Kecamatan</th>
<th>Action</th> {{-- <th>Action</th> --}}
</tr> </tr>
</thead> </thead>
@foreach ( $kecamatans as $kecamatan ) @foreach ( $kecamatans as $kecamatan )
@ -50,7 +50,7 @@
</td> </td>
<td>{{ $kecamatan -> id }}</td> <td>{{ $kecamatan -> id }}</td>
<td>{{ $kecamatan -> nama_kecamatan }}</td> <td>{{ $kecamatan -> nama_kecamatan }}</td>
<td> {{-- <td class="text-center">
<div class="d-flex align-items-center list-action"> <div class="d-flex align-items-center list-action">
<a class="badge bg-success mr-2" data-toggle="tooltip" data-placement="top" title="" <a class="badge bg-success mr-2" data-toggle="tooltip" data-placement="top" title=""
href="/dashboard/kecamatan/{{ $kecamatan ->id}}/edit"><i class="ri-pencil-line mr-0"></i></a> href="/dashboard/kecamatan/{{ $kecamatan ->id}}/edit"><i class="ri-pencil-line mr-0"></i></a>
@ -61,7 +61,7 @@
</form> </form>
</div> </div>
</td> </td> --}}
</tr> </tr>
</tbody> </tbody>
@endforeach @endforeach

View File

@ -9,7 +9,6 @@
<p class="mb-0">Berikut merupakan data Klaster atau Kategori yang dijadikan sebagai acuan pemetaan.<br> <p class="mb-0">Berikut merupakan data Klaster atau Kategori yang dijadikan sebagai acuan pemetaan.<br>
Ingat dalam pengisian data klaster, kategori aman atau rendah dimulai dari id 1</p> Ingat dalam pengisian data klaster, kategori aman atau rendah dimulai dari id 1</p>
</div> </div>
<a href="/dashboard/klaster/create" class="btn btn-primary add-list"><i class="las la-plus mr-3"></i>Tambah Klaster</a>
</div> </div>
</div> </div>
@if (session()->has('succes')) @if (session()->has('succes'))
@ -36,7 +35,7 @@
<th>id</th> <th>id</th>
<th>Nama Klaster</th> <th>Nama Klaster</th>
<th>Warna</th> <th>Warna</th>
<th>Action</th> {{-- <th>Action</th> --}}
</tr> </tr>
</thead> </thead>
@foreach ( $klasters as $klaster ) @foreach ( $klasters as $klaster )
@ -51,7 +50,7 @@
<td>{{ $klaster -> id }}</td> <td>{{ $klaster -> id }}</td>
<td>{{ $klaster -> nama_klaster }}</td> <td>{{ $klaster -> nama_klaster }}</td>
<td style="background-color: {{ $klaster->warna }}" >{{ $klaster -> warna }}</td> <td style="background-color: {{ $klaster->warna }}" >{{ $klaster -> warna }}</td>
<td> {{-- <td>
<div class="d-flex align-items-center list-action"> <div class="d-flex align-items-center list-action">
<a class="badge bg-success mr-2" data-toggle="tooltip" data-placement="top" title="" <a class="badge bg-success mr-2" data-toggle="tooltip" data-placement="top" title=""
href="/dashboard/klaster/{{ $klaster->id }}/edit"><i class="ri-pencil-line mr-0"></i></a> href="/dashboard/klaster/{{ $klaster->id }}/edit"><i class="ri-pencil-line mr-0"></i></a>
@ -62,7 +61,7 @@
</form> </form>
</div> </div>
</td> </td> --}}
</tr> </tr>
</tbody> </tbody>
@endforeach @endforeach

View File

@ -1,6 +1,7 @@
<x-layoutAdmin> <x-layoutAdmin>
<div class="content-page"> <div class="content-page">
<div class="container-fluid add-form-list"> <div class="container-fluid add-form-
">
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<div class="card"> <div class="card">

View File

@ -39,7 +39,7 @@
<div class="iq-sidebar sidebar-default "> <div class="iq-sidebar sidebar-default ">
<div class="iq-sidebar-logo d-flex align-items-center justify-content-between"> <div class="iq-sidebar-logo d-flex align-items-center justify-content-between">
<a href="/dashboard" class="header-logo"> <a href="/dashboard" class="header-logo">
<img src="{{ asset('/assets/images/logo.png') }}" class="img-fluid rounded-normal light-logo" alt="logo"><h5 class="logo-title light-logo ml-3">PROTECT</h5> <img src="{{ asset('assets/images/logo.png') }}" class="img-fluid rounded-normal light-logo" alt="logo"><h5 class="logo-title light-logo ml-3">KPROTECT</h5>
</a> </a>
<div class="iq-menu-bt-sidebar ml-0"> <div class="iq-menu-bt-sidebar ml-0">
<i class="las la-bars wrapper-menu"></i> <i class="las la-bars wrapper-menu"></i>
@ -56,7 +56,21 @@
<span class="ml-4">Dashboard</span> <span class="ml-4">Dashboard</span>
</a> </a>
</li> </li>
<li class=" {{ Request::is('dashboard/kecamatan')||Request::is('dashboard/kecamatan/create') ? 'active' : '' }}"> <li class="{{ Request::is('dashboard/kecamatan') ? 'active' : '' }}">
<a href="/dashboard/kecamatan" class="svg-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M5.875 12.5729C5.30847 11.2498 5 9.84107 5 8.51463C5 4.9167 8.13401 2 12 2C15.866 2 19 4.9167 19 8.51463C19 12.0844 16.7658 16.2499 13.2801 17.7396C12.4675 18.0868 11.5325 18.0868 10.7199 17.7396C9.60664 17.2638 8.62102 16.5151 7.79508 15.6" stroke="#676e8a" stroke-width="1.9200000000000004" stroke-linecap="round"></path> <path d="M14 9C14 10.1046 13.1046 11 12 11C10.8954 11 10 10.1046 10 9C10 7.89543 10.8954 7 12 7C13.1046 7 14 7.89543 14 9Z" stroke="#676e8a" stroke-width="1.9200000000000004"></path> <path d="M20.9605 15.5C21.6259 16.1025 22 16.7816 22 17.5C22 18.4251 21.3797 19.285 20.3161 20M3.03947 15.5C2.37412 16.1025 2 16.7816 2 17.5C2 19.9853 6.47715 22 12 22C13.6529 22 15.2122 21.8195 16.5858 21.5" stroke="#676e8a" stroke-width="1.9200000000000004" stroke-linecap="round"></path> </g></svg>
<span class="ml-4">Kecamatan</span>
</a>
</li>
<li class="{{ Request::is('dashboard/klaster') ? 'active' : '' }}">
<a href="/dashboard/klaster" class="svg-icon">
<svg class="svg-icon" id="p-dash4" width="20" height="20" xmlns="http://www.w3.org/ 2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21.21 15.89A10 10 0 1 1 8 2.83"></path><path d="M22 12A10 10 0 0 0 12 2v10z"></path>
</svg>
<span class="ml-4">Klaster</span>
</a>
</li>
{{-- <li class=" {{ Request::is('dashboard/kecamatan')||Request::is('dashboard/kecamatan/create') ? 'active' : '' }}">
<a href="#product" class="collapsed" data-toggle="collapse" aria-expanded="false"> <a href="#product" class="collapsed" data-toggle="collapse" aria-expanded="false">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M5.875 12.5729C5.30847 11.2498 5 9.84107 5 8.51463C5 4.9167 8.13401 2 12 2C15.866 2 19 4.9167 19 8.51463C19 12.0844 16.7658 16.2499 13.2801 17.7396C12.4675 18.0868 11.5325 18.0868 10.7199 17.7396C9.60664 17.2638 8.62102 16.5151 7.79508 15.6" stroke="#676e8a" stroke-width="1.9200000000000004" stroke-linecap="round"></path> <path d="M14 9C14 10.1046 13.1046 11 12 11C10.8954 11 10 10.1046 10 9C10 7.89543 10.8954 7 12 7C13.1046 7 14 7.89543 14 9Z" stroke="#676e8a" stroke-width="1.9200000000000004"></path> <path d="M20.9605 15.5C21.6259 16.1025 22 16.7816 22 17.5C22 18.4251 21.3797 19.285 20.3161 20M3.03947 15.5C2.37412 16.1025 2 16.7816 2 17.5C2 19.9853 6.47715 22 12 22C13.6529 22 15.2122 21.8195 16.5858 21.5" stroke="#676e8a" stroke-width="1.9200000000000004" stroke-linecap="round"></path> </g></svg> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M5.875 12.5729C5.30847 11.2498 5 9.84107 5 8.51463C5 4.9167 8.13401 2 12 2C15.866 2 19 4.9167 19 8.51463C19 12.0844 16.7658 16.2499 13.2801 17.7396C12.4675 18.0868 11.5325 18.0868 10.7199 17.7396C9.60664 17.2638 8.62102 16.5151 7.79508 15.6" stroke="#676e8a" stroke-width="1.9200000000000004" stroke-linecap="round"></path> <path d="M14 9C14 10.1046 13.1046 11 12 11C10.8954 11 10 10.1046 10 9C10 7.89543 10.8954 7 12 7C13.1046 7 14 7.89543 14 9Z" stroke="#676e8a" stroke-width="1.9200000000000004"></path> <path d="M20.9605 15.5C21.6259 16.1025 22 16.7816 22 17.5C22 18.4251 21.3797 19.285 20.3161 20M3.03947 15.5C2.37412 16.1025 2 16.7816 2 17.5C2 19.9853 6.47715 22 12 22C13.6529 22 15.2122 21.8195 16.5858 21.5" stroke="#676e8a" stroke-width="1.9200000000000004" stroke-linecap="round"></path> </g></svg>
<span class="ml-4">Kecamatan</span> <span class="ml-4">Kecamatan</span>
@ -99,7 +113,7 @@
</a> </a>
</li> </li>
</ul> </ul>
</li> </li> --}}
<li class=" {{ Request::is('dashboard/curas')||Request::is('dashboard/curas/create') ||Request::is('dashboard/curanmor/create') ||Request::is('dashboard/curanmor/create') ||Request::is('dashboard/detail-curas') ||Request::is('dashboard/detail-curanmor') ? 'active' : '' }}"> <li class=" {{ Request::is('dashboard/curas')||Request::is('dashboard/curas/create') ||Request::is('dashboard/curanmor/create') ||Request::is('dashboard/curanmor/create') ||Request::is('dashboard/detail-curas') ||Request::is('dashboard/detail-curanmor') ? 'active' : '' }}">
<a href="#people" class="collapsed" data-toggle="collapse" aria-expanded="false"> <a href="#people" class="collapsed" data-toggle="collapse" aria-expanded="false">
<svg class="svg-icon" id="p-dash8" width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg class="svg-icon" id="p-dash8" width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@ -166,6 +180,28 @@
</li> </li>
</ul> </ul>
</li> </li>
<li class=" {{ Request::is('dashboard/TampilHitungCuras')||Request::is('dashboard/TampilHitungCuranmor') ? 'active' : '' }}">
<a href="#return" class="collapsed" data-toggle="collapse" aria-expanded="false">
<svg fill="#676e8a" height="20px" width="20px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve" stroke="#676e8a"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <g> <path d="M468.293,0c-6.07,0-418.515,0-424.585,0C19.607,0,0,19.607,0,43.707c0,6.07,0,418.515,0,424.585 C0,492.393,19.607,512,43.707,512c6.07,0,418.515,0,424.585,0c24.1,0,43.707-19.607,43.707-43.707c0-6.07,0-418.515,0-424.585 C512,19.607,492.393,0,468.293,0z M237.268,474.537H43.707c-3.443,0-6.244-2.801-6.244-6.244V274.732h199.805V474.537z M237.268,237.268H37.463V43.707c0-3.443,2.801-6.244,6.244-6.244h193.561V237.268z M474.537,468.293 c0,3.443-2.801,6.244-6.244,6.244H274.732V274.732h199.805V468.293z M474.537,237.268H274.732V37.463h193.561 c3.443,0,6.244,2.801,6.244,6.244V237.268z"></path> </g> </g> <g> <g> <path d="M177.327,118.634h-21.229V97.405c0-10.345-8.387-18.732-18.732-18.732s-18.732,8.387-18.732,18.732v21.229H97.405 c-10.345,0-18.732,8.387-18.732,18.732s8.387,18.732,18.732,18.732h21.229v21.229c0,10.345,8.387,18.732,18.732,18.732 s18.732-8.387,18.732-18.732v-21.229h21.229c10.345,0,18.732-8.387,18.732-18.732S187.672,118.634,177.327,118.634z"></path> </g> </g> <g> <g> <path d="M414.595,384.624h-79.43c-9.616,0-18.051,7.044-19.106,16.601c-1.246,11.299,7.568,20.862,18.614,20.862h79.43 c9.616,0,18.051-7.044,19.106-16.601C434.456,394.188,425.642,384.624,414.595,384.624z"></path> </g> </g> <g> <g> <path d="M414.595,327.18h-79.43c-9.616,0-18.051,7.044-19.106,16.601c-1.246,11.299,7.568,20.862,18.614,20.862h79.43 c9.616,0,18.051-7.044,19.106-16.601C434.456,336.744,425.642,327.18,414.595,327.18z"></path> </g> </g> <g> <g> <path d="M414.595,118.634h-79.922c-10.345,0-18.732,8.387-18.732,18.732s8.387,18.732,18.732,18.732h79.922 c10.345,0,18.732-8.387,18.732-18.732S424.94,118.634,414.595,118.634z"></path> </g> </g> <g> <g> <path d="M178.868,389.646l-15.012-15.012l15.012-15.012c7.315-7.315,7.315-19.175-0.001-26.49c-7.314-7.314-19.175-7.315-26.49,0 l-15.01,15.012l-15.012-15.012c-7.313-7.314-19.174-7.315-26.49,0c-7.315,7.315-7.315,19.175,0,26.49l15.012,15.012 l-15.012,15.012c-7.315,7.315-7.315,19.175,0,26.49c7.314,7.314,19.175,7.315,26.49,0l15.012-15.012l15.012,15.012 c7.314,7.315,19.174,7.315,26.49,0C186.183,408.821,186.183,396.961,178.868,389.646z"></path> </g> </g> </g></svg>
<span class="ml-4">Detail Perhitungan
</span>
<svg class="svg-icon iq-arrow-right arrow-active" width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="10 15 15 20 20 15"></polyline><path d="M4 4h7a4 4 0 0 1 4 4v12"></path>
</svg>
</a>
<ul id="return" class="iq-submenu collapse" data-parent="#iq-sidebar-toggle">
<li class="">
<a href="/dashboard/TampilHitungCuras">
<i class="las la-minus"></i><span>K - Means Curas</span>
</a>
</li>
<li class="">
<a href="/dashboard/TampilHitungCuranmor">
<i class="las la-minus"></i><span>K - Means Curanmor</span>
</a>
</li>
</ul>
</li>
@ -178,9 +214,9 @@
<nav class="navbar navbar-expand-lg navbar-light p-0"> <nav class="navbar navbar-expand-lg navbar-light p-0">
<div class="iq-navbar-logo d-flex align-items-center justify-content-between"> <div class="iq-navbar-logo d-flex align-items-center justify-content-between">
<i class="ri-menu-line wrapper-menu"></i> <i class="ri-menu-line wrapper-menu"></i>
<a href="../backend/index.html" class="header-logo"> <a href="/dashboard" class="header-logo">
<img src="{{ asset('assets/images/logo.png') }}" class="img-fluid rounded-normal" alt="logo"> <img src="{{ asset('assets/images/logo.png') }}" class="img-fluid rounded-normal" alt="logo">
<h5 class="logo-title ml-3">PROTECT</h5> <h5 class="logo-title ml-3">KPROTECT</h5>
</a> </a>
</div> </div>
@ -335,12 +371,11 @@ class="rounded profile-img img-fluid avatar-70">
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-lg-6">
<ul class="list-inline mb-0"> <ul class="list-inline mb-0">
<li class="list-inline-item"><a href="../backend/privacy-policy.html">Privacy Policy</a></li> <li class="list-inline-item">Designed By : <a target="blank" href="https://iqonic.design/">Iconic.Design</a></li>
<li class="list-inline-item"><a href="../backend/terms-of-service.html">Terms of Use</a></li>
</ul> </ul>
</div> </div>
<div class="col-lg-6 text-right"> <div class="col-lg-6 text-right">
<span class="mr-1"><script>document.write(new Date().getFullYear())</script>©</span> <a href="#" class="">POS Dash</a>. <span class="mr-1"><script>document.write(new Date().getFullYear())</script>©</span> <a href="/" class="">KProtect</a>.
</div> </div>
</div> </div>
</div> </div>

View File

@ -88,7 +88,6 @@
.legend-item { .legend-item {
display: flex; display: flex;
align-items: left; align-items: left;
margin-bottom: 5px; margin-bottom: 5px;
} }
@ -164,9 +163,10 @@ class="img-fluid"
<!-- drop down third level --> <!-- drop down third level -->
</li> </li>
<li> <li>
<a href="#sectionMap">Map</a> <a href="#sectionOurTeam">Our Teams</a>
</li> </li>
<li><a href="#sectionOurTeam">Our Teams</a> <li>
<a href="#sectionMap">Map</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -1434,6 +1434,47 @@ class="img-fluid rounded-circle"
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-3 col-md-6">
<div class="team-box">
<div class="team-img text-center">
<img
src="{{ asset('assets/assetLanding/images/team/zahra.jpg') }}"
class="img-fluid rounded-circle"
alt="image"
/>
</div>
<div class="team-detail">
<a class="team-plus" href="#"><i class="fas fa-plus"></i></a>
<div class="team-info">
<h6 class="mb-0 text-white">
<a href="">Fatimatuzzahra <br></a>
</h6>
<span class="mb-0 text-white text-gray iq-fw-4"
>ANGGOTA PENGUJI</span
>
</div>
</div>
<div class="team-hover">
<p>
Dosen Politeknik Negeri Jember Program Studi D4 Teknik Informatika. Berperan sebagai Anggota Penguji pada Web SIG Pemetaan Daerah Rawan Curas dan Curanmor
</p>
<ul class="list-inline">
<li class="list-inline-item">
<a href="#sectionOurTeam"><i class="fab fa-facebook-f"></i></a>
</li>
<li class="list-inline-item">
<a href="#sectionOurTeam"><i class="fab fa-twitter"></i></a>
</li>
<li class="list-inline-item">
<a href="#sectionOurTeam"><i class="fab fa-linkedin-in"></i></a>
</li>
<li class="list-inline-item">
<a href="#sectionOurTeam"><i class="fab fa-instagram"></i></a>
</li>
</ul>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -1511,7 +1552,7 @@ class="tab-pane show active"
<span class="legend-label">Update Terakhir Data Curas : {{ $tanggalCuras }}</span> <span class="legend-label">Update Terakhir Data Curas : {{ $tanggalCuras }}</span>
</div> </div>
<div class="legend-item" id="update-curanmor" style="display: none;"> <div class="legend-item" id="update-curanmor" style="display: none;">
<span class="legend-label">Update Terakhir Data Curanmor : {{ $tanggalCuranmor }}</span> <span class="legend-label">Update Terakhir Curanmor : {{ $tanggalCuranmor }}</span>
</div> </div>
</div> </div>
@ -1809,8 +1850,8 @@ class="form-control position-relative subscription-email"
</li> </li>
<li class="list-item"><a href="#sectionCurasCuranmor">Curas</a></li> <li class="list-item"><a href="#sectionCurasCuranmor">Curas</a></li>
<li class="list-item"><a href="#sectionKmeans">Clustering</a></li> <li class="list-item"><a href="#sectionKmeans">Clustering</a></li>
<li class="list-item"><a href="#sectionMap">Map</a></li>
<li class="list-item"><a href="#sectionOurTeam">Our Team</a></li> <li class="list-item"><a href="#sectionOurTeam">Our Team</a></li>
<li class="list-item"><a href="#sectionMap">Map</a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -2046,7 +2087,13 @@ function popUp(feature, layer) {
} }
function loadInitialMap() { function loadInitialMap() {
map = L.map('map').setView([-7.843271790154591, 113.2990930356143], 10); map = L.map('map', {
center: [-7.843271790154591, 113.2990930356143],
zoom: 10,
minZoom: 10,
maxZoom: 19
});
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19, maxZoom: 19,
attribution: '&copy; OpenStreetMap' attribution: '&copy; OpenStreetMap'
@ -2056,41 +2103,37 @@ function loadInitialMap() {
fetchAndLoadMap(apiUrl, 'Pemetaan Curas Kab Probolinggo'); fetchAndLoadMap(apiUrl, 'Pemetaan Curas Kab Probolinggo');
} }
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// Jalankan peta awal
loadInitialMap(); loadInitialMap();
// Tombol Curas diklik
document.getElementById('btn-curas').addEventListener('click', (e) => { document.getElementById('btn-curas').addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
fetchAndLoadMap("{{ url('/api/map/curas') }}", "Pemetaan Curas Kab Probolinggo");
});
document.getElementById('btn-curanmor').addEventListener('click', (e) => {
e.preventDefault();
fetchAndLoadMap("{{ url('/api/map/curanmor') }}", "Pemetaan Curanmor Kab Probolinggo");
});
});
</script>
<script>
document.getElementById('btn-curas').addEventListener('click', (e) => {
e.preventDefault();
fetchAndLoadMap("{{ url('/api/map/curas') }}", "Pemetaan Curas Kab Probolinggo"); fetchAndLoadMap("{{ url('/api/map/curas') }}", "Pemetaan Curas Kab Probolinggo");
// Tampilkan info update curas, sembunyikan curanmor // Tampilkan info curas, sembunyikan curanmor
document.getElementById('update-curas').style.display = 'block'; document.getElementById('update-curas').style.display = 'block';
document.getElementById('update-curanmor').style.display = 'none'; document.getElementById('update-curanmor').style.display = 'none';
}); });
// Tombol Curanmor diklik
document.getElementById('btn-curanmor').addEventListener('click', (e) => { document.getElementById('btn-curanmor').addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
fetchAndLoadMap("{{ url('/api/map/curanmor') }}", "Pemetaan Curanmor Kab Probolinggo"); fetchAndLoadMap("{{ url('/api/map/curanmor') }}", "Pemetaan Curanmor Kab Probolinggo");
// Tampilkan info update curanmor, sembunyikan curas // Tampilkan info curanmor, sembunyikan curas
document.getElementById('update-curas').style.display = 'none'; document.getElementById('update-curas').style.display = 'none';
document.getElementById('update-curanmor').style.display = 'block'; document.getElementById('update-curanmor').style.display = 'block';
}); });
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -10,20 +10,33 @@
use App\Http\Controllers\dashboardController; use App\Http\Controllers\dashboardController;
use App\Http\Controllers\KecamatanController; use App\Http\Controllers\KecamatanController;
use App\Http\Controllers\DetailCurasController; use App\Http\Controllers\DetailCurasController;
use App\Http\Controllers\hasilIterasiController;
use App\Http\Controllers\DetailCuranmorController; use App\Http\Controllers\DetailCuranmorController;
use App\Http\Controllers\TampilHitunganController;
// Route Landing
Route::get('/kmeans', [LandingController::class, 'runKmeans']);
Route::get('/', [LandingController::class, 'index']); Route::get('/', [LandingController::class, 'index']);
Route::resource('/dashboard/detail-curas', DetailCurasController::class)->middleware('auth');
Route::resource('/dashboard/detail-curanmor', DetailCuranmorController::class)->middleware('auth');
Route::get('/blank', function () { Route::get('/blank', function () {
return view('admin.dashboardBlank'); return view('admin.dashboardBlank');
}); });
// Route Auth
Route::post('/login', [loginController::class, 'authenticate']);
Route::post('/logout', [loginController::class, 'logout']);
Route::get('/login', [loginController::class, 'index'])->name('login');
// Route Fitur Utama Controller
Route::get('/dashboard', [dashboardController::class, 'index'])->middleware('auth');
Route::get('/dashboard/TampilHitungCuras', [TampilHitunganController::class, 'TampilHitungCuras'])->middleware('auth');
Route::get('/dashboard/TampilHitungCuranmor', [TampilHitunganController::class, 'TampilHitungCuranmor'])->middleware('auth');
Route::resource('/dashboard/kecamatan', KecamatanController::class) ->parameters(['data-kecamatan' => 'kecamatan'])->middleware('auth');
Route::resource('/dashboard/klaster', KlasterController::class) ->parameters(['data-klaster' => 'klaster'])->middleware('auth');
Route::resource('/dashboard/curas', CurasController::class)->middleware('auth');
Route::resource('/dashboard/curanmor', CuranmorController::class) ->parameters(['data-curanmor' => 'curanmor'])->middleware('auth');
Route::resource('/dashboard/detail-curas', DetailCurasController::class)->middleware('auth');
Route::resource('/dashboard/detail-curanmor', DetailCuranmorController::class)->middleware('auth');
// Route Fitur Tampil Map Admin
Route::get('/dashboard/mapcuras', function () { Route::get('/dashboard/mapcuras', function () {
return view('admin.dashboardMapCuras'); return view('admin.dashboardMapCuras');
})->middleware('auth'); })->middleware('auth');
@ -31,16 +44,6 @@
return view('admin.dashboardMapCuranmor'); return view('admin.dashboardMapCuranmor');
})->middleware('auth'); })->middleware('auth');
Route::get('/dashboard', [dashboardController::class, 'index'])->middleware('auth'); // Route K-Means Centroid Tetap
Route::get('/login', [loginController::class, 'index'])->name('login'); Route::get('/kmeans-curas', [KmeansController::class, 'KMeansCuras'])->middleware('auth');
Route::post('/login', [loginController::class, 'authenticate']); Route::get('/kmeans-curanmor', [KmeansController::class, 'KMeansCuranmor'])->middleware('auth');
Route::post('/logout', [loginController::class, 'logout']);
Route::resource('/dashboard/kecamatan', KecamatanController::class) ->parameters(['data-kecamatan' => 'kecamatan'])->middleware('auth');
Route::resource('/dashboard/curas', CurasController::class)->middleware('auth');
Route::resource('/dashboard/curanmor', CuranmorController::class) ->parameters(['data-curanmor' => 'curanmor'])->middleware('auth');
Route::resource('/dashboard/klaster', KlasterController::class) ->parameters(['data-klaster' => 'klaster'])->middleware('auth');
Route::get('/dashboard/iterasiCuras', [hasilIterasiController::class, 'iterasiCuras'])->middleware('auth');
Route::get('/kmeans-curas', [KmeansController::class, 'KMeansCuras']);
Route::get('/kmeans-curanmor', [KmeansController::class, 'KMeansCuranmor']);