map-controller/templates/index.html
2025-07-03 20:31:42 +07:00

950 lines
46 KiB
HTML

<html>
<head>
<title>Peta Wilayah</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/select2.min.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='responsive.css') }}" />
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
.select2-selection__arrow {
display: block !important;
}
.custom-popup {
font-size: 8px; /* Atur ukuran sesuai kebutuhan */
}
</style>
</head>
<body>
<div class="main-container">
<div class="main">
<div class="searchbar2">
<input type="text" name="" id="" placeholder="Search" />
<div class="searchbtn">
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210180758/Untitled-design-(28).png"
class="icn srchicn" alt="search-button" />
</div>
</div>
<!-- <div class="box-container">
<div class="box box1">
<div class="text">
<h2 class="topic-heading">60.5k</h2>
<h2 class="topic">Article Views</h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(31).png"
alt="Views" />
</div>
<div class="box box2">
<div class="text">
<h2 class="topic-heading">150</h2>
<h2 class="topic">Likes</h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185030/14.png" alt="likes" />
</div>
<div class="box box3">
<div class="text">
<h2 class="topic-heading">320</h2>
<h2 class="topic">Comments</h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(32).png"
alt="comments" />
</div>
<div class="box box4">
<div class="text">
<h2 class="topic-heading">70</h2>
<h2 class="topic">Published</h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185029/13.png"
alt="published" />
</div>
</div> -->
<!--<div class="report-container">
<div class="report-header">
<h1 class="recent-Articles">Recent Articles</h1>
<button class="view">View All</button>
<div class="box-container">
<div class="box box1">
<div class="text">
<h2 class="topic-heading" id="tot_dd">Total Dana Desa</h2>
<h2 class="topic">Total Dana Desa</h2>
<h2></h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(31).png"
alt="Views" />
</div>
<div class="box box2">
<div class="text">
<h2 class="topic-heading" id="tot_sr">150</h2>
<h2 class="topic">Total Serapan</h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185030/14.png" alt="likes" />
</div>
<div class="box box3">
<div class="text">
<h2 class="topic-heading" id="pr_sr">320</h2>
<h2 class="topic">Persentase Serapan</h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210184645/Untitled-design-(32).png"
alt="comments" />
</div>
<div class="box box4">
<div class="text">
<h2 class="topic-heading">70</h2>
<h2 class="topic">Published</h2>
</div>
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20221210185029/13.png"
alt="published" />
</div>
</div>
</div> -->
<div class="header_container">
<div class="map-container" id="map"></div>
<div class="side_container" style="height:100%">
<div class="row form-group">
<div class="col-md-12">
<div class="input-group">
<!-- <div class="input-group-prepend">
<span class="input-group-text" style="width: 150px;">
Provinsi
</span>
</div> -->
<select class="form-control select2 border border-primary" name="provinsiDropdown" id="provinsiDropdown"
data-placeholder="Provinsi ......">
<option></option>
{% for provinsi in provinsis %}
<option value="{{provinsi[0]}}">{{provinsi[1]}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-12">
<div class="input-group">
<!-- <div class="input-group-prepend">
<span class="input-group-text" style="width: 150px;">
Kabupaten/Kota
</span>
</div> -->
<select class="form-control select2" name="kabkotaDropdown" id="kabkotaDropdown"
data-placeholder="Kabupaten/Kota ....." >
<option></option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-12">
<div class="input-group">
<!-- <div class="input-group-prepend">
<span class="input-group-text" style="width: 150px;">
Kecamatan
</span>
</div> -->
<select class="form-control select2" name="kecamatanDropdown" id="kecamatanDropdown"
data-placeholder="Kecamatan .....">
<option></option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
</div>
</div>
</div>
<!-- <div class="row">
<div class="col-md-12">
<canvas id="canvas" style="width=100%"></canvas>
</div> -->
</div>
<!-- <canvas id="myChart" style="width:80%;max-width:400px; margin-left: 20px;"></canvas> -->
</div>
</div>
</div>
</div>
</div>
<script src="{{ url_for('static', filename='script.js')}}"></script>
<script src="{{ url_for('static', filename='js/jquery-3.7.1.js')}}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/select2.min.js')}}"></script>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// const map = L.map('map').setView([4.2, 96.9], 7);
const indonesiaBounds = L.latLngBounds(
L.latLng(-11, 94), // Southwest corner (approx Sabang - Rote)
L.latLng(6.5, 141) // Northeast corner (approx Papua)
);
const map = L.map('map', {
center: [-2, 118], // Pusat Indonesia
// zoom: 5,
maxBounds: indonesiaBounds,
maxBoundsViscosity: 1.0,
zoomSnap: 0.5,
zoomDelta: 0.5
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap',
maxZoom: 12
}).addTo(map);
map.fitBounds(indonesiaBounds);
const optimalZoom = map.getZoom();
map.setMinZoom(optimalZoom);
</script>
<script>
const baseUrl = "{{ base_url }}";
let currentLayer = null;
let currentState = {
level: null,
kode: null
};
function loadLayer(url, onClickCallback, level = 'provinsi') {
currentLevel = level;
fetch(url)
.then(res => res.json())
.then(data => {
// 1. Fungsi validasi dan pembersih
function isValidCoord(coord) {
return Array.isArray(coord) &&
coord.length === 2 &&
typeof coord[0] === "number" &&
typeof coord[1] === "number" &&
!isNaN(coord[0]) &&
!isNaN(coord[1]);
}
function cleanCoordinates(multiPolygon) {
return multiPolygon.map(polygon =>
polygon.map(ring =>
ring.filter(coord => isValidCoord(coord))
).filter(ring => ring.length >= 4) // valid ring minimal 4 titik
).filter(polygon => polygon.length > 0);
}
// 2. Bersihkan data sebelum digunakan
data.features.forEach(feature => {
if (feature.geometry.type === "MultiPolygon") {
feature.geometry.coordinates = cleanCoordinates(feature.geometry.coordinates);
}
});
if (currentLayer) {
map.removeLayer(currentLayer);
}
currentLayer = L.geoJSON(data, {
style: function (feature) {
return {
color: "white",
weight: 1,
//dashArray: '5, 10',
opacity: 1,
fillOpacity: 0.4,
fillColor: '#32CD32'
};
},
onEachFeature: function (feature, layer) {
let clickTimer = null;
layer.on('click', async function (e) {
let kode = feature.properties.id;
// onClickCallback(kode);
if (clickTimer) {
// Double click detected
clearTimeout(clickTimer);
clickTimer = null;
// Aksi double click → Pindah layer
let kode = feature.properties.id;
onClickCallback(kode);
if (url.includes("/provinsi")) {
const provinsiId = feature.properties.id;
localStorage.setItem('kode_provinsi', provinsiId);
updateDropdown('provinsi',kode)
} else if (currentLevel === 'kabupatenkota') {
let province_id = localStorage.getItem('kode_provinsi')
localStorage.setItem('kode_kabupatenkota',feature.properties.id)
updateDropdown('kabupatenkota',kode)
}else if(currentLevel === 'kecamatan'){
localStorage.setItem('kode_kecamatan',feature.properties.id)
updateDropdown('kabupatenkota',kode)
}
} else {
// Single click → Tampilkan popup
clickTimer = setTimeout(async () => {
clickTimer = null;
if (url.includes("/provinsi")) {
localStorage.setItem('kode_provinsi', feature.properties.kode)
const status = await fetchStatusDesaByProvinsi(feature.properties.kode);
let klasifikasiHTML = "<li>Tidak ada data</li>";
if (Array.isArray(status?.[0])) {
provIndexDesaHTML = status[0]
.map(d => `${d[1]}: ${d[4]} / `)
.join("");
provBumdesHTML = status[1]
.map(dt => `${dt[0]}:${dt[1]} / `)
.join("");
const raw = Number(status[5]);
provDanaTotalHTML = `Total : ${formatWithUnit(raw)}`;
provDanadesaHTML = `Total : ${status[2].jumlah_per_m}, Persentase : ${status[2].persentage}%`;
provKoperasiHTML = status[4]
.map(dt => `${dt[0]}: ${dt[1]} / `)
.join("");
}
const popupContent = `
<strong>${feature.properties.nama}</strong><br/>
<strong>Status Desa:</strong>
<li>IDM - ${provIndexDesaHTML}</li>
<li>BUM - ${provBumdesHTML}</li>
<li>DD - ${provDanaTotalHTML}</li>
<li>SERAPAN - ${provDanadesaHTML} </li>
<li>KOPERASI - ${provKoperasiHTML} </li>
`;
layer.bindPopup(popupContent, {className: 'custom-popup'}).openPopup(e.latlng);
} else if (currentLevel === 'kabupatenkota') {
const province_code = localStorage.getItem('kode_provinsi');
localStorage.setItem('kode_kabupatenkota',feature.properties.kode)
const status = await fetchStatusDesaByKabupatenkota(province_code, feature.properties.kode);
let klasifikasiHTML = "<li>Tidak ada data</li>";
if (Array.isArray(status?.[0])) {
kabindexDesaHTML= status[0]
.map(d => `${d[1]}: ${d[5]} / `)
.join("");
kabbumdesHTML = status[1]
.map(dt => `${dt[0]}:${dt[1]} / `)
.join("");
const raw = Number(status[5]);
kabdanaTotalHTML = `Total : ${formatWithUnit(raw)}`;
kabdanadesaHTML = `Dana :${status[2].jumlah_per_m}, Persentase : ${status[2].persentage}%`;
kabserapanHTML = status[3]
.map(([jabatan, nilai]) => {
const alias = jabatan === 'Pendamping Lokal Desa' ? 'PLD' :
jabatan === 'Pendamping Desa' ? 'PD' :
jabatan;
return `${alias}: ${nilai} /`;
}).join("");
kabkoperasiHTML = status[4]
.map(dt => `${dt[0]}: ${dt[1]} / `)
.join("");
}
const popupContent = `
<strong>${feature.properties.nama}</strong><br/>
<strong>Status Desa (Kabupaten):</strong>
<li>IDM - ${kabindexDesaHTML}</li>
<li>BUM - ${kabbumdesHTML}</li>
<li>DD - ${kabdanaTotalHTML}</li>
<li>SERAPAN - ${kabdanadesaHTML} </li>
<li>KOPERASI - ${kabkoperasiHTML} </li>
`;
layer.bindPopup(popupContent, {className:'custom-popup'}).openPopup(e.latlng);
} else if (currentLevel === 'kecamatan'){
const province_code = localStorage.getItem('kode_provinsi')
const region_code = localStorage.getItem('kode_kabupatenkota')
localStorage.setItem('kode_kecamatan',feature.properties.id)
const status = await fetchStatusDesaByKecamatan(province_code, region_code, feature.properties.kode)
let klasifikasiHTML = "<li>Tidak ada data</li>";
if (Array.isArray(status?.[0])) {
kecindexDesaHTML = status[0]
.map(d => `${d[1]}: ${d[6]} / `)
.join("");
kecbumdesHTML = status[1]
.map(dt => `${dt[0]}:${dt[1]} / `)
.join("");
const raw = Number(status[5]);
kecdanaTotalHTML = `Total : ${formatWithUnit(raw)}`;
kecdanadesaHTML = `Total: ${formatWithUnit(status[2][0])} / Persen: ${Math.round(status[2][1])}`;
kecserapanHTML = status[3]
.map(([jabatan, nilai]) => {
const alias = jabatan === 'Pendamping Lokal Desa' ? 'PLD' :
jabatan === 'Pendamping Desa' ? 'PD' :
jabatan;
return `${alias}: ${nilai} /`;
}).join("");
keckoperasiHTML = status[4]
.map(dt => `${dt[0]}: ${dt[1]} / `)
.join("");
}
const popupContent =
`
<strong> ${feature.properties.nama}</strong>
<strong>Status Desa (Kecamatan):</strong>
<li>IDM - ${kecindexDesaHTML}</li>
<li>BUM - ${kecbumdesHTML}</li>
<li>DD - ${kecdanaTotalHTML}</li>
<li>SERAPAN - ${kecdanadesaHTML} </li>
<li>KOPERASI - ${keckoperasiHTML} </li>
`
layer.bindPopup(popupContent, {className:'custom-popup'}).openPopup(e.latlng);
}else {
// Desa
const province_code = localStorage.getItem('kode_provinsi')
const region_code = localStorage.getItem('kode_kabupatenkota')
const district_code = localStorage.getItem('kode_kecamatan')
console.log(province_code, region_code , district_code, feature.properties.kode)
const status = await fetchStatusDesaByDesa(province_code, region_code , district_code, feature.properties.kode);
let klasifikasiHTML = "<li>Tidak ada data</li>";
if (Array.isArray(status?.[0])) {
indexDesaHTML = status[0]
.map(d => `${d[1]}`)
.join("");
bumdesHTML = status[1]
.map(dt => `${dt[0]}:${dt[1]} / `)
.join("");
const raw = Number(status[5]);
danaTotalHTML = `Total : ${formatWithUnit(raw)}`;
danadesaHTML = status[2].map(([serapan,persen]) => {
return `Nominal - ${formatWithUnit(serapan)} / Persen - ${Math.round(persen)}%`;
});
serapanHTML = status[3]
.map(([jabatan, nilai]) => {
const alias = jabatan === 'Pendamping Lokal Desa' ? 'PLD' :
jabatan === 'Pendamping Desa' ? 'PD' :
jabatan;
return `${alias}: ${nilai} /`;
}).join("");
koperasiHTML = status[4]
.map(dt => `${dt[0]}: ${dt[1]} / `)
.join("");
}
const popupContent = `
<strong>${feature.properties.nama}</strong><br/>
<strong>Status Desa (Desa):</strong>
<li>IDM - ${indexDesaHTML}</li>
<li>BUM - ${bumdesHTML}</li>
<li>DD - ${danaTotalHTML}</li>
<li>SERAPAN - ${danadesaHTML} </li>
<li>KOPERASI - ${koperasiHTML} </li>
`;
layer.bindPopup(popupContent,{className:'custom-popup'}).openPopup(e.latlng);
}
}, 250);
layer.bindPopup(feature.properties.nama, {className:'custom-popup'});
}
console.log(currentLevel)
});
layer.bindPopup(feature.properties.nama, {className: 'custom-popup'});
}
}).addTo(map);
map.fitBounds(currentLayer.getBounds());
setTimeout(() => {
map.invalidateSize();
}, 200);
});
}
function formatWithUnit(value) {
const abs = Math.abs(value);
let scaled, unit;
if (abs >= 1e12) { scaled = value / 1e12; unit = 'Triliun'; }
else if (abs >= 1e9) { scaled = value / 1e9; unit = 'Miliar'; }
else if (abs >= 1e6) { scaled = value / 1e6; unit = 'Juta'; }
else if (abs >= 1e3) { scaled = value / 1e3; unit = 'Ribu'; }
else { scaled = value; unit = ''; }
const formatted = scaled.toLocaleString('id-ID', {
minimumFractionDigits: unit ? 2 : 0,
maximumFractionDigits: unit ? 2 : 0
});
return unit
? `${formatted} ${unit}`
: formatted;
}
async function fetchStatusDesaByProvinsi(kodeProvinsi) {
const url = `${baseUrl}/api/status-provinsi/${kodeProvinsi}`;
const urltdd = `${baseUrl}/api/status/danadesa/provinsi/${kodeProvinsi}`;
const urldd = `${baseUrl}/api/provinsi/serapan/${kodeProvinsi}`;
const urlpd = `${baseUrl}/api/provinsi/pendamping/${kodeProvinsi}`
const urlkop = `${baseUrl}/api/provinsi/koperasi/${kodeProvinsi}`
const urlbd = `${baseUrl}/api/provinsi/bumdes/${kodeProvinsi}`;
try {
const res = await fetch(url);
const tdd = await fetch(urltdd)
const bumdes = await fetch(urlbd)
const dd = await fetch(urldd)
const pd = await fetch(urlpd)
const kop = await fetch(urlkop)
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
const IPD = await res.json()
const dtdd = await tdd.json()
const bd = await bumdes.json()
const danadesa = await dd.json()
const dtpd = await pd.json()
const dtkop = await kop.json()
console.log([IPD, bd, danadesa, dtpd, dtkop, dtdd]);
return [IPD, bd, danadesa, dtpd, dtkop, dtdd];
} catch (err) {
console.error("Gagal ambil status desa:", err);
return null;
}
}
async function fetchStatusDesaByKabupatenkota(kode_prov, kode_kabkota) {
const url = `${baseUrl}/api/status-kabupatenkota/${kode_prov}/${kode_kabkota}`
const urltdd = `${baseUrl}/api/status/danadesa/kabkota/${kode_kabkota}`;
const urldd = `${baseUrl}/api/kabkota/serapan/${kode_kabkota}`;
const urlpd = `${baseUrl}/api/kabkota/pendamping/${kode_kabkota}`
const urlkop = `${baseUrl}/api/kabkota/koperasi/${kode_kabkota}`
const urlbd = `${baseUrl}/api/kabkota/bumdes/${kode_kabkota}`;
try{
const res = await fetch(url)
const tdd = await fetch(urltdd)
const bumdes = await fetch(urlbd)
const dd = await fetch(urldd)
const pd = await fetch(urlpd)
const kop = await fetch(urlkop)
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
const IPD = await res.json()
const bd = await bumdes.json()
const danadesa = await dd.json()
const dtpd = await pd.json()
const dtkop = await kop.json()
const dttd = await tdd.json()
return [IPD,bd, danadesa, dtpd, dtkop,dttd];
}catch(err){
console.log(err)
return null;
}
}
async function fetchStatusDesaByKecamatan(province_code, region_code, district_code){
const url = `${baseUrl}/api/status-kecamatan/${province_code}/${region_code}/${district_code}`
const urltdd = `${baseUrl}/api/status/danadesa/kecamatan/${district_code}`;
const urldd = `${baseUrl}/api/kecamatan/serapan/${district_code}`;
const urlpd = `${baseUrl}/api/kecamatan/pendamping/${district_code}`
const urlkop = `${baseUrl}/api/kecamatan/koperasi/${district_code}`
const urlbd = `${baseUrl}/api/kecamatan/bumdes/${district_code}`;
try {
const res = await fetch(url)
const tdd = await fetch(urltdd)
const bumdes = await fetch(urlbd)
const dd = await fetch(urldd)
const pd = await fetch(urlpd)
const kop = await fetch(urlkop)
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
const IPD = await res.json()
const bd = await bumdes.json()
const danadesa = await dd.json()
const dtpd = await pd.json()
const dtkop = await kop.json()
const dttd = await tdd.json()
return [IPD,bd, danadesa, dtpd, dtkop, dttd];;
} catch (error) {
console.log(error)
return null
}
}
async function fetchStatusDesaByDesa(province_code, region_code, district_code, village_code){
const url = `${baseUrl}/api/desa/status/${province_code}/${region_code}/${district_code}/${village_code}`
const urltdd = `${baseUrl}/api/status/danadesa/desa/${village_code}`;
const urldd = `${baseUrl}/api/desa/serapan/${village_code}`;
const urlpd = `${baseUrl}/api/desa/pendamping/${village_code}`
const urlkop = `${baseUrl}/api/desa/koperasi/${village_code}`
const urlbd = `${baseUrl}/api/desa/bumdes/${village_code}`;
try {
const res = await fetch(url)
const tdd = await fetch(urltdd)
const bumdes = await fetch(urlbd)
const dd = await fetch(urldd)
const pd = await fetch(urlpd)
const kop = await fetch(urlkop)
if (!res.ok && !bumdes.ok && !dd.ok) throw new Error(`HTTP ${res.status}`);
const IPD = await res.json()
const bd = await bumdes.json()
const danadesa = await dd.json()
const dtpd = await pd.json()
const dtkop = await kop.json()
const dttd = await tdd.json()
return [IPD,bd, danadesa, dtpd, dtkop, dttd];;
} catch (error) {
console.log(error)
return null
}
}
// Load provinsi Aceh awal
loadLayer(`${baseUrl}/geojson/provinsi`, function (kode_provinsi) {
loadLayer(`${baseUrl}/geojson/kabupaten/${kode_provinsi}`, function (kode_kabupaten) {
loadLayer(`${baseUrl}/geojson/kecamatan/${kode_kabupaten}`, function (kode_kecamatan) {
loadLayer(`${baseUrl}/geojson/desa/${kode_kecamatan}`, function () {
// Desa tidak turun level lagi
}, 'desa');
}, 'kecamatan');
}, 'kabupatenkota');
}, 'provinsi');
function goToLevel(level) {
const prov = localStorage.getItem('kode_provinsi');
const kab = localStorage.getItem('kode_kabupatenkota');
const kec = localStorage.getItem('kode_kecamatan');
switch (level) {
case 'provinsi':
loadLayer(`${baseUrl}/geojson/provinsi`, () => {}, 'provinsi');
break;
case 'kabupatenkota':
loadLayer(`${baseUrl}/geojson/kabupaten/${prov}`, () => {}, 'kabupatenkota');
break;
case 'kecamatan':
loadLayer(`${baseUrl}/geojson/kecamatan/${kab}`, () => {}, 'kecamatan');
break;
}
}
$('#provinsiDropdown').on('change', function (e) {
const kodeProvinsi = $(this).val();
console.log("Provinsi dipilih:", kodeProvinsi);
if (!kodeProvinsi) {
console.warn("Tidak ada kode provinsi yang dipilih!");
return;
}
localStorage.setItem('kode_provinsi', kodeProvinsi);
$('#kabkotaDropdown').empty().trigger('change');
// Ambil kabupaten berdasarkan provinsi
const kabkotaURL = "{{ url_for('main.get_master_kabkota') }}";
$.ajax({
url: kabkotaURL,
data: { provinsi_id: kodeProvinsi },
dataType: 'json',
success: function (data) {
const results = data.map(kabupaten => ({
id: kabupaten[0],
text: kabupaten[1]
}));
// Tambahkan ke dropdown kabupaten
$('#kabkotaDropdown').select2({
data: results,
placeholder: 'Pilih Kabupaten/Kota',
allowClear: true
});
}
});
console.log(`Memuat kabupaten dari /geojson/kabupaten/${kodeProvinsi}`);
loadLayer(`${baseUrl}/geojson/kabupaten/${kodeProvinsi}`, () => {
console.log("Layer kabupaten dimuat.");
}, 'kabupatenkota');
});
$('#kabkotaDropdown').on('change', function (e) {
const kodeKabupaten = $(this).val();
if (!kodeKabupaten) {
console.warn("Tidak ada kode provinsi yang dipilih!");
return;
}
localStorage.setItem('kode_kabupatenkota', kodeKabupaten);
$('#kecamatanDropdown').empty().trigger('change');
// Ambil kabupaten berdasarkan provinsi
const kabkotaURL = "{{ url_for('main.get_master_kecamatan') }}";
$.ajax({
url: kabkotaURL,
data: { kabkota_id: kodeKabupaten },
dataType: 'json',
success: function (data) {
const results = data.map(kecamatan => ({
id: kecamatan[0],
text: kecamatan[1]
}));
// Tambahkan ke dropdown kabupaten
$('#kecamatanDropdown').select2({
data: results,
placeholder: 'Pilih Kecamatan',
allowClear: true
});
}
});
loadLayer(`${baseUrl}/geojson/kecamatan/${kodeKabupaten}`, () => {}, 'kecamatan');
}).select2();
$('#kecamatanDropdown').on('change', function (e) {
const kodeKecamatan = $(this).val();
console.log(kodeKecamatan)
if (!kodeKecamatan) {
console.warn("Kode kecamatan kosong atau null.");
return;
}
localStorage.setItem('kode_kecamatan', kodeKecamatan);
loadLayer(`${baseUrl}/geojson/desa/${kodeKecamatan}`, () => {
console.log("desa dimuat")
}, 'desa');
});
</script>
<script>
const dropdownMap = {
provinsi: '#provinsiDropdown',
kabupatenkota: '#kabkotaDropdown',
kecamatan: '#kecamatanDropdown'
};
const apiURLMap = {
provinsi: "{{ url_for('main.get_master_kabkota') }}",
kabupatenkota: "{{ url_for('main.get_master_kecamatan') }}"
};
const dataKeyMap = {
provinsi: 'provinsi_id',
kabupatenkota: 'kabkota_id'
};
function getNextLevel(level) {
const order = ['provinsi', 'kabupatenkota', 'kecamatan'];
const index = order.indexOf(level);
return order[index + 1];
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function updateDropdown(level, kode,autoSelectKodeNext = null) {
const dropdownId = dropdownMap[level];
if (!dropdownId || !$(dropdownId).length) return;
// Set value dan trigger select2
$(dropdownId).val(kode).trigger('change.select2');
console.log(dropdownId,kode);
// Ambil level berikutnya
const nextLevel = getNextLevel(level);
const targetDropdownId = dropdownMap[nextLevel];
// Kalau ada level berikutnya, ambil datanya via AJAX
if (nextLevel && apiURLMap[level]) {
const targetDropdownId = dropdownMap[getNextLevel(level)];
const apiURL = apiURLMap[level];
const paramKey = dataKeyMap[level];
const paramVal = $(dropdownId).val();
$.ajax({
url: apiURL,
data: { [paramKey]: paramVal },
dataType: 'json',
success: function (data) {
const results = data.map(item => ({
id: item[0],
text: item[1]
}));
$(targetDropdownId).empty().select2({
data: results,
placeholder: `Pilih ${capitalize(getNextLevel(level))}`,
allowClear: true
});
}
});
if (autoSelectKodeNext) {
$(targetDropdownId).val(autoSelectKodeNext).trigger('change.select2');
}
}
}
$(document).ready(function () {
console.log("ready for fetching data")
const provinsiURL = "{{ url_for('main.get_master_provinsi') }}";
$('#kabkotaDropdown').empty().trigger('change');
$('#provinsiDropdown').select2({
placeholder: 'Pilih Provinsi',
allowClear: true,
//ajax: {
// url: '',//provinsiURL,
// dataType: 'json',
// delay: 250,
// data: function (params) {
// return {
// q: params.term
// };
// },
// processResults: function (data) {
// return {
// results: data.map(provinsi => ({
// id: provinsi[0],
// text: provinsi[1]
// }))
// };
// },
// cache: true
//},
minimumInputLength: 0
});
});
</script>
<script>
document.addEventListener("DOMContentLoaded", (event) => {
$( '.select2' ).select2( {
theme: 'bootstrap-4'
} );
//let total_dd_container = document.getElementById('tot_dd')
fetchTotDana(`${baseUrl}/api/desa/total-dana-desa`)
fethTotSerapan(`${baseUrl}/api/desa/total-serapan-dana`)
function fetchTotDana(url){
fetch(url)
.then(res => res.json())
.then(data => {
if(typeof (data) == 'object'){
//total_dd_container.textContent = parseDanBulatkanKeMiliar(data.jumlah_per_m)
}else{
//total_dd_container.textContent = parseDanBulatkanKeMiliar(data)
}
})
}
function fethTotSerapan(url){
fetch(url)
.then(res => res.json())
.then(data => {
if(data){
console.log("fetch serapan:", data)
//document.getElementById('tot_sr').textContent = parseDanBulatkanKeMiliar(data['serapan_per_m'])
//document.getElementById('pr_sr').textContent = data['persentage'] + "%"
}
})
}
function parseDanBulatkanKeMiliar(input) {
// 1. Bersihkan input: hapus "Rp", ".", ganti koma dengan titik
let cleaned = input
.replace(/Rp/g, "")
.replace(/\./g, "")
.replace(",", ".");
// 2. Konversi ke angka
let angka = parseFloat(cleaned);
// 3. Bulatkan ke satuan miliar
let hasilBulat = Math.round(angka / 1e9);
// 4. Tambahkan format "x Miliar"
return "Rp" + hasilBulat.toLocaleString("id-ID") + " M";
}
})
</script>
<!-- Chart Script -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var getRandomDataArray = function () {
var dataArray = [];
for (var i = 0; i < 7; i++) dataArray.push(Math.round(Math.random() * 100));
return dataArray;
}
function getColorByStatus(value) {
return value > 15 ? '#006400' : // dark green
value > 12 ? '#32CD32' : // lime green
value > 10 ? '#ADFF2F' : // green-yellow
value > 8 ? '#FFFF00' : // yellow
value > 5 ? '#FFA500' : // orange
'#44704BFF'; // red
}
function getColorByValue(val) {
return val > 200 ? '#18D814' :
val > 100 ? '#50AF1C' :
val > 60 ? '#888523' :
val > 10 ? '#C05C2B' :
'#F73232';
}
window.onload = function(){
var chartOptions = { responsive : true };
var chartData = {
labels : ["January","February","March","April","May","June","July"],
datasets : [
{
fillColor : "#ffa500",
strokeColor : "rgba(220,220,220,0.8)",
highlightFill: "rgba(220,220,220,0.75)",
highlightStroke: "rgba(220,220,220,1)",
data : getRandomDataArray()
},
{
fillColor : "rgba(151,187,205,0.5)",
strokeColor : "rgba(151,187,205,0.8)",
highlightFill : "rgba(151,187,205,0.75)",
highlightStroke : "rgba(151,187,205,1)",
data : getRandomDataArray()
}
]
}
//var chart = document.getElementById("canvas").getContext("2d");
//window.myBar = new Chart(chart, {
// type: "bar", // <- gunakan type di sini, bukan .Bar()
// data: chartData,
// options: chartOptions
//});
}
</script>
</body>
</html>