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

如何在Mapbox世界地图上渲染六边形(React Native犯罪率应用)

实现Mapbox六边形犯罪率地图+代码优化方案

一、在Mapbox上渲染H3六边形网格

要实现覆盖全球的六边形网格并关联犯罪数据,用Uber H3是最直接的方案,步骤如下:

  1. 安装依赖
    先装H3库(你已经安装了@rnmapbox/maps):
npm install h3-js
# 或
yarn add h3-js
  1. 生成H3六边形网格
    H3用分辨率(0-15,数值越大六边形越小)控制网格精度。可以根据地图当前视野的边界生成对应网格,比如先针对伦敦区域生成分辨率为6的六边形:
import { polyfill, h3ToGeoBoundary } from 'h3-js';

// 伦敦大致边界的GeoJSON多边形坐标
const londonBounds = [
  [-0.510375, 51.286760],
  [0.334015, 51.286760],
  [0.334015, 51.691874],
  [-0.510375, 51.691874],
  [-0.510375, 51.286760]
];

// 生成H3网格索引数组(分辨率6)
const h3Indexes = polyfill(londonBounds, 6, true);
  1. 转换为GeoJSON格式
    Mapbox需要GeoJSON数据渲染图层,把H3索引转成多边形:
// 把H3索引数组转成GeoJSON FeatureCollection
const h3GeoJSON = {
  type: 'FeatureCollection',
  features: h3Indexes.map(index => ({
    type: 'Feature',
    properties: { h3Index: index },
    geometry: {
      type: 'Polygon',
      coordinates: [h3ToGeoBoundary(index, true)] // true表示返回WGS84坐标
    }
  }))
};
  1. 在Mapbox中渲染六边形
    用ShapeSource加载GeoJSON,再用FillLayer渲染填充样式,后续可根据犯罪率动态调整颜色:
<MapboxGL.MapView style={styles.map}>
  {/* 加载H3网格数据源 */}
  <MapboxGL.ShapeSource id="h3-source" shape={h3GeoJSON}>
    {/* 渲染六边形填充层 */}
    <MapboxGL.FillLayer
      id="h3-fill"
      style={{
        fillColor: '#4287f5',
        fillOpacity: 0.5,
        fillOutlineColor: '#ffffff'
      }}
    />
  </MapboxGL.ShapeSource>
</MapboxGL.MapView>

二、现有React Native代码的优化方向

1. 简化视图层级

当前page和container嵌套完全可以合并,减少不必要的View:

// 修改后返回部分
return (
  <View style={styles.page}>
    <MapboxGL.MapView style={styles.map} />
  </View>
);

// 样式简化
const styles = StyleSheet.create({
  page: {
    flex: 1,
  },
  map: {
    flex: 1,
  },
});

2. 地图初始化优化

添加初始中心坐标、缩放级别,以及加载状态提示:

const App = () => {
  const [mapLoaded, setMapLoaded] = useState(false);

  return (
    <View style={styles.page}>
      {!mapLoaded && <Text>加载地图中...</Text>}
      <MapboxGL.MapView
        style={styles.map}
        onMapLoaded={() => setMapLoaded(true)}
        initialCameraPosition={{
          center: [-0.1276, 51.5074], // 伦敦坐标
          zoomLevel: 10,
        }}
      />
    </View>
  );
};

3. 性能优化

  • 按需生成网格:监听地图onRegionDidChangeComplete事件,根据当前视野和缩放级别调整H3分辨率(比如缩放级别高时用更高分辨率),只生成当前视野内的六边形,避免一次性加载全球数据。
  • 缓存GeoJSON:用useMemo缓存生成的GeoJSON数据,防止每次组件渲染重复计算:
const h3GeoJSON = useMemo(() => {
  // 这里是生成GeoJSON的逻辑
}, [mapRegion, h3Resolution]);

4. 错误处理与用户体验

添加地图加载失败的回调,处理token无效等情况:

<MapboxGL.MapView
  // ...其他属性
  onMapLoadingError={(error) => {
    console.error('地图加载失败:', error);
    // 提示用户检查token或网络
  }}
/>

5. 后续扩展优化

接入Met Police数据后,用useState或useReducer管理犯罪数据状态,根据每个六边形的H3索引匹配对应犯罪率,动态修改FillLayer的填充颜色(比如用fillColor表达式实现颜色分级)。

完整示例代码

import React, { useState, useMemo } from "react";
import { StyleSheet, View, Text } from "react-native";
import MapboxGL from "@rnmapbox/maps";
import { polyfill, h3ToGeoBoundary } from 'h3-js';

MapboxGL.setAccessToken("<ACCESS-TOKEN-HERE>");

const App = () => {
  const [mapLoaded, setMapLoaded] = useState(false);
  const [mapRegion, setMapRegion] = useState({
    center: [-0.1276, 51.5074],
    zoomLevel: 10,
  });

  // 用useMemo缓存H3 GeoJSON
  const h3GeoJSON = useMemo(() => {
    // 简化:用当前地图中心生成一个小范围的六边形网格
    const bounds = [
      [mapRegion.center[0] - 0.2, mapRegion.center[1] - 0.2],
      [mapRegion.center[0] + 0.2, mapRegion.center[1] - 0.2],
      [mapRegion.center[0] + 0.2, mapRegion.center[1] + 0.2],
      [mapRegion.center[0] - 0.2, mapRegion.center[1] + 0.2],
      [mapRegion.center[0] - 0.2, mapRegion.center[1] - 0.2],
    ];
    const h3Indexes = polyfill(bounds, 6, true);
    return {
      type: 'FeatureCollection',
      features: h3Indexes.map(index => ({
        type: 'Feature',
        properties: { h3Index: index },
        geometry: {
          type: 'Polygon',
          coordinates: [h3ToGeoBoundary(index, true)]
        }
      }))
    };
  }, [mapRegion]);

  return (
    <View style={styles.page}>
      {!mapLoaded && (
        <View style={styles.loadingOverlay}>
          <Text>加载地图中...</Text>
        </View>
      )}
      <MapboxGL.MapView
        style={styles.map}
        onMapLoaded={() => setMapLoaded(true)}
        initialCameraPosition={mapRegion}
        onRegionDidChangeComplete={(newRegion) => setMapRegion(newRegion)}
        onMapLoadingError={(error) => console.error('地图加载失败:', error)}
      >
        <MapboxGL.ShapeSource id="h3-source" shape={h3GeoJSON}>
          <MapboxGL.FillLayer
            id="h3-fill"
            style={{
              fillColor: '#4287f5',
              fillOpacity: 0.5,
              fillOutlineColor: '#ffffff'
            }}
          />
        </MapboxGL.ShapeSource>
      </MapboxGL.MapView>
    </View>
  );
};

export default App;

const styles = StyleSheet.create({
  page: {
    flex: 1,
  },
  map: {
    flex: 1,
  },
  loadingOverlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(255,255,255,0.8)',
  },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:31:12