Upload files to "/"
This commit is contained in:
parent
9773a8ab07
commit
dbca4b8a9f
1
filtered_cities.json
Normal file
1
filtered_cities.json
Normal file
File diff suppressed because one or more lines are too long
501
map.html
Normal file
501
map.html
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Minimalist Interactive World Map</title>
|
||||||
|
|
||||||
|
<!-- Leaflet CSS -->
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
|
||||||
|
|
||||||
|
<!-- Google Fonts -->
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Google Material Icons -->
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Page Styles -->
|
||||||
|
<style>
|
||||||
|
/* Reset default margins and paddings */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set height for html and body to ensure the map covers the full viewport */
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map container styling */
|
||||||
|
#map {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #282A36; /* Dracula dark gray for water */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UI Menu Styling */
|
||||||
|
#menu {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px; /* Position 20px from the bottom */
|
||||||
|
right: 20px; /* Position 20px from the right */
|
||||||
|
background-color: rgba(40, 42, 54, 0.9); /* Semi-transparent Dracula dark gray */
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
z-index: 1000; /* Ensure it stays above the map */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button Styling remains unchanged */
|
||||||
|
#menu button {
|
||||||
|
background-color: #6272A4; /* Dracula muted purple */
|
||||||
|
border: none;
|
||||||
|
color: #F8F8F2; /* Dracula light gray text */
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button Hover Effect remains unchanged */
|
||||||
|
#menu button:hover {
|
||||||
|
background-color: #50fa7b; /* Dracula green */
|
||||||
|
color: #282A36; /* Dark gray text on hover */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Popup Styling (Overridden for Dark Theme) */
|
||||||
|
.leaflet-popup-content-wrapper {
|
||||||
|
background: #44475A; /* Dark background matching land fill */
|
||||||
|
color: #F8F8F2; /* Light text color */
|
||||||
|
border: 1px solid #6272A4; /* Optional: Subtle border */
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-popup-tip {
|
||||||
|
background: #44475A; /* Match the popup background */
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-popup-content {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #F8F8F2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide all controls in the top-left corner */
|
||||||
|
.leaflet-top.leaflet-left {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide all controls in the bottom-right corner */
|
||||||
|
.leaflet-bottom.leaflet-right {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Popup Styling (optional, can be customized further) */
|
||||||
|
.leaflet-popup-content {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #F8F8F2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Top Menu Bar Styling */
|
||||||
|
#topMenu {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgba(40, 42, 54, 0.9); /* Semi-transparent Dracula dark gray */
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 20px;
|
||||||
|
gap: 20px;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
||||||
|
z-index: 1001; /* Above the existing #menu which has z-index: 1000 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual Menu Item Styling */
|
||||||
|
#topMenu .menu-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: #F8F8F2; /* Light text color */
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: default; /* Change to 'pointer' if interactive */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Material Icons Styling */
|
||||||
|
#topMenu .material-icons {
|
||||||
|
font-size: 24px; /* Adjust icon size as needed */
|
||||||
|
color: #50fa7b; /* Dracula green for icons */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover Effect (Optional) */
|
||||||
|
#topMenu .menu-item:hover {
|
||||||
|
color: #50fa7b; /* Change text color on hover */
|
||||||
|
}
|
||||||
|
|
||||||
|
#topMenu .material-icons:hover {
|
||||||
|
color: #f1fa8c; /* Change icon color on hover */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Attribution Styling */
|
||||||
|
#attribution {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 10px;
|
||||||
|
background-color: rgba(40, 42, 54, 0.8); /* Semi-transparent background */
|
||||||
|
color: #F8F8F2; /* Light text color */
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
z-index: 1000; /* Ensure it stays above the map */
|
||||||
|
}
|
||||||
|
|
||||||
|
#attribution a {
|
||||||
|
color: #50fa7b; /* Dracula green for links */
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attribution a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Floating Event Window Styling */
|
||||||
|
.popup {
|
||||||
|
position: fixed;
|
||||||
|
width: 300px;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: #2E2E2E; /* Dark background */
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 2000; /* Above all other elements */
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
display: none; /* Hidden by default */
|
||||||
|
cursor: move; /* Indicate draggable */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Popup header styling */
|
||||||
|
.popup-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title in the header */
|
||||||
|
.popup-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close button styling */
|
||||||
|
.popup-close-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content area */
|
||||||
|
.popup-content {
|
||||||
|
margin-top: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Action buttons */
|
||||||
|
.popup-actions {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-action-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #50fa7b; /* Green */
|
||||||
|
color: #282A36;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-action-btn:hover {
|
||||||
|
background-color: #62d96b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Adjustments for Popup */
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
.popup {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- Top Menu Bar -->
|
||||||
|
<div id="topMenu">
|
||||||
|
<div class="menu-item">
|
||||||
|
<span class="material-icons">attach_money</span>
|
||||||
|
<span class="menu-text">Money: $1,000</span>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item">
|
||||||
|
<span class="material-icons">access_time</span>
|
||||||
|
<span class="menu-text" id="currentTime">Time: 12:00 PM</span>
|
||||||
|
</div>
|
||||||
|
<!-- Add more menu items as needed -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Map Container -->
|
||||||
|
<div id="map"></div>
|
||||||
|
|
||||||
|
<!-- UI Menu with Zoom Controls -->
|
||||||
|
<div id="menu">
|
||||||
|
<button id="zoomInBtn">Zoom In</button>
|
||||||
|
<button id="zoomOutBtn">Zoom Out</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Floating Event Window -->
|
||||||
|
<div id="eventWindow" class="popup">
|
||||||
|
<div class="popup-header">
|
||||||
|
<span class="popup-title">Event Title</span>
|
||||||
|
<button class="popup-close-btn">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="popup-content">
|
||||||
|
<p>Event description goes here. This area will be updated with dynamic text.</p>
|
||||||
|
</div>
|
||||||
|
<div class="popup-actions">
|
||||||
|
<button class="popup-action-btn" id="actionOk">OK</button>
|
||||||
|
<button class="popup-action-btn" id="actionCancel">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Leaflet JS -->
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
|
||||||
|
|
||||||
|
<!-- Initialize Map and Add Layers -->
|
||||||
|
<script>
|
||||||
|
// Initialize the map centered at latitude 20, longitude 0 with zoom level 2
|
||||||
|
const map = L.map('map').setView([20, 0], 2);
|
||||||
|
|
||||||
|
// Create custom panes to control layer order
|
||||||
|
map.createPane('landPane');
|
||||||
|
map.getPane('landPane').style.zIndex = 400; // Below citiesPane
|
||||||
|
|
||||||
|
map.createPane('citiesPane');
|
||||||
|
map.getPane('citiesPane').style.zIndex = 650; // Above landPane
|
||||||
|
|
||||||
|
// Define styles for land and water
|
||||||
|
const landStyle = {
|
||||||
|
color: "#F8F8F2", // Light gray border (optional)
|
||||||
|
fillColor: "#44475A", // Light gray land fill (Dracula theme)
|
||||||
|
fillOpacity: 1,
|
||||||
|
weight: 0.5
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add land GeoJSON layer to the 'landPane'
|
||||||
|
fetch('ne_50m_land.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
L.geoJSON(data, {
|
||||||
|
style: landStyle,
|
||||||
|
pane: 'landPane' // Assign to landPane
|
||||||
|
}).addTo(map);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading ne_50m_land.json:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define styles for cities using Dracula color scheme
|
||||||
|
const cityStyle = {
|
||||||
|
radius: 4,
|
||||||
|
fillColor: "#FF79C6", // Dracula pink
|
||||||
|
color: "#BD93F9", // Dracula purple border
|
||||||
|
weight: 1,
|
||||||
|
opacity: 1,
|
||||||
|
fillOpacity: 0.9
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load the filtered cities JSON file (from worldcities.csv)
|
||||||
|
fetch('filtered_cities.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(cities => {
|
||||||
|
const cityLayer = L.layerGroup(); // Group cities into a layer
|
||||||
|
cities.forEach(city => {
|
||||||
|
// Convert lat/lng to numbers
|
||||||
|
const lat = parseFloat(city.lat);
|
||||||
|
const lng = parseFloat(city.lng);
|
||||||
|
|
||||||
|
// Create a circle marker for each city
|
||||||
|
L.circleMarker([lat, lng], {
|
||||||
|
...cityStyle,
|
||||||
|
pane: 'citiesPane' // Assign to citiesPane
|
||||||
|
})
|
||||||
|
.bindPopup(`<strong>${city.city}</strong><br>Population: ${city.population}`)
|
||||||
|
.addTo(cityLayer);
|
||||||
|
});
|
||||||
|
// Add city layer on top of the map
|
||||||
|
cityLayer.addTo(map);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading filtered_cities.json:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Zoom In Button Functionality
|
||||||
|
document.getElementById('zoomInBtn').addEventListener('click', () => {
|
||||||
|
map.zoomIn();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Zoom Out Button Functionality
|
||||||
|
document.getElementById('zoomOutBtn').addEventListener('click', () => {
|
||||||
|
map.zoomOut();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Optional: Add keyboard controls for zooming
|
||||||
|
map.keyboard.enable();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- JavaScript for Dynamic Time Update -->
|
||||||
|
<script>
|
||||||
|
// Function to format time in HH:MM AM/PM
|
||||||
|
function formatTime(date) {
|
||||||
|
let hours = date.getHours();
|
||||||
|
let minutes = date.getMinutes();
|
||||||
|
const ampm = hours >= 12 ? 'PM' : 'AM';
|
||||||
|
hours = hours % 12;
|
||||||
|
hours = hours ? hours : 12; // the hour '0' should be '12'
|
||||||
|
minutes = minutes < 10 ? '0'+minutes : minutes;
|
||||||
|
const strTime = hours + ':' + minutes + ' ' + ampm;
|
||||||
|
return strTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update the current time every second
|
||||||
|
function updateTime() {
|
||||||
|
const now = new Date();
|
||||||
|
const formattedTime = formatTime(now);
|
||||||
|
document.getElementById('currentTime').textContent = `Time: ${formattedTime}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize time update
|
||||||
|
updateTime(); // Initial call
|
||||||
|
setInterval(updateTime, 1000); // Update every second
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- JavaScript for Floating Event Window -->
|
||||||
|
<script>
|
||||||
|
// Get popup elements
|
||||||
|
const popup = document.getElementById("eventWindow");
|
||||||
|
const closeBtn = document.querySelector(".popup-close-btn");
|
||||||
|
const actionOkBtn = document.getElementById("actionOk");
|
||||||
|
const actionCancelBtn = document.getElementById("actionCancel");
|
||||||
|
|
||||||
|
// Function to open popup with dynamic content
|
||||||
|
function showPopup(eventTitle, eventDescription, actions = { ok: null, cancel: null }) {
|
||||||
|
popup.style.display = "block";
|
||||||
|
document.querySelector(".popup-title").textContent = eventTitle;
|
||||||
|
document.querySelector(".popup-content p").textContent = eventDescription;
|
||||||
|
|
||||||
|
// Assign actions if provided
|
||||||
|
if (actions.ok) {
|
||||||
|
actionOkBtn.textContent = actions.ok.text || "OK";
|
||||||
|
actionOkBtn.onclick = actions.ok.handler || closePopup;
|
||||||
|
} else {
|
||||||
|
actionOkBtn.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions.cancel) {
|
||||||
|
actionCancelBtn.textContent = actions.cancel.text || "Cancel";
|
||||||
|
actionCancelBtn.onclick = actions.cancel.handler || closePopup;
|
||||||
|
} else {
|
||||||
|
actionCancelBtn.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to close popup
|
||||||
|
function closePopup() {
|
||||||
|
popup.style.display = "none";
|
||||||
|
// Reset action buttons display
|
||||||
|
actionOkBtn.style.display = "inline-block";
|
||||||
|
actionCancelBtn.style.display = "inline-block";
|
||||||
|
// Reset action buttons handlers
|
||||||
|
actionOkBtn.onclick = () => { closePopup(); };
|
||||||
|
actionCancelBtn.onclick = () => { closePopup(); };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close button click handler
|
||||||
|
closeBtn.addEventListener("click", closePopup);
|
||||||
|
|
||||||
|
// Action buttons handler (for demo purposes)
|
||||||
|
actionOkBtn.addEventListener("click", () => {
|
||||||
|
alert("OK clicked!");
|
||||||
|
closePopup();
|
||||||
|
});
|
||||||
|
|
||||||
|
actionCancelBtn.addEventListener("click", () => {
|
||||||
|
alert("Cancel clicked!");
|
||||||
|
closePopup();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Example: Trigger popup with event information
|
||||||
|
// This can be replaced by your game logic
|
||||||
|
// Uncomment the line below to test the popup on page load
|
||||||
|
// showPopup("Promotion Event", "You have been promoted to the rank of Godmother in the Versace family!");
|
||||||
|
|
||||||
|
// Making the Popup Draggable
|
||||||
|
(function() {
|
||||||
|
let isDragging = false;
|
||||||
|
let offsetX, offsetY;
|
||||||
|
|
||||||
|
const header = popup.querySelector(".popup-header");
|
||||||
|
|
||||||
|
header.addEventListener("mousedown", (e) => {
|
||||||
|
isDragging = true;
|
||||||
|
const rect = popup.getBoundingClientRect();
|
||||||
|
offsetX = e.clientX - rect.left;
|
||||||
|
offsetY = e.clientY - rect.top;
|
||||||
|
popup.style.transition = "none"; // Disable transition while dragging
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("mousemove", (e) => {
|
||||||
|
if (isDragging) {
|
||||||
|
let newLeft = e.clientX - offsetX;
|
||||||
|
let newTop = e.clientY - offsetY;
|
||||||
|
|
||||||
|
// Optional: Prevent the popup from going off-screen
|
||||||
|
const popupWidth = popup.offsetWidth;
|
||||||
|
const popupHeight = popup.offsetHeight;
|
||||||
|
const windowWidth = window.innerWidth;
|
||||||
|
const windowHeight = window.innerHeight;
|
||||||
|
|
||||||
|
// Clamp the positions
|
||||||
|
newLeft = Math.max(0, Math.min(newLeft, windowWidth - popupWidth));
|
||||||
|
newTop = Math.max(0, Math.min(newTop, windowHeight - popupHeight));
|
||||||
|
|
||||||
|
popup.style.left = `${newLeft}px`;
|
||||||
|
popup.style.top = `${newTop}px`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("mouseup", () => {
|
||||||
|
if (isDragging) {
|
||||||
|
isDragging = false;
|
||||||
|
popup.style.transition = ""; // Re-enable transition if needed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Example: Trigger the sample event after 5 seconds
|
||||||
|
setTimeout(triggerSampleEvent, 5000);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1425
ne_50m_land.json
Normal file
1425
ne_50m_land.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user