|
6 | 6 | <p class="text-blue-100">Marker berdasarkan jumlah anggota per kecamatan.</p> |
7 | 7 | </div> |
8 | 8 | </div> |
| 9 | + <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6"> |
| 10 | + <div class="bg-white p-4 rounded-lg shadow-md border border-gray-200"> |
| 11 | + <div class="grid grid-cols-1 md:grid-cols-3 gap-4 items-center"> |
| 12 | + |
| 13 | + <div class="md:col-span-1"> |
| 14 | + <label for="filter-komisariat" class="block text-sm font-medium text-gray-700">Filter Komisariat</label> |
| 15 | + <select id="filter-komisariat" wire:model.live="selectedKomisariat" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 sm:text-sm rounded-md"> |
| 16 | + <option value="">Semua Komisariat</option> |
| 17 | + @foreach($this->komisariatOptions as $id => $nama) |
| 18 | + <option value="{{ $id }}">{{ $nama }}</option> |
| 19 | + @endforeach |
| 20 | + </select> |
| 21 | + </div> |
| 22 | + |
| 23 | + <div class="md:col-span-1"> |
| 24 | + <label for="filter-jurusan" class="block text-sm font-medium text-gray-700">Filter Jurusan</label> |
| 25 | + <select id="filter-jurusan" wire:model.live="selectedJurusan" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 sm:text-sm rounded-md"> |
| 26 | + <option value="">Semua Jurusan</option> |
| 27 | + @foreach($this->jurusanOptions as $id => $nama) |
| 28 | + <option value="{{ $id }}">{{ $nama }}</option> |
| 29 | + @endforeach |
| 30 | + </select> |
| 31 | + </div> |
9 | 32 |
|
| 33 | + <div class="md:col-span-1 text-center md:text-right text-gray-600"> |
| 34 | + <p class="text-sm">Menampilkan <span class="font-bold text-emerald-700">{{ $markerCount }}</span> marker</p> |
| 35 | + </div> |
| 36 | + </div> |
| 37 | + </div> |
| 38 | + </div> |
10 | 39 | <!-- Map Section --> |
11 | 40 | <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-10"> |
12 | | - <div id="map" class="w-full h-[500px] rounded-lg shadow-md"></div> |
| 41 | + <div wire:ignore id="map" class="w-full h-[500px] rounded-lg shadow-md"></div> |
13 | 42 | </div> |
14 | 43 | </div> |
15 | 44 |
|
16 | 45 | <script> |
17 | | - const kecamatanData = @json($kecamatanData); |
18 | | -
|
19 | | - function initMap() { |
20 | | - // Titik tengah default (Pontianak) |
21 | | - const centerLocation = { lat: -0.026330, lng: 109.342503 }; |
| 46 | + document.addEventListener('livewire:navigated', () => { |
| 47 | + |
| 48 | + let map = null; |
| 49 | + let activeMarkers = []; |
| 50 | + const defaultAvatar = "{{ asset('images/default-avatar.png') }}"; |
| 51 | + |
| 52 | + const abortController = new AbortController(); |
22 | 53 |
|
23 | | - const map = new google.maps.Map(document.getElementById("map"), { |
24 | | - zoom: 12, |
25 | | - center: centerLocation, |
26 | | - }); |
| 54 | + document.addEventListener('livewire:navigating', () => { |
| 55 | + |
| 56 | + abortController.abort(); |
| 57 | + |
| 58 | + map = null; |
| 59 | + }, { once: true }); |
27 | 60 |
|
28 | | - if (!kecamatanData.length) { |
29 | | - console.warn("Tidak ada data kecamatan"); |
30 | | - return; |
| 61 | + function clearMarkers() { |
| 62 | + activeMarkers.forEach(marker => marker.setMap(null)); |
| 63 | + activeMarkers = []; |
31 | 64 | } |
32 | 65 |
|
33 | | - kecamatanData.forEach(item => { |
34 | | - const lat = parseFloat(item.latitude); |
35 | | - const lng = parseFloat(item.longitude); |
| 66 | + function drawMarkers(anggotaData) { |
| 67 | + if (!map) return; |
| 68 | + clearMarkers(); |
36 | 69 |
|
37 | | - if (isNaN(lat) || isNaN(lng)) return; |
| 70 | + const infowindow = new google.maps.InfoWindow(); |
38 | 71 |
|
39 | | - const marker = new google.maps.Marker({ |
40 | | - position: { lat, lng }, |
41 | | - map, |
42 | | - title: item.kecamatan |
43 | | - }); |
| 72 | + anggotaData.forEach(anggota => { |
| 73 | + const lat = parseFloat(anggota.latitude); |
| 74 | + const lng = parseFloat(anggota.longitude); |
| 75 | + if (isNaN(lat) || isNaN(lng)) return; |
| 76 | +
|
| 77 | + const marker = new google.maps.Marker({ |
| 78 | + position: { lat, lng }, |
| 79 | + map, |
| 80 | + title: anggota.nama |
| 81 | + }); |
| 82 | + activeMarkers.push(marker); |
44 | 83 |
|
45 | | - const infoWindow = new google.maps.InfoWindow({ |
46 | | - content: ` |
47 | | - <div> |
48 | | - <strong>Kecamatan:</strong> ${item.kecamatan} <br> |
49 | | - <strong>Jumlah Anggota:</strong> ${item.jumlah} |
| 84 | + const contentString = ` |
| 85 | + <div style="display: flex; align-items: center; gap: 15px; color: black; max-width: 350px;"> |
| 86 | + <img src="${anggota.foto ? '/storage/' + anggota.foto : defaultAvatar}" alt="${anggota.nama}" style="width: 80px; height: 80px; object-fit: cover; border-radius: 50%;"> |
| 87 | + <div> |
| 88 | + <strong style="font-size: 1.1em;">${anggota.nama}</strong><br> |
| 89 | + <strong>Kuliah:</strong> ${anggota.tahun_masuk_kuliah || 'N/A'}<br> |
| 90 | + <strong>LK1:</strong> ${anggota.tahun_lk1 || 'N/A'}<br> |
| 91 | + <strong>Jurusan:</strong> ${anggota.jurusan ? anggota.jurusan.nama_jurusan : 'N/A'}<br> |
| 92 | + <strong>Komisariat:</strong> ${anggota.komisariat ? anggota.komisariat.nama : 'N/A'} |
| 93 | + </div> |
50 | 94 | </div> |
51 | | - ` |
| 95 | + `; |
| 96 | +
|
| 97 | + marker.addListener('click', () => { |
| 98 | + infowindow.setContent(contentString); |
| 99 | + infowindow.open(map, marker); |
| 100 | + }); |
52 | 101 | }); |
| 102 | + } |
53 | 103 |
|
54 | | - marker.addListener('click', () => infoWindow.open(map, marker)); |
55 | | - }); |
56 | | - } |
| 104 | + function initialize() { |
| 105 | + const mapElement = document.getElementById("map"); |
| 106 | + if (!mapElement || map) return; |
| 107 | +
|
| 108 | + const centerLocation = { lat: -0.026330, lng: 109.342503 }; |
| 109 | + map = new google.maps.Map(mapElement, { |
| 110 | + zoom: 12, |
| 111 | + center: centerLocation, |
| 112 | + }); |
| 113 | +
|
| 114 | + Livewire.on('updateMap', ({ data }) => { |
| 115 | + drawMarkers(data); |
| 116 | + }, { signal: abortController.signal }); |
| 117 | +
|
| 118 | + @this.call('triggerRender'); |
| 119 | + } |
| 120 | +
|
| 121 | + if (typeof google === 'object' && typeof google.maps === 'object') { |
| 122 | + initialize(); |
| 123 | + } else { |
| 124 | + window.addEventListener('google-maps-loaded', initialize, { once: true }); |
| 125 | + } |
| 126 | + }); |
57 | 127 | </script> |
58 | 128 |
|
59 | | -<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAgGBjlEnlrlO2KdsQMFL70E_Ppo3GmFPs&callback=initMap&v=weeklyy" async defer></script> |
| 129 | +<script> |
| 130 | + function initAllMaps() { |
| 131 | + window.dispatchEvent(new CustomEvent('google-maps-loaded')); |
| 132 | + } |
| 133 | +</script> |
| 134 | +<script src="https://maps.googleapis.com/maps/api/js?key={{ env('GOOGLE_MAPS_API_KEY') }}&callback=initAllMaps&v=weekly" async defer></script> |
0 commit comments