geo-map-distance / index.html
alterzick's picture
additional search area fitur - Follow Up Deployment
814cee5 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive GIS Application</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
#map {
height: 70vh;
width: 100%;
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.control-panel {
background-color: rgba(255, 255, 255, 0.9);
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
padding: 1rem;
margin-bottom: 1rem;
}
.toggle-btn {
transition: all 0.3s ease;
}
.toggle-btn.active {
background-color: #3b82f6;
color: white;
}
.measurement-result {
background-color: rgba(255, 255, 255, 0.9);
border-radius: 0.5rem;
padding: 0.5rem 1rem;
margin-top: 0.5rem;
font-size: 0.9rem;
}
.coordinates-display {
position: absolute;
bottom: 10px;
right: 10px;
background-color: rgba(255, 255, 255, 0.9);
padding: 0.5rem 1rem;
border-radius: 0.5rem;
font-size: 0.8rem;
z-index: 1000;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
@media (max-width: 768px) {
#map {
height: 60vh;
}
.coordinates-display {
font-size: 0.7rem;
padding: 0.3rem 0.6rem;
}
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<header class="mb-8 text-center">
<h1 class="text-3xl font-bold text-blue-700 mb-2">Interactive GIS Application</h1>
<p class="text-gray-600">Measure distances, calculate areas, and view coordinates on the map</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
<div class="lg:col-span-1 space-y-4">
<div class="control-panel">
<h2 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
<i class="fas fa-tools mr-2"></i> Control Panel
</h2>
<div class="mb-4">
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
<i class="fas fa-ruler-combined mr-2"></i> Distance Measurement
</h3>
<button id="distanceToggle" class="toggle-btn w-full py-2 px-4 bg-gray-200 rounded-lg flex items-center justify-between">
<span>Turn On</span>
<i class="fas fa-toggle-off"></i>
</button>
<div id="distanceResult" class="measurement-result hidden">
<div class="flex justify-between">
<span>Total Distance:</span>
<span id="distanceValue">0</span>
</div>
</div>
</div>
<div class="mb-4">
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
<i class="fas fa-vector-square mr-2"></i> Area Measurement
</h3>
<button id="areaToggle" class="toggle-btn w-full py-2 px-4 bg-gray-200 rounded-lg flex items-center justify-between">
<span>Turn On</span>
<i class="fas fa-toggle-off"></i>
</button>
<div id="areaResult" class="measurement-result hidden">
<div class="flex justify-between">
<span>Total Area:</span>
<span id="areaValue">0</span>
</div>
</div>
</div>
<div>
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
<i class="fas fa-map-marker-alt mr-2"></i> Coordinates Display
</h3>
<button id="coordinatesToggle" class="toggle-btn w-full py-2 px-4 bg-gray-200 rounded-lg flex items-center justify-between">
<span>Turn On</span>
<i class="fas fa-toggle-off"></i>
</button>
</div>
</div>
<div class="control-panel">
<h2 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
<i class="fas fa-search mr-2"></i> Location Search
</h2>
<div class="mb-4">
<input type="text" id="searchInput" placeholder="Search for a location..."
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<button id="searchButton" class="mt-2 w-full py-2 px-4 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition">
Search
</button>
</div>
<h2 class="text-xl font-semibold mb-4 text-gray-800 flex items-center">
<i class="fas fa-info-circle mr-2"></i> Instructions
</h2>
<ul class="space-y-2 text-sm text-gray-600">
<li class="flex items-start">
<i class="fas fa-circle text-blue-500 mt-1 mr-2 text-xs"></i>
<span>Toggle buttons to activate measurement tools</span>
</li>
<li class="flex items-start">
<i class="fas fa-circle text-blue-500 mt-1 mr-2 text-xs"></i>
<span>Click on map to start measuring distance</span>
</li>
<li class="flex items-start">
<i class="fas fa-circle text-blue-500 mt-1 mr-2 text-xs"></i>
<span>Double-click to finish distance measurement</span>
</li>
<li class="flex items-start">
<i class="fas fa-circle text-blue-500 mt-1 mr-2 text-xs"></i>
<span>Draw a polygon for area measurement</span>
</li>
<li class="flex items-start">
<i class="fas fa-circle text-blue-500 mt-1 mr-2 text-xs"></i>
<span>Enable coordinates to see current pointer location</span>
</li>
</ul>
</div>
</div>
<div class="lg:col-span-3 relative">
<div id="map"></div>
<div id="coordinatesDisplay" class="coordinates-display hidden">
<div class="flex space-x-4">
<div>
<span class="text-gray-500">Lat:</span>
<span id="latValue">0</span>
</div>
<div>
<span class="text-gray-500">Lng:</span>
<span id="lngValue">0</span>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize the map centered on Indonesia
const map = L.map('map').setView([-2.5489, 118.0149], 5);
// Add OpenStreetMap tiles
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);
// Variables for measurement features
let distanceMode = false;
let areaMode = false;
let coordinatesMode = false;
let drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// Initialize draw controls
const drawControl = new L.Control.Draw({
draw: {
polygon: false,
polyline: false,
rectangle: false,
circle: false,
marker: false,
circlemarker: false
},
edit: {
featureGroup: drawnItems
}
});
map.addControl(drawControl);
// DOM elements
const distanceToggle = document.getElementById('distanceToggle');
const areaToggle = document.getElementById('areaToggle');
const coordinatesToggle = document.getElementById('coordinatesToggle');
const distanceResult = document.getElementById('distanceResult');
const areaResult = document.getElementById('areaResult');
const distanceValue = document.getElementById('distanceValue');
const areaValue = document.getElementById('areaValue');
const coordinatesDisplay = document.getElementById('coordinatesDisplay');
const latValue = document.getElementById('latValue');
const lngValue = document.getElementById('lngValue');
// Toggle distance measurement
distanceToggle.addEventListener('click', function() {
distanceMode = !distanceMode;
if (distanceMode) {
// Turn off area mode if it's on
if (areaMode) {
toggleAreaMode();
}
this.classList.add('active');
this.innerHTML = '<span>Turn Off</span><i class="fas fa-toggle-on"></i>';
distanceResult.classList.remove('hidden');
// Enable polyline drawing
const polyline = new L.Draw.Polyline(map, {
shapeOptions: {
color: '#3b82f6',
weight: 3,
dashArray: '5, 5'
},
metric: true
});
polyline.enable();
// Listen for draw events
map.on('draw:created', function(e) {
const type = e.layerType;
const layer = e.layer;
if (type === 'polyline') {
drawnItems.addLayer(layer);
updateDistance(layer);
// Listen for edits
layer.on('edit', function() {
updateDistance(layer);
});
}
});
} else {
this.classList.remove('active');
this.innerHTML = '<span>Turn On</span><i class="fas fa-toggle-off"></i>';
distanceResult.classList.add('hidden');
drawnItems.clearLayers();
}
});
// Toggle area measurement
areaToggle.addEventListener('click', function() {
toggleAreaMode();
});
function toggleAreaMode() {
areaMode = !areaMode;
if (areaMode) {
// Turn off distance mode if it's on
if (distanceMode) {
toggleDistanceMode();
}
areaToggle.classList.add('active');
areaToggle.innerHTML = '<span>Turn Off</span><i class="fas fa-toggle-on"></i>';
areaResult.classList.remove('hidden');
// Enable polygon drawing
const polygon = new L.Draw.Polygon(map, {
shapeOptions: {
color: '#10b981',
weight: 2,
fillOpacity: 0.3
},
metric: true
});
polygon.enable();
// Listen for draw events
map.on('draw:created', function(e) {
const type = e.layerType;
const layer = e.layer;
if (type === 'polygon') {
drawnItems.addLayer(layer);
updateArea(layer);
// Listen for edits
layer.on('edit', function() {
updateArea(layer);
});
}
});
} else {
areaToggle.classList.remove('active');
areaToggle.innerHTML = '<span>Turn On</span><i class="fas fa-toggle-off"></i>';
areaResult.classList.add('hidden');
drawnItems.clearLayers();
}
}
function toggleDistanceMode() {
distanceMode = !distanceMode;
distanceToggle.classList.toggle('active');
distanceToggle.innerHTML = distanceMode ?
'<span>Turn Off</span><i class="fas fa-toggle-on"></i>' :
'<span>Turn On</span><i class="fas fa-toggle-off"></i>';
distanceResult.classList.toggle('hidden');
drawnItems.clearLayers();
}
// Toggle coordinates display
coordinatesToggle.addEventListener('click', function() {
coordinatesMode = !coordinatesMode;
if (coordinatesMode) {
this.classList.add('active');
this.innerHTML = '<span>Turn Off</span><i class="fas fa-toggle-on"></i>';
coordinatesDisplay.classList.remove('hidden');
// Show initial coordinates
latValue.textContent = map.getCenter().lat.toFixed(6);
lngValue.textContent = map.getCenter().lng.toFixed(6);
// Update coordinates on mouse move
map.on('mousemove', updateCoordinates);
} else {
this.classList.remove('active');
this.innerHTML = '<span>Turn On</span><i class="fas fa-toggle-off"></i>';
coordinatesDisplay.classList.add('hidden');
map.off('mousemove', updateCoordinates);
}
});
// Update coordinates display
function updateCoordinates(e) {
latValue.textContent = e.latlng.lat.toFixed(6);
lngValue.textContent = e.latlng.lng.toFixed(6);
}
// Calculate and update distance
function updateDistance(layer) {
const distance = L.GeometryUtil.length(layer);
distanceValue.textContent = distance > 1000 ?
(distance / 1000).toFixed(2) + ' km' :
Math.round(distance) + ' m';
}
// Calculate and update area
function updateArea(layer) {
const area = L.GeometryUtil.geodesicArea(layer.getLatLngs()[0]);
areaValue.textContent = area > 10000 ?
(area / 1000000).toFixed(2) + ' km²' :
Math.round(area) + ' m²';
}
// Clear measurements when switching modes
function clearMeasurements() {
drawnItems.clearLayers();
}
// Location search functionality
const searchInput = document.getElementById('searchInput');
const searchButton = document.getElementById('searchButton');
searchButton.addEventListener('click', searchLocation);
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
searchLocation();
}
});
function searchLocation() {
const query = searchInput.value.trim();
if (!query) return;
fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}`)
.then(response => response.json())
.then(data => {
if (data.length > 0) {
const result = data[0];
const lat = parseFloat(result.lat);
const lon = parseFloat(result.lon);
map.setView([lat, lon], 14);
// Add marker for the found location
drawnItems.clearLayers();
L.marker([lat, lon])
.bindPopup(`<b>${result.display_name}</b>`)
.addTo(drawnItems)
.openPopup();
} else {
alert('Location not found');
}
})
.catch(error => {
console.error('Search error:', error);
alert('Error searching for location');
});
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=alterzick/geo-map-distance" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>