290 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			290 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			HTML
		
	
	
	
| <!DOCTYPE html>
 | |
| <html lang="en">
 | |
| <head>
 | |
|     <meta charset="UTF-8">
 | |
|     <title>Korail GIS</title>
 | |
|     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
 | |
|     integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
 | |
|     crossorigin=""/>
 | |
|     <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
 | |
|     integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
 | |
|     crossorigin=""></script>
 | |
|     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | |
|     <style>
 | |
|     #map {
 | |
|         height: calc(100vh - 60px);
 | |
|         background-color: #e5e5e5;
 | |
|     }
 | |
|     
 | |
|     .station-label {
 | |
|         text-align: center;
 | |
|         font-weight: bold;
 | |
|         font-size: 15px;
 | |
|         color: black;     
 | |
|     }
 | |
| 
 | |
|     .train-marker {
 | |
|         text-align: center;
 | |
|     }
 | |
| 
 | |
|     .bottombar {
 | |
|         height: 40px;
 | |
|         display: flex;
 | |
|         justify-content: space-between;
 | |
|         align-items: center;
 | |
|         padding: 0 20px;
 | |
|     }
 | |
| 
 | |
|     .bottombar .left {
 | |
|         display: flex;
 | |
|         align-items: center;
 | |
|     }
 | |
| 
 | |
|     .bottombar .left input[type="checkbox"] {
 | |
|         margin-right: 10px;
 | |
|     }
 | |
| 
 | |
|     .bottombar .right {
 | |
|         display: flex;
 | |
|         align-items: center;
 | |
|     }
 | |
| 
 | |
|     .bottombar .loading {
 | |
|         margin-right: 15px;
 | |
|     }
 | |
| 
 | |
|     #reloadTrains {
 | |
|         padding: 5px 10px;
 | |
|         background-color: #007BFF;
 | |
|         color: white;
 | |
|         border: none;
 | |
|         cursor: pointer;
 | |
|         border-radius: 4px;
 | |
|     }
 | |
| 
 | |
|     #reloadTrains:hover {
 | |
|         background-color: #0056b3;
 | |
|     }  
 | |
| 
 | |
|     .hidden {
 | |
|         display: none;
 | |
|     }
 | |
| 
 | |
|     </style>
 | |
| </head>
 | |
| <body>
 | |
|     <div id="map"></div>
 | |
|     <div class="bottombar">
 | |
|         <div class="left">
 | |
|             <input type="checkbox" id="layer0"> Express
 | |
|             <input type="checkbox" id="layer1"> Semi
 | |
|             <input type="checkbox" id="layer2"> Normal
 | |
|             <input type="checkbox" id="layer3"> Passenger
 | |
|             <input type="checkbox" id="layer4"> Subway
 | |
|             <input type="checkbox" id="layer5"> Logis
 | |
|         </div>
 | |
|         <div class="right">
 | |
|             <span class="loading" id="loading">Loading...</span>
 | |
|             <button id="reloadTrains">Reload</button>
 | |
|             <input type="checkbox" id="autoReload"> Auto
 | |
|         </div>
 | |
|     </div>
 | |
|     <script>
 | |
|         async function myFetch(url, options = {}) {
 | |
|             let headers = options.headers 
 | |
|             let f =  fetch('https://proxy.devpg.net', {
 | |
|                 headers: {
 | |
|                     'X-Proxy-URL': url,
 | |
|                     'X-Proxy-Header': JSON.stringify(headers),
 | |
|                     'X-Proxy-Cache': '0'
 | |
|                 }
 | |
|             });
 | |
|             console.log(`fetch(${url}, headers=${JSON.stringify(headers)}`, f);
 | |
|             return f
 | |
|         }
 | |
|         
 | |
|         const trainAPI = 'https://gis.korail.com/api/train?bbox=120.6263671875,28.07910949377748,134.0736328125,45.094739803960664'
 | |
| 
 | |
|         const server = ''
 | |
|         const map = L.map('map').setView([36.5, 128], 7.5);
 | |
| 
 | |
|         L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
 | |
|             attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
 | |
|         }).addTo(map);
 | |
| 
 | |
|         const railLayers = {
 | |
|             express: L.layerGroup().addTo(map),
 | |
|             normal: L.layerGroup().addTo(map),
 | |
|             semi: L.layerGroup().addTo(map),
 | |
|             logis: L.layerGroup().addTo(map)
 | |
|         };
 | |
| 
 | |
|         const stationLayers = [];
 | |
| 
 | |
|         for (let i = 0; i < 64; i++) {
 | |
|             const layerGroup = L.layerGroup().addTo(map);
 | |
|             stationLayers.push(layerGroup);
 | |
|         }
 | |
|     
 | |
|         for (let layer of stationLayers) {
 | |
|             map.removeLayer(layer);
 | |
|         }
 | |
|     
 | |
|         const trainLayer = L.layerGroup().addTo(map);
 | |
| 
 | |
|         function startSpinner() {
 | |
|             document.getElementById("loading").classList.remove("hidden");
 | |
|         }
 | |
|         function clearSpinner() {
 | |
|             document.getElementById("loading").classList.add("hidden");
 | |
|         }
 | |
| 
 | |
|         function loadRail(type) {
 | |
|             fetch(`${server}/api/rail/${type}`)
 | |
|                 .then(response => {
 | |
|                     if (!response.ok) {
 | |
|                         throw new Error(`Network response was not ok ${response.statusText}`);
 | |
|                     }
 | |
|                     return response.json();
 | |
|                 })
 | |
|                 .then(data => {
 | |
|                     L.geoJSON(data, {
 | |
|                         style: {
 | |
|                             color: type === 'express' ? 'blue' : type === 'normal' ? 'green' : type === 'semi' ? 'orange' : 'red'
 | |
|                         }
 | |
|                     }).addTo(railLayers[type]);
 | |
|                 })
 | |
|                 .catch(error => console.error(`Error fetching ${type} rail data: `, error));
 | |
|         }
 | |
| 
 | |
|         function loadStations() {
 | |
|             fetch(`${server}/api/station`)
 | |
|                 .then(response => {
 | |
|                     if (!response.ok) {
 | |
|                         throw new Error('Network response was not ok');
 | |
|                     }
 | |
|                     return response.json();
 | |
|                 })
 | |
|                 .then(data => {
 | |
|                     L.geoJSON(data, {
 | |
|                         pointToLayer: function (feature, latlng) {
 | |
|                             const shownLayer = parseInt(feature.properties.shown_layer.slice(2), 2);
 | |
| 
 | |
|                             const marker = L.marker(latlng, {
 | |
|                                 icon: L.divIcon({
 | |
|                                     className: 'station-label',
 | |
|                                     html: `<div>${feature.properties.name}</div>`,
 | |
|                                     iconSize: [100, 0]
 | |
|                                 })
 | |
|                             });
 | |
|                             if (stationLayers[shownLayer]) {
 | |
|                                 stationLayers[shownLayer].addLayer(marker);
 | |
|                             }
 | |
| 
 | |
|                             return marker;
 | |
|                         }
 | |
|                     });
 | |
|                 })
 | |
|                 .catch(error => console.error('Error fetching station data: ', error));
 | |
|         }
 | |
| 
 | |
|         function loadTrains() {
 | |
|             startSpinner();
 | |
|             myFetch(trainAPI, {
 | |
|                 headers: {
 | |
|                     "x-requested-with": "com.korail.talk",
 | |
|                     "referer": "https://gis.korail.com/korailTalk/entrance",
 | |
|                     "user-agent": "korailtalk AppVersion/6.3.3"
 | |
|                     }
 | |
|                 })
 | |
|                 .then(response => {
 | |
|                     if (!response.ok) {
 | |
|                         throw new Error('Network response was not ok');
 | |
|                     }
 | |
|                     return response.json();
 | |
|                 })
 | |
|                 .then(data => {
 | |
|                     trainLayer.clearLayers();
 | |
| 
 | |
|                     L.geoJSON(data, {
 | |
|                     pointToLayer: function (feature, latlng) {
 | |
|                         const trainIconHtml = `
 | |
|                             <div style="position: relative; text-align: center;">
 | |
|                                 <div style="background-color: #007bff; 
 | |
|                                             border-radius: 50%; 
 | |
|                                             width: 16px; 
 | |
|                                             height: 16px; 
 | |
|                                             display: inline-block; 
 | |
|                                             border: 2px solid white;"></div>
 | |
|                                 <div style="font-size: 12px; 
 | |
|                                             color: black; 
 | |
|                                             background-color: white; 
 | |
|                                             border: 1px solid black; 
 | |
|                                             margin-top: 2px; 
 | |
|                                             padding: 1px 3px; 
 | |
|                                             border-radius: 3px;
 | |
|                                             display: inline-block;
 | |
|                                             position: absolute;
 | |
|                                             left: 50%;
 | |
|                                             transform: translateX(-50%);
 | |
|                                             white-space: nowrap;">${feature.properties.trn_case} ${feature.properties.trn_no}</div>
 | |
|                             </div>`;
 | |
|                         return L.marker(latlng, {
 | |
|                             icon: L.divIcon({
 | |
|                                 className: 'train-marker',
 | |
|                                 html: trainIconHtml,
 | |
|                                 iconSize: [30, 42],
 | |
|                                 iconAnchor: [15, 21]
 | |
|                             })
 | |
|                         }).bindPopup(`${feature.properties.trn_case} ${feature.properties.trn_no}<br>
 | |
|                                             (${feature.properties.dpt_stn_nm} -> ${feature.properties.arv_stn_nm})<br>
 | |
|                                             ${feature.properties.now_stn} ${feature.properties.next_stn}`);
 | |
|                         }
 | |
|                     }).addTo(trainLayer);
 | |
|                     clearSpinner();
 | |
|                 })
 | |
|                 .catch(error => console.error('Error fetching train data: ', error));
 | |
|         }
 | |
| 
 | |
|         loadRail('express');
 | |
|         loadRail('normal');
 | |
|         loadRail('semi');
 | |
|         loadRail('logis');
 | |
| 
 | |
| 
 | |
|         for (let f = 0; f < 6; f++) {
 | |
|             document.getElementById(`layer${f}`).addEventListener('change', function () { // lable0: 0b 1XXXXX, label1: 0bX1XXXX, ...
 | |
|                 for (let i = 0; i < 64; i++) {
 | |
|                     if ( i & (1 << (5 - 0)) ) {
 | |
|                         if (this.checked) {
 | |
|                             map.addLayer(stationLayers[i]);   
 | |
|                         } else {
 | |
|                             map.removeLayer(stationLayers[i]);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             })
 | |
|         }
 | |
|         
 | |
|         document.getElementById('reloadTrains').addEventListener('click', loadTrains);
 | |
|         document.getElementById('autoReload').addEventListener('click', autoReload);
 | |
| 
 | |
|         let reloadInterval = null
 | |
|         function autoReload() {
 | |
|             if (this.checked) {
 | |
|                 reloadInterval = setInterval(loadTrains, 2000);
 | |
|             }
 | |
|             else {
 | |
|                 if (reloadInterval) {
 | |
|                     clearInterval(reloadInterval);
 | |
|                     reloadInterval = null;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         loadStations();
 | |
|         loadTrains();
 | |
| 
 | |
|     </script>
 | |
| </body>
 | |
| </html>
 |