KorailMap/index.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: '&copy; <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>