ระบบโทรมาตร DWR+RID

ลุ่มน้ำนครศรีธรรมราช

📡 เรดาร์เมืองคอน 70%

ระบบโทรมาตร DWR+RID (แชตบอท)

ลุ่มน้ำนครศรีธรรมราช

📡เรดาร์เมืองคอน 70%
// 📍 คัดลอกท่อนนี้ไปวางแทนที่ช่องตัวแปร stations เดิมในไฟล์โค้ดของคุณได้เลยครับ const stations = [ { code: "TNA01", name: "ฝายบ้านตาล", lat: 8.430936, lng: 99.879033, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/NAKORN/TNA01/image.jpg" }, { code: "TNA02", name: "คลองวัดหญ้า", lat: 8.476894, lng: 99.924250, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/NAKORN/TNA02/image.jpg" }, { code: "TNB03", name: "ฝายท่าดี", lat: 8.391047, lng: 99.864547, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/NAKORN/TNB07/image.jpg" }, { code: "TNB12", name: "บ้านปากพญา", lat: 8.483189, lng: 100.015408, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/NAKORN/TNB12/image.jpg" }, { code: "TNB13", name: "บ้านหนองลุง", lat: 8.376106, lng: 99.878564, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/NAKORN/TNB13/image.jpg" }, { code: "TNB15", name: "คลองท่าเรือ", lat: 8.357911, lng: 99.980492, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/NAKORN/TNB15/image.jpg" }, { code: "STN1", name: "ปตร.แพรกเมือง", lat: 8.017673, lng: 100.300883, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/PAKPHANANG/ST16/image.jpg" }, { code: "TTP01", name: "บ้านต้นโพธิ์", lat: 8.50845, lng: 99.5108, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/TAPI/TTP01/image.jpg" }, { code: "TTP03", name: "บ้านวังตลับ", lat: 8.39809, lng: 99.3452, img: "https://images.weserv.nl/?url=119.110.213.190/PPPCCTV/TAPI/TTP03/image.jpg" }, // กลุ่มสถานีจากกรมทรัพยากรน้ำ เปลี่ยนโปรโตคอลนำหน้าจาก http เป็น https ให้ตรงกับระบบรักษาความปลอดภัยของบราว์เซอร์ { code: "TC191705", name: "สะพานปากน้ำสิชล", lat: 9.00878, lng: 99.89003, img: "https://tele-nakhonsri.dwr.go.th/image/TC191705/CCTV_image/Staff_1.jpg" }, { code: "TC191802", name: "สะพานบ้านโรงเหล็ก", lat: 8.73099, lng: 99.74612, img: "https://tele-nakhonsri.dwr.go.th/image/TC191802/CCTV_image/Staff_1.jpg" }, { code: "TC191001", name: "แม่น้ำตาปี ตลาดฉวาง", lat: 8.42911, lng: 99.50842, img: "https://tele-nakhonsri.dwr.go.th/image/TC191001/CCTV_image/Staff_1.jpg" }, { code: "TC191913", name: "สะพานคีรีวง", lat: 8.43248, lng: 99.78259, img: "https://tele-nakhonsri.dwr.go.th/image/TC191913/CCTV_image/Staff_1.jpg" }, { code: "TC191911", name: "สะพานวัดท่าแพ", lat: 8.51459, lng: 99.95274, img: "https://tele-nakhonsri.dwr.go.th/image/TC191911/CCTV_image/Staff_1.jpg" }, { code: "TC191912", name: "สะพานคลองท่าวัง", lat: 8.44410, lng: 99.95959, img: "https://tele-nakhonsri.dwr.go.th/image/TC191912/CCTV_image/Staff_1.jpg" }, { code: "TC191918", name: "สะพานตลาดเชียรใหญ่", lat: 8.17389, lng: 100.14914, img: "https://tele-nakhonsri.dwr.go.th/image/TC191918/CCTV_image/Staff_1.jpg" } ]; let mapMain = null, currentPop = null, layerRadar = null; const ERROR_IMAGE = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='800' height='450' viewBox='0 0 800 450'%3E%3Crect width='800' height='450' fill='%231e293b'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%2394a3b8' font-size='24'%3Eไม่สามารถโหลดภาพ%3C/text%3E%3C/svg%3E"; function getImageUrl(originalUrl, isGif = false) { if (!originalUrl) return ''; const t = Date.now(); const urlWithTime = originalUrl + (originalUrl.includes('?') ? '&' : '?') + 't=' + t; if (isGif) return `https://wsrv.nl/?url=${encodeURIComponent(urlWithTime)}&n=-1`; return urlWithTime; } // 1. แสดงผลพิกัด (Lat, Lng) ลงใน Sidebar รายชื่อกล้อง function createStationList() { const container = document.getElementById('station-list'); if (!container) return; container.innerHTML = ''; stations.forEach(s => { const div = document.createElement('div'); div.className = 'glass border border-slate-600 rounded-3xl p-4 cursor-pointer hover:border-sky-400 transition-all'; div.innerHTML = `
${s.code}
${s.name}
📍 ${s.lat.toFixed(5)}, ${s.lng.toFixed(5)}
`; div.onclick = () => { if(mapMain) mapMain.flyTo([s.lat, s.lng], 16); }; container.appendChild(div); }); } function updateThaiTime() { const el = document.getElementById('thai-time'); if (!el) return; const now = new Date(); const thaiYear = now.getFullYear() + 543; const days = ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์']; const months = ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน','กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม']; el.innerHTML = `
${days[now.getDay()]} ${now.getDate()} ${months[now.getMonth()]} ${thaiYear}
${now.toLocaleTimeString('th-TH')}
`; } function showStationPopup(station, latlng) { if (!mapMain) return; if (currentPop) mapMain.closePopup(currentPop); const imgUrl = getImageUrl(station.img, false); const container = document.createElement('div'); container.className = 'custom-popup'; container.style.minWidth = '320px'; container.style.maxWidth = '480px'; container.innerHTML = `
${station.code}
${station.name}
✧ คลิกที่ภาพเพื่อดูขนาดเต็ม ✧
`; currentPop = L.popup({ maxWidth: 520, className: 'custom-popup', closeButton: true }) .setLatLng(latlng) .setContent(container) .openOn(mapMain); } // ฟังก์ชันสร้างแผนที่แบบปลอดภัย: มั่นใจชัวร์ว่าตัวแปรแผนที่จะพร้อมใช้งานและไม่ถูกแทรกแซง function initMap() { try { if (mapMain) { mapMain.remove(); } mapMain = L.map('map').setView([8.5, 99.9], 10); L.tileLayer('https://{s}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', { subdomains: ['mt0','mt1','mt2','mt3'], maxZoom: 19 }).addTo(mapMain); const radarBounds = [[7.5959, 98.6618], [9.69797, 100.6378]]; const radarUrl = getImageUrl('https://semet.uk/loop/NSTLoop.gif', true); layerRadar = L.imageOverlay(radarUrl, radarBounds, { opacity: 0.7 }).addTo(mapMain); const camIcon = L.icon({ iconUrl: 'https://i.ibb.co/4nSt8YfF/security-camera-64.png', iconSize: [42,42], iconAnchor: [21,42] }); stations.forEach(s => { L.marker([s.lat, s.lng], { icon: camIcon }).addTo(mapMain).on('click', (e) => showStationPopup(s, e.latlng)); }); setTimeout(() => { if(mapMain) mapMain.invalidateSize(); }, 400); } catch (err) { console.error("แผนที่เริ่มต้นผิดพลาด พยายามสร้างใหม่อีกครั้ง...", err); } } function switchLayer(n) { if(!mapMain) return; mapMain.eachLayer(l => { if(l instanceof L.TileLayer) mapMain.removeLayer(l); }); if(n===0) L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {maxZoom:17}).addTo(mapMain); else L.tileLayer('https://{s}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', {subdomains:['mt0','mt1','mt2','mt3'],maxZoom:19}).addTo(mapMain); document.getElementById('btn-osm')?.classList.toggle('active-layer', n===0); document.getElementById('btn-hybrid')?.classList.toggle('active-layer', n===1); } function openImageModal(station) { const codeEl = document.getElementById('modal-code'); const nameEl = document.getElementById('modal-name'); const imgEl = document.getElementById('modal-image'); if(codeEl && nameEl && imgEl) { codeEl.innerText = station.code; nameEl.innerText = station.name; imgEl.src = getImageUrl(station.img, false); document.getElementById('image-modal')?.classList.remove('hidden'); document.getElementById('image-modal')?.classList.add('flex'); } } function closeModal() { document.getElementById('image-modal')?.classList.add('hidden'); document.getElementById('image-modal')?.classList.remove('flex'); } function toggleFullscreenImage() { const imgEl = document.getElementById('modal-image'); if(!imgEl) return; const src = imgEl.src; const ov = document.createElement('div'); ov.className = 'fullscreen-overlay'; ov.id='fs-overlay'; ov.innerHTML = ``; document.body.appendChild(ov); } function toggleMultiview() { const m = document.getElementById('multiview-modal'); if(!m) return; m.classList.toggle('hidden'); m.classList.toggle('flex'); if(!m.classList.contains('hidden')) renderMultiview(); } function renderMultiview() { const grid = document.getElementById('multiview-grid'); if(!grid) return; grid.innerHTML = ''; stations.forEach(s => { const imgUrl = getImageUrl(s.img, false); const frame = document.createElement('div'); frame.className = 'camera-frame'; frame.setAttribute('data-target-id', s.code); frame.innerHTML = `
${s.code}
${s.name}
LIVE
`; grid.appendChild(frame); }); const timeEl = document.getElementById('multi-time'); if(timeEl) timeEl.innerText = new Date().toLocaleTimeString('th-TH'); } document.addEventListener('click', function(event) { const popupArea = event.target.closest('.popup-image'); if (popupArea) { event.stopPropagation(); const code = popupArea.getAttribute('data-target-id'); const match = stations.find(x => x.code === code); if (match) openImageModal(match); return; } const gridArea = event.target.closest('.camera-frame'); if (gridArea) { const code = gridArea.getAttribute('data-target-id'); const match = stations.find(x => x.code === code); if (match) { toggleMultiview(); setTimeout(() => openImageModal(match), 200); } return; } if (event.target.closest('.fullscreen-close') || event.target.id === 'fs-overlay') { document.getElementById('fs-overlay')?.remove(); return; } }); // ใช้การตรวจสอบความมีอยู่จริงก่อนผูก Event (Safe Listener Setup) เพื่อกัน Error พังระบบ function setupListeners() { document.getElementById('btn-osm')?.addEventListener('click', () => switchLayer(0)); document.getElementById('btn-hybrid')?.addEventListener('click', () => switchLayer(1)); document.getElementById('btn-toggle-multiview')?.addEventListener('click', toggleMultiview); document.getElementById('btn-toggle-sidebar')?.addEventListener('click', function() { const sb = document.getElementById('sidebar'); if(sb) { sb.style.width = sb.style.width === '0px' ? '288px' : '0px'; setTimeout(() => { if(mapMain) mapMain.invalidateSize(); }, 250); } }); document.getElementById('btn-refresh-multi')?.addEventListener('click', renderMultiview); document.getElementById('btn-close-multi')?.addEventListener('click', toggleMultiview); document.getElementById('btn-close-modal')?.addEventListener('click', closeModal); document.getElementById('modal-image')?.addEventListener('click', toggleFullscreenImage); document.getElementById('radar-toggle')?.addEventListener('change', e => { if(!mapMain || !layerRadar) return; e.target.checked ? layerRadar.addTo(mapMain) : mapMain.removeLayer(layerRadar); }); document.getElementById('radar-opacity')?.addEventListener('input', e => { if(layerRadar) layerRadar.setOpacity(e.target.value); const opVal = document.getElementById('opacity-value'); if(opVal) opVal.innerText = Math.round(e.target.value*100)+'%'; }); } // 🌟 ย้ายมาทำงานแบบอิสระ ไม่รอคิว DOM เพื่อไม่ให้โดนสคริปต์ของบอทสายฟ้าตัดคิวแย่งโหลด createStationList(); initMap(); updateThaiTime(); setupListeners(); setInterval(updateThaiTime, 1000); // เผื่อความชัวร์ ให้แผนที่คำนวณสัดส่วนซ้ำอีกครั้งเมื่อหน้าจอเบราว์เซอร์พร้อมทั้งหมด window.addEventListener('load', function() { if (mapMain) mapMain.invalidateSize(); }); document.addEventListener('keydown', e => { if(e.key === 'Escape') { document.getElementById('fs-overlay')?.remove(); closeModal(); if(currentPop && mapMain) mapMain.closePopup(currentPop); } });