Commit 606a51e3 authored by Matthias Betz's avatar Matthias Betz
Browse files

remove unused test resource

parent e910bf8c
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Leaflet Polygon Selector (Background Download)</title>
<link rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin="" />
<link rel="stylesheet"
href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<script
src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
<style>
/* Basic CSS to make the map fullscreen */
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden; /* Prevent scrollbars on body */
}
#map {
width: 100%;
height: 100%;
}
/* Style for the WKT output box */
#wkt-output {
position: absolute;
bottom: 70px; /* Position above the download button */
right: 10px;
background: rgba(255, 255, 255, 0.85);
padding: 5px 10px;
border: 1px solid #ccc;
border-radius: 4px;
z-index: 1000; /* Ensure it's above the map */
font-family: monospace;
font-size: 0.8em;
max-width: 300px;
max-height: 150px;
overflow-y: auto;
word-wrap: break-word;
display: none; /* Hidden by default */
}
/* Simple instruction text */
#instructions {
position: absolute;
top: 10px;
left: 50px; /* Position relative to default zoom controls */
background: rgba(255, 255, 255, 0.85);
padding: 5px 10px;
border: 1px solid #ccc;
border-radius: 4px;
z-index: 1000;
font-family: sans-serif;
font-size: 0.9em;
}
/* Style for the Download button */
#download-button {
position: absolute;
bottom: 30px;
right: 10px;
z-index: 1000;
padding: 8px 15px;
cursor: pointer;
background-color: #4CAF50; /* Green */
color: white;
border: none;
border-radius: 4px;
font-size: 1em;
display: none; /* Hidden by default */
}
#download-button:hover {
background-color: #45a049;
}
#download-button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
/* Style for the Clear button */
#clear-button {
position: absolute;
bottom: 30px;
right: 160px; /* Adjusted position */
z-index: 1000;
padding: 8px 15px;
cursor: pointer;
background-color: #f44336; /* Red */
color: white;
border: none;
border-radius: 4px;
font-size: 1em;
display: none; /* Hidden by default, show while drawing or finished*/
}
#clear-button:hover {
background-color: #da190b;
}
/* Ensure geocoder input is usable */
.leaflet-control-geocoder {
z-index: 1001 !important; /* Ensure search is above other elements */
}
.leaflet-control-geocoder-form input {
min-width: 200px; /* Make search input wider */
}
#searchContainer {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%); /* horizontally center */
z-index: 1000;
background: rgba(255, 255, 255, 0.9);
padding: 5px 10px;
border: 1px solid #ccc;
border-radius: 4px;
display: flex;
gap: 8px;
align-items: center;
}
#searchContainer input {
padding: 4px 8px;
font-size: 0.9em;
}
#searchContainer button {
padding: 5px 10px;
font-size: 0.9em;
cursor: pointer;
}
</style>
</head>
<body>
<div id="searchContainer">
<input id="searchInput" type="text" placeholder="Enter ID to search">
<button id="searchButton">Search</button>
</div>
<div id="map"></div>
<div id="instructions">Click map to start drawing polygon.</div>
<div id="wkt-output"></div>
<button id="download-button">Download Data</button>
<button id="clear-button">Clear Polygon</button>
<script>
const qaColors = {
'QA1': { color: '#e41a1c', fillColor: '#fbb4ae', text: 'QA1 (EFH/2FA)' },
'QA2': { color: '#377eb8', fillColor: '#b3cde3', text: 'QA2 (Mehrgeschossig)'},
'QA3': { color: '#4daf4a', fillColor: '#ccebc5', text: 'QA3 (Innenstadt)' },
'QA4': { color: '#984ea3', fillColor: '#decbe4', text: 'QA4 (Großer Wohnungsbau)' },
'QA5': { color: '#ff7f00', fillColor: '#fed9a6', text: 'QA5 (Wohn- Geschäfts- Bürozentrum)' },
'QA6': { color: '#a65628', fillColor: '#fddbc7', text: 'QA6 (Stadtnahes Gewerbe)' },
'QA7': { color: '#f781bf', fillColor: '#fbb5d3', text: 'QA7 (Industrie- und Gewerbepark)' }
};
// Wait for the DOM to be fully loaded
document.addEventListener('DOMContentLoaded', function () {
// --- Configuration ---
const SERVER_BASE_URL = "https://citygml.hft-stuttgart.de/citygml"; // Define server URL here
const DEFAULT_FILENAME = "data.gml"; // Fallback filename for download
// --- Initialize Map ---
const map = L.map('map', {
keyboard: true
}).fitBounds([[47.53564, 7.52587], [49.78976, 10.4856]]); // Center on BW
const featureLayers = {};
let highlightedLayer = null;
// --- Load GeoJSON file ---
fetch('test.geojson')
.then(response => response.json())
.then(data => {
// Add the GeoJSON layer
const geoJsonLayer = L.geoJSON(data, {
style: feature => {
const qa = feature.properties.Quarterarchetype;
const colors = qaColors[qa] || { color: 'gray', fillColor: 'lightgray' };
return {
color: colors.color,
weight: 2,
fillColor: colors.fillColor,
fillOpacity: 0.5
};
},
onEachFeature: function (feature, layer) {
// Save each layer by its ID property
if (feature.properties && feature.properties.id) {
featureLayers[feature.properties.id] = layer;
}
// Optional: bind popup to show properties
if (feature.properties) {
layer.bindPopup("ID: " + feature.properties.id + "<br>Archetype: " + feature.properties.Quarterarchetype);
}
}
}).addTo(map);
map.fitBounds(geoJsonLayer.getBounds());
// --- Add a Legend ---
const legend = L.control({ position: 'bottomleft' });
legend.onAdd = function (map) {
const div = L.DomUtil.create('div', 'info legend');
div.style.background = 'white';
div.style.padding = '8px';
div.style.border = '1px solid #ccc';
div.style.borderRadius = '4px';
div.style.fontSize = '0.9em';
div.innerHTML += '<strong>QA Legend</strong><br>';
for (const qa in qaColors) {
const { fillColor, color, text } = qaColors[qa];
div.innerHTML +=
`<i style="
background:${fillColor};
border:2px solid ${color};
display:inline-block;
width:18px;
height:18px;
margin-right:6px;
vertical-align:middle;">
</i> ${text}<br>`;
}
return div;
};
legend.addTo(map);
})
.catch(err => console.error('Error loading GeoJSON:', err));
document.getElementById('searchButton').addEventListener('click', () => {
const value = document.getElementById('searchInput').value.trim();
// Reset any previous highlight
if (highlightedLayer) {
geoJsonLayer.resetStyle(highlightedLayer);
highlightedLayer = null;
}
if (value && featureLayers[value]) {
highlightedLayer = featureLayers[value];
// Highlight style
highlightedLayer.setStyle({
color: 'yellow',
weight: 4,
fillColor: 'gold',
fillOpacity: 0.7
});
// Bring to front (useful for polygons)
if (highlightedLayer.bringToFront) {
highlightedLayer.bringToFront();
}
// Zoom to the layer
map.fitBounds(highlightedLayer.getBounds());
// Optionally open its popup
highlightedLayer.openPopup();
} else {
alert('No feature found with ID = ' + value);
}
});
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);
// --- Add Geocoder (Search) Control ---
L.Control.geocoder({
defaultMarkGeocode: true
}).addTo(map);
// --- State Variables ---
let drawingEnabled = true;
let points = [];
let tempMarkers = [];
let tempPolyline = null;
let finalPolygon = null;
let firstMarker = null;
let currentWktString = null; // Store WKT for download button
// --- DOM Element References ---
const wktOutputDiv = document.getElementById('wkt-output');
const downloadButton = document.getElementById('download-button');
const clearButton = document.getElementById('clear-button');
const instructionsDiv = document.getElementById('instructions');
// --- Helper Functions ---
function getFilenameFromHeader(header) {
if (!header) return null;
// Simple regex for filename="..."; handles quotes, case-insensitive
const match = header.match(/filename\s*=\s*"?([^"]+)"?/i);
return match && match[1] ? match[1] : null;
}
function updateInstructions() {
if (drawingEnabled) {
if (points.length === 0) {
instructionsDiv.textContent = 'Click map to start drawing polygon.';
} else if (points.length < 3) {
instructionsDiv.textContent = `Points: ${points.length}. Add ${3 - points.length} more point(s). Click first marker to close (min 3 points).`;
} else {
instructionsDiv.textContent = `Points: ${points.length}. Click first marker or add more points.`;
}
} else {
instructionsDiv.textContent = 'Polygon finalized. Click Download or Clear.';
}
}
function resetDrawing() {
drawingEnabled = true;
points = [];
currentWktString = null;
tempMarkers.forEach(marker => map.removeLayer(marker));
tempMarkers = [];
if (firstMarker) {
firstMarker.off('click'); // Remove specific listener
firstMarker = null;
}
if (tempPolyline) {
map.removeLayer(tempPolyline);
tempPolyline = null;
}
if (finalPolygon) {
map.removeLayer(finalPolygon);
finalPolygon = null;
}
wktOutputDiv.style.display = 'none';
wktOutputDiv.textContent = '';
downloadButton.style.display = 'none';
downloadButton.disabled = false; // Re-enable button
downloadButton.textContent = 'Download Data'; // Reset button text
clearButton.style.display = 'none';
updateInstructions();
console.log("Drawing reset.");
}
function finalizePolygon() {
if (points.length < 3) return;
console.log("Finalizing polygon...");
drawingEnabled = false;
// Remove temporary items
tempMarkers.forEach(marker => map.removeLayer(marker));
tempMarkers = [];
if (tempPolyline) {
map.removeLayer(tempPolyline);
tempPolyline = null;
}
if (firstMarker) {
firstMarker.off('click');
firstMarker = null; // Ref only needed during drawing
}
if (finalPolygon) map.removeLayer(finalPolygon);
finalPolygon = L.polygon(points, { color: 'blue' }).addTo(map);
// Generate and store WKT
let wktCoords = points.map(p => `${p.lng} ${p.lat}`);
wktCoords.push(`${points[0].lng} ${points[0].lat}`); // Close ring
currentWktString = `POLYGON((${wktCoords.join(',')}))`; // Store for download
// Display WKT
wktOutputDiv.textContent = `WKT (WGS84):\n${currentWktString}`;
wktOutputDiv.style.display = 'block';
// Show buttons
downloadButton.style.display = 'block';
clearButton.style.display = 'block';
updateInstructions();
}
// --- Event Listeners ---
// Map Click: Add points
map.on('click', function(e) {
if (!drawingEnabled) return;
const latlng = e.latlng;
points.push(latlng);
if (points.length > 0) {
clearButton.style.display = 'block';
}
const newMarker = L.marker(latlng).addTo(map);
tempMarkers.push(newMarker);
if (points.length === 1) {
firstMarker = newMarker; // Store reference to the first marker
// Add the specific click listener for closing
firstMarker.on('click', function(ev) {
L.DomEvent.stopPropagation(ev); // Prevent map click
if (drawingEnabled && points.length >= 3) {
finalizePolygon();
} else if (drawingEnabled) {
console.log("Click on first marker, but not enough points (<3).");
// Optional: Provide user feedback here
}
});
}
if (tempPolyline) map.removeLayer(tempPolyline);
if (points.length > 1) {
tempPolyline = L.polyline(points, { color: 'red', weight: 2, dashArray: '5, 5' }).addTo(map);
}
updateInstructions();
});
// Download Button Click: Fetch data and trigger download
downloadButton.addEventListener('click', async function() {
if (!currentWktString) {
console.error("Download clicked, but no WKT available.");
return;
}
const encodedWkt = encodeURIComponent(currentWktString); // Correctly escapes () etc.
const fullUrl = `${SERVER_BASE_URL}?wktPolygon=${encodedWkt}`;
console.log("Requesting data from:", fullUrl);
downloadButton.disabled = true;
downloadButton.textContent = 'Downloading...';
try {
const response = await fetch(fullUrl);
if (!response.ok) {
// Handle HTTP errors (e.g., 404, 500)
throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);
}
// Get data as a Blob
const blob = await response.blob();
// Determine filename
const contentDisposition = response.headers.get('Content-Disposition');
const filename = getFilenameFromHeader(contentDisposition) || DEFAULT_FILENAME;
// Create a temporary link to trigger download
const tempLink = document.createElement('a');
const objectUrl = URL.createObjectURL(blob);
tempLink.href = objectUrl;
tempLink.download = filename; // Set the desired filename
document.body.appendChild(tempLink); // Append necessary for Firefox
tempLink.click(); // Simulate click
// Cleanup
document.body.removeChild(tempLink);
URL.revokeObjectURL(objectUrl);
console.log(`Download triggered for file: ${filename}`);
downloadButton.textContent = 'Download Complete'; // Give feedback
} catch (error) {
console.error("Download failed:", error);
alert(`Failed to download data: ${error.message}`); // Notify user
downloadButton.textContent = 'Download Failed'; // Give feedback
} finally {
// Re-enable button after a delay, or keep it as 'Complete'/'Failed'
// For simplicity, let's re-enable and reset text on clear/new polygon.
// If keeping status, disable clear until download complete/failed?
// Let's just allow clear anytime.
// Reset button state after a small delay to show status
setTimeout(() => {
if (!drawingEnabled) { // Only reset if still in finalized state
downloadButton.disabled = false;
downloadButton.textContent = 'Download Data';
}
}, 3000); // Reset text after 3 seconds
}
});
// Clear Button Click
clearButton.addEventListener('click', function() {
console.log("Clear button clicked.");
resetDrawing();
});
// Optional: Reset on double-click (if not drawing)
map.on('dblclick', function(e) {
if (!drawingEnabled) {
resetDrawing();
}
});
// --- Initial State ---
updateInstructions();
}); // End DOMContentLoaded
</script>
</body>
</html>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment