You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Overpass API端点问题以实现建筑面积计算与地图展示?

修复方案

你的问题核心是没有向Overpass API发送有效的查询语句,直接请求https://api.openstreetmap.org/api/interpreter不会返回任何建筑数据,导致buildingData一直为空,进而面积计算为0,地图也无法正常初始化。以下是具体修复步骤:

1. 构造有效的Overpass API查询

Overpass API需要你提供Overpass QL查询语句来获取指定的地理数据。比如要获取你指定坐标附近的建筑,可以用如下查询:

[out:json][timeout:25];
(
  way["building"](59.12,9.71,59.14,9.74);
);
out body;
>;
out skel qt;

这个查询会返回坐标范围(59.12,9.71)到(59.14,9.74)内的所有建筑数据,格式为OSM原生结构,后续需要转成GeoJSON。

正确的API请求方式

使用GET请求时,需要将查询语句作为data参数传递:

const response = await axios.get('https://api.openstreetmap.org/api/interpreter', {
  params: {
    data: '[out:json][timeout:25];(way["building"](59.12,9.71,59.14,9.74););out body;>;out skel qt;'
  }
});

2. 修复组件逻辑问题

  • 避免重复创建地图:地图应该在数据加载完成后初始化一次,而不是每次计算面积都重新创建。
  • 处理异步数据:初始状态下buildingData为null,必须等待数据加载完成后再执行地图初始化和面积计算。
  • 转换OSM数据为GeoJSON:Overpass返回的是OSM原生格式,需要转成标准GeoJSON才能被turf和Leaflet正常识别。

修改后的完整代码

import { useState, useEffect } from 'react';
import axios from 'axios';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import * as turf from '@turf/turf';
import osmtogeojson from 'osmtogeojson'; // 需要安装此包

// 修复Leaflet默认图标路径问题(可替换为本地图标路径)
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
  iconRetinaUrl: '/assets/marker-icon-2x.png',
  iconUrl: '/assets/marker-icon.png',
  shadowUrl: '/assets/marker-shadow.png',
});

const MapComponent = () => {
  const [buildingData, setBuildingData] = useState(null);
  const [area, setArea] = useState(0);
  const [map, setMap] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        // 构造Overpass QL查询
        const overpassQuery = `[out:json][timeout:25];(way["building"](59.12,9.71,59.14,9.74););out body;>;out skel qt;`;
        const response = await axios.get('https://api.openstreetmap.org/api/interpreter', {
          params: { data: overpassQuery }
        });
        
        // 将OSM数据转换为标准GeoJSON
        const geoJsonData = osmtogeojson(response.data);
        setBuildingData(geoJsonData);
      } catch (error) {
        console.error('获取数据失败:', error);
      }
    };

    fetchData();
  }, []);

  // 初始化地图并计算面积
  useEffect(() => {
    if (!buildingData || buildingData.features.length === 0) return;

    // 仅初始化一次地图
    if (!map) {
      const newMap = L.map('map').setView([59.132659900251944, 9.727169813491393], 16);
      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
      }).addTo(newMap);
      setMap(newMap);
    }

    // 计算第一个建筑的表面积
    const firstBuilding = buildingData.features[0];
    if (firstBuilding.geometry.type === 'Polygon') {
      const calculatedArea = turf.area(firstBuilding);
      setArea(calculatedArea);

      // 将建筑多边形添加到地图
      const leafletCoords = firstBuilding.geometry.coordinates[0].map(([lon, lat]) => [lat, lon]);
      L.polygon(leafletCoords, { color: 'red' }).addTo(map);
    }
  }, [buildingData, map]);

  return (
    <div style={{ width: "100%", height: "100vh", display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column" }}>
      <p>表面积: {area.toFixed(2)} 平方米</p>
      <div id="map" style={{ height: '500px', width: '500px', border: "3.2px solid red" }}></div>
    </div>
  );
};

export default MapComponent;

额外说明

  • 执行npm install osmtogeojson安装数据转换依赖包
  • 地图初始化和面积计算逻辑拆分到独立的useEffect中,确保只在数据加载完成后执行
  • 对面积结果做了保留两位小数的格式化,提升可读性

内容的提问来源于stack exchange,提问作者David Guri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:12:32