我正在try 使用天桥API、OpenStreetMap API、ReactJS来计算建筑的表面积.代码如下:

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 MapComponent = () => {
  const [buildingData, setBuildingData] = useState(null);
  const [area, setArea] = useState(0);
  const mapRef = useRef(null);

  // Initialize the map
  useEffect(() => {
    if (!mapRef.current) {
      mapRef.current = L.map('map').setView([59.132659900251944, 9.727169813491393], 20); // Centered on Paris
      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
      }).addTo(mapRef.current);
    }
  }, []);

  // Fetch building data
  useEffect(() => {
    const fetchData = async () => {
      try {

        const response = await axios.post(
          'https://overpass-api.de/api/interpreter',
          `[out:json];(way["building"](around:3000,59.132659900251944, 9.727169813491393););out body;>;out skel qt;`,
          {
            headers: { 'Content-Type': 'text/plain' }
          }
        );

        setBuildingData(response.data);

      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    fetchData();
  }, []);

  const calculateAndDisplayArea = useCallback(() => {
    if (buildingData && mapRef.current) {
      let totalArea = 0;
      const nodeMapping = {}; // Assuming you have this mapping from node ID to { lat, lon }

      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];
          });

          if (coordinates.length > 0) {
            L.polygon(coordinates).addTo(mapRef.current); // Add polygon to map

            const geoJsonPolygon = {
              type: 'Polygon',
              coordinates: [coordinates.map(coord => [coord[1], coord[0]])], // Convert to [lon, lat]
            };

            totalArea += turf.area(geoJsonPolygon);
          }
        }
      });

      setArea(totalArea);
    }
  }, [buildingData]);


  useEffect(() => {
    calculateAndDisplayArea();
  }, [calculateAndDisplayArea, buildingData]);

  return (
    <div>
      <p>Area: {area.toFixed(2)} square meters</p>
      <div id="map" style={{ height: '800px', width: '1000px', margin: '0 auto' }}></div>
    </div>
  );
};

export default MapComponent;

我只需要得到位于给定坐标下的特定建筑屋顶的面积,但我得到的是周围所有建筑的面积(大约30,000平方米).

我怎么才能解决这个问题呢?

推荐答案

该查询可以获取特定的药剂信息. is_in()

The standalone query is_in returns the areas and closed ways that cover

the given coordinates (when specified) or
one or more nodes from the input set (when no coordinates are specified).

此查询将解决此问题

`[out:json];
  (
    is_in(${lat},${lon});
    area._[building];
  );
  out body; >; out skel qt;`,

我在 map 组件中添加了go 反弹代码.

Debounce是一种在编程中使用的技术,用于延迟(100毫秒)或限制功能或操作的执行,直到自上次触发以来经过一定的时间.它有助于防止对函数的重复或频繁调用,使其更有效,特别是在用户输入处理或API请求等场景中.


const debounce = (func, wait) => {
  let timeout;

  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };

    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};
---
  const debouncedFetchAndDisplay = useCallback(debounce(fetchAndDisplayBuildingData, 100), [
    fetchAndDisplayBuildingData
  ]);

通过使用debounce 的鼠标移动事件显示鼠标位置,意味着只有在最后一次鼠标移动后的短暂延迟后才会触发更新鼠标位置的功能.此延迟有助于防止过度更新,并确保仅在用户短时间内停止移动鼠标时才调用该函数.这是一种根据鼠标移动来优化和控制更新频率的方法,类似于go 抖对其他功能的作用.

map.on('mousemove', (e) => {
  setMousePosition({ lat: e.latlng.lat, lon: e.latlng.lng });
});

此演示代码将显示一个建筑面积

import React, { 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, wait) => {
  let timeout;

  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', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
      }).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: '800px', width: '100%', maxWidth: '1000px' }}></div>
    </div>
  );
};

export default MapComponent;

结果

enter image description here

enter image description here

Reactjs相关问答推荐

sourceBuffer. appendBuffer成功,但h5视频播放器卡住了

无法在jest中发布行动

Redux向后端发送请求时出现钩子问题

下拉Tailwind CSS菜单与怪异beviour

Redux Store未触发React组件中的重新呈现

对搜索引擎优化来说,react 头盔的异步足够了吗?

自定义变量默认、聚焦和填充时所需TextField中标签的星号 colored颜色

如何修复ReferenceError:在构建过程中未定义导航器

React 在第一次渲染时为 null

Symfony ux-react:使用react_component()时React组件不会渲染

如何在next.js 13中仅在主页导航栏上隐藏组件?

redux 工具包使用中间件构建器函数时,必须返回一个中间件数组

onChange in useEffect 的最佳实践

如何在 Next Js 13 App Router 中添加 Favicon 图标?

我应该如何将字符串作为props 传递给 React 组件?

导入样式化组件时未导入组件内容

刷新页面时状态改变问题

Lodash 在命名导入中导入整个包

为什么我在运行一些 npm react 命令时会收到这些警告?

axios post方法中的请求失败,状态码为500错误