I have the code below that shows the surface area of a building in OpenStreetMap when hovered. Here's the code:
import { useState, useEffect, useRef, useCallback } from 'react';
import axios from 'axios';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import * as turf from '@turf/turf';
const debounce = (func: any, wait: any) => {
let timeout: any;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
const MapComponent = () => {
const [area, setArea] = useState(0);
const [mousePosition, setMousePosition] = useState({ lat: 0, lon: 0 });
const mapRef = useRef(null);
// Initialize the map
useEffect(() => {
if (!mapRef.current) {
const map = L.map('map').setView([59.132659900251944, 9.727169813491393], 18);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
map.on('mousemove', (e) => {
setMousePosition({ lat: e.latlng.lat, lon: e.latlng.lng });
});
mapRef.current = map;
}
}, []);
const displayBuildings = useCallback((buildingData) => {
if (buildingData && mapRef.current) {
mapRef.current.eachLayer((layer) => {
if (layer instanceof L.Polygon) {
mapRef.current.removeLayer(layer);
}
});
let totalArea = 0;
const nodeMapping = {};
buildingData.elements.forEach(element => {
if (element.type === 'node') {
nodeMapping[element.id] = { lat: element.lat, lon: element.lon };
}
});
const features = buildingData.elements.filter(element => element.type === 'way');
features.forEach(feature => {
if (feature.nodes && feature.nodes.length > 0) {
const coordinates = feature.nodes.map(nodeId => {
const node = nodeMapping[nodeId];
return [node.lat, node.lon]; // Lon, Lat format for Leaflet
});
if (coordinates.length > 0) {
L.polygon(coordinates, { color: 'blue' }).addTo(mapRef.current);
const geoJsonPolygon = {
type: 'Polygon',
coordinates: [coordinates],
};
totalArea += turf.area(geoJsonPolygon);
}
}
});
setArea(totalArea);
}
}, []);
// Function to fetch and display building data
const fetchAndDisplayBuildingData = useCallback(async (lat, lon) => {
try {
const response = await axios.post(
'https://overpass-api.de/api/interpreter',
`[out:json];
(
is_in(${lat},${lon});
area._[building];
);
out body; >; out skel qt;`,
{
headers: { 'Content-Type': 'text/plain' }
}
);
displayBuildings(response.data);
} catch (error) {
console.error('Error fetching data:', error);
}
}, [displayBuildings]);
// Debounced version of fetchAndDisplayBuildingData
const debouncedFetchAndDisplay = useCallback(debounce(fetchAndDisplayBuildingData, 100), [
fetchAndDisplayBuildingData
]);
// Handle mouse movement
useEffect(() => {
if (mapRef.current) {
mapRef.current.on('mousemove', (e) => {
setMousePosition({ lat: e.latlng.lat, lon: e.latlng.lng });
debouncedFetchAndDisplay(e.latlng.lat, e.latlng.lng);
});
}
}, [debouncedFetchAndDisplay]);
return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<p style={{ fontSize: '24px', textAlign: 'center' }}>Area: {area.toFixed(2)} square meters</p>
<p style={{ fontSize: '24px', textAlign: 'center' }}>Mouse Position: Latitude: {mousePosition.lat.toFixed(5)}, Longitude: {mousePosition.lon.toFixed(5)}</p>
<div id="map" style={{ height: '420px', width: '420px' }}></div>
</div>
);
};
export default MapComponent;
I want it to be selectable on click and have that value then saved. Multiple buildings need to be saved. In addition, is there a way to get the roof angle data as well?
I need the angle data as I need to calculate the true area of the roof of a building, not just the space it occupies on a 2D map. This specific true area value needs to then be saved.
How can I fix this?
Is there a way to get the roof angle data as well? No, I can't find the solution. I check Overpass documentation, There are no angle of building or roof data.
This demo can handle Multiple buildings save data by mouse click over the build area.
Save format example
Adding feature Tags and shows all of saved build information by Clicking.
Call this call back function from map's
<div>tag byonClick()event.Getting Tags information from Overpass API
Data source from
OverpassDemo code
Result