Spaces:
Running
Running
Download script.js from S127272/deepsite-project: direct link, hf CLI and curl.
- Browser
- Download file 7.34 kB
-
https://huggingface.co/spaces/S127272/deepsite-project/resolve/main/script.js
- Command line
-
hf download hf://spaces/S127272/deepsite-project/script.js
-
curl -L -o script.js https://huggingface.co/spaces/S127272/deepsite-project/resolve/main/script.js
7.34 kB
| ```javascript | |
| // Initialize map centered on UWI St. Augustine | |
| var map = L.map('map').setView([10.6411, -61.3995], 16); | |
| L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
| maxZoom: 21, | |
| attribution: '© OpenStreetMap contributors' | |
| }).addTo(map); | |
| // Variables to hold layers | |
| var buildingsLayer, roadsLayer, walkwaysLayer, poisLayer; | |
| var promises = []; | |
| // Also load blocks from backend once | |
| let blockMap = new Map(); // block_id -> block_name | |
| promises.push( | |
| fetch('/blocks').then(r => r.json()).then(rows => { | |
| rows.forEach(b => blockMap.set(b.block_id, b.name)); | |
| }) | |
| ); | |
| // Load Buildings | |
| promises.push( | |
| fetch('data/st_augustine_buildings.geojson') | |
| .then(res => res.json()) | |
| .then(data => { | |
| buildingsLayer = L.geoJSON(data, { | |
| style: { color: 'black', fillColor: 'lightgrey', weight: 1 }, | |
| onEachFeature: function(feature, layer) { | |
| if (feature.properties && feature.properties.name) { | |
| layer.bindPopup("Building: " + feature.properties.name); | |
| } | |
| } | |
| }).addTo(map); | |
| }) | |
| ); | |
| // Load Roads | |
| promises.push( | |
| fetch('data/drive_edges.geojson') | |
| .then(res => res.json()) | |
| .then(data => { | |
| roadsLayer = L.geoJSON(data, { | |
| style: { color: 'blue', weight: 1 } | |
| }).addTo(map); | |
| }) | |
| ); | |
| // Load Walkways | |
| promises.push( | |
| fetch('data/walk_edges.geojson') | |
| .then(res => res.json()) | |
| .then(data => { | |
| walkwaysLayer = L.geoJSON(data, { | |
| style: { color: 'green', weight: 3, dashArray: '4' } | |
| }).addTo(map); | |
| }) | |
| ); | |
| // Load POIs | |
| promises.push( | |
| fetch('data/pois.geojson') | |
| .then(res => res.json()) | |
| .then(data => { | |
| poisLayer = L.geoJSON(data, { | |
| pointToLayer: (feature, latlng) => { | |
| var marker = L.circleMarker(latlng, { | |
| radius: 5, | |
| fillColor: 'red', | |
| color: 'lightgrey', | |
| weight: 0.5, | |
| fillOpacity: 0.5 | |
| }); | |
| if (feature.properties && feature.properties.name) { | |
| marker.bindPopup(feature.properties.name); | |
| } | |
| return marker; | |
| } | |
| }).addTo(map); | |
| }) | |
| ); | |
| // After all layers are loaded | |
| Promise.all(promises).then(() => { | |
| var overlays = { | |
| "Buildings": buildingsLayer, | |
| "Roads": roadsLayer, | |
| "Walkways": walkwaysLayer, | |
| "POIs": poisLayer | |
| }; | |
| L.control.layers(null, overlays).addTo(map); | |
| // Search functionality | |
| let highlightedLayers = { from: null, to: null }; | |
| function clearHighlight(type) { | |
| if (highlightedLayers[type]) { | |
| buildingsLayer.resetStyle(highlightedLayers[type]); | |
| highlightedLayers[type] = null; | |
| } | |
| } | |
| function normalize(s) { return (s || '').toString().toLowerCase().trim(); } | |
| function findBuildingLayerByName(blockName) { | |
| if (!blockName) return null; | |
| let target = null; | |
| const targetNorm = normalize(blockName); | |
| buildingsLayer.eachLayer(function(layer) { | |
| const n = normalize(layer?.feature?.properties?.name); | |
| if (!n) return; | |
| if (n === targetNorm || n.includes(targetNorm) || targetNorm.includes(n)) { | |
| target = layer; | |
| } | |
| }); | |
| return target; | |
| } | |
| function zoomToSelection(fromName, toName) { | |
| const fromLayer = findBuildingLayerByName(fromName); | |
| const toLayer = findBuildingLayerByName(toName); | |
| if (fromLayer && toLayer) { | |
| clearHighlight('from'); | |
| clearHighlight('to'); | |
| // Highlight from location | |
| highlightedLayers.from = fromLayer; | |
| fromLayer.setStyle({ color: '#ff7800', weight: 3, fillColor: '#ffd27f', fillOpacity: 0.6 }); | |
| // Highlight to location | |
| highlightedLayers.to = toLayer; | |
| toLayer.setStyle({ color: '#4CAF50', weight: 3, fillColor: '#8BC34A', fillOpacity: 0.6 }); | |
| // Fit both locations in view | |
| const bounds = L.latLngBounds([fromLayer.getBounds(), toLayer.getBounds()]); | |
| map.fitBounds(bounds, { padding: [50, 50] }); | |
| // TODO: Add path finding logic here using walkwaysLayer | |
| } else { | |
| alert('Could not find one or both locations'); | |
| } | |
| } | |
| // Handle search and suggestions | |
| let activeSearch = null; | |
| const sug = document.getElementById('suggestions'); | |
| function renderSuggestions(items, inputId) { | |
| sug.innerHTML = ''; | |
| if (!items.length) { sug.style.display = 'none'; return; } | |
| items.forEach(item => { | |
| const div = document.createElement('div'); | |
| div.className = 'item'; | |
| const blockName = (item.type === 'block') ? item.name : (blockMap.get(item.block_id) || ''); | |
| const label = (item.type === 'block') ? item.name : `${item.room_name} — ${blockName}`; | |
| div.textContent = label; | |
| div.dataset.blockName = blockName; | |
| div.onclick = () => { | |
| sug.style.display = 'none'; | |
| document.getElementById(inputId).value = label; | |
| const layer = findBuildingLayerByName(blockName); | |
| if (layer) { | |
| map.fitBounds(layer.getBounds(), { padding: [20, 20] }); | |
| } | |
| }; | |
| sug.appendChild(div); | |
| }); | |
| sug.style.display = 'block'; | |
| } | |
| // Event listeners for search inputs | |
| document.getElementById('fromSearch').addEventListener('input', function() { | |
| const q = this.value.trim(); | |
| if (q.length < 1) { sug.style.display = 'none'; return; } | |
| activeSearch = 'fromSearch'; | |
| fetch(`/search?q=${encodeURIComponent(q)}`) | |
| .then(res => res.json()) | |
| .then(results => renderSuggestions(results, 'fromSearch')) | |
| .catch(() => { sug.style.display = 'none'; }); | |
| }); | |
| document.getElementById('toSearch').addEventListener('input', function() { | |
| const q = this.value.trim(); | |
| if (q.length < 1) { sug.style.display = 'none'; return; } | |
| activeSearch = 'toSearch'; | |
| fetch(`/search?q=${encodeURIComponent(q)}`) | |
| .then(res => res.json()) | |
| .then(results => renderSuggestions(results, 'toSearch')) | |
| .catch(() => { sug.style.display = 'none'; }); | |
| }); | |
| // Find path button | |
| document.getElementById('findPathBtn').addEventListener('click', function() { | |
| const from = document.getElementById('fromSearch').value; | |
| const to = document.getElementById('toSearch').value; | |
| if (!from || !to) { | |
| alert('Please select both starting point and destination'); | |
| return; | |
| } | |
| // Extract building names (removing room numbers if present) | |
| const fromBuilding = from.split('—')[0].trim(); | |
| const toBuilding = to.split('—')[0].trim(); | |
| zoomToSelection(fromBuilding, toBuilding); | |
| }); | |
| // Hide suggestions when clicking outside | |
| document.addEventListener('click', (e) => { | |
| if (!document.getElementById('search-container').contains(e.target)) { | |
| sug.style.display = 'none'; | |
| } | |
| }); | |
| // Handle suggestion clicks | |
| sug.addEventListener('click', function(e) { | |
| if (e.target.classList.contains('item') && e.target.dataset.blockName && activeSearch) { | |
| document.getElementById(activeSearch).value = e.target.textContent; | |
| sug.style.display = 'none'; | |
| } | |
| }); | |
| }); | |
| ``` | |
| These changes will: | |
| 1. Replace the single search box with two search bars for "from" and "to" locations | |
| 2. Add labels and a "Find Path" button | |
| 3. Style the new elements to match the existing design | |
| 4. Update the JavaScript to handle both search inputs and path finding | |
| 5. Keep all the existing map functionality while adding the new features |