生成指定辖区内随机点

在 web 地图开发过程中可能需要根据某一个区域生成一些随机点用来做测试。

之前在某个网站有这个功能是借助百度地图相关 api 来实现的,那我们不借助这些地图厂商的 api 可以实现吗?答案是可以的。

在线体验地址: leaflet-gaode.netlify.app/

仓库地址: github.com/leafletjsEx...

要实现什么?

实现的内容如下图:选择辖区、输入生成点位数量后点击"生成点位" 会移动到辖区中心点并在辖区范围内生成一定数量的随机点(因为需要过滤掉不在辖区内的的点位实际加载的点位数量会小于输入框的数量)。

分解下任务

  1. 获取辖区数据即省市区三级联动数据
  2. 获取区域的中心点、区域边界框
  3. 判断点位是否在指定区域内
  4. 生成随机点
  5. 加载到地图

获取辖区数据即省市区三级联动数据

这个数据是从 datav 这个网站获取的。

获取的数据是一维数据手动处理成了省市区三级联动数据点击获取。

获取区域的中心点、边界框

上边通过 datav 获取的数据中已经包含了区域边界框、中心点。

你可能会好奇如果没有怎么计算呢?

使用 turfjs 执行 pnpm i @turf/turf 安装依赖

Turf.js 是一个用于地理空间分析和处理的 JavaScript 库。它提供了一系列功能强大且易于使用的工具,用于处理地理空间数据、执行地理空间分析以及生成地理空间几何对象等操作。

根据范围获取边界框

bbox方法接收一个 geojson 类型的参数

js 复制代码
import {bbox as turfBbox} from '@turf/turf'

const getBbox = async () => {  
// 获取 datav 区域边界 geojson
const data = await fetch('https://geo.datav.aliyun.com/areas_v3/bound/371500.json').then(res => res.json())  

// 输出四个顶点坐标数组 [115.271447, 35.779921,116.549533,37.032217]
console.log(turfBbox(data));   
}

线上 github、netlify 等部署后无法访问 datav geojson 数据(403)使用 aircode写接口代理一层。

js 复制代码
// @see https://docs.aircode.io/guide/functions/
const aircode = require('aircode');

module.exports = async function (params, context) {
  const areaCode = params.areaCode
  if (!areaCode) {
    return {
      msg: 'areaCode 不能为空'
    }
  }
  
  const url = `https://geo.datav.aliyun.com/areas_v3/bound/${areaCode}.json`

  return await fetch(url).then(res => res.json())
};

// 访问如下接口传递 区域 code 获取数据
const areaData = await fetch(`https://36dvjmmx39.us.aircode.run/index?areaCode=${code}`).then(res => res.json())

非 geojson 类型的数据使用 polygon 方法转换为 gepjson 在进行上边的操作

js 复制代码
import { polygon , bbox} from '@turf/turf'

// 创建一个表示区域范围的多边形
const polygon = polygon([[
  [0, 0],
  [0, 10],
  [10, 10],
  [10, 0],
  [0, 0]
]]);

// 计算多边形的边界框
const bbox = bbox(polygon);

console.log(bbox); // 返回一个表示边界框的数组 [minX, minY, maxX, maxY]

生成随机点

随机点是根据边界框来计算生成逻辑比较简单

js 复制代码
const generateRandomPointInBoundingBox = (bbox) => {  
    const [minX, minY, maxX, maxY] = bbox;  
    const randomX = Math.random() * (maxX - minX) + minX;  
    const randomY = Math.random() * (maxY - minY) + minY;  
    
    // 坐标点
    return [randomX, randomY];  
}

判断点位是否在指定区域内

这个需要使用 turfjs 的 booleanPointInPolygon 方法用于判断点是否在多边形内部。接收一个 geojson<Polygon | MultiPolygon> 类型的数据。

区域边界数据从 datav 来获取https://geo.datav.aliyun.com/areas_v3/bound/371500.json 将链接中的 371500 替换成对应的辖区 code 就可以获取到对应的辖区数据(上边获取的省市区数据里包含区域 code)。

js 复制代码
// todo 这里重命名 只是为了防止名称重复
import {  
point as turfPoint,  
multiPolygon as turfMultiPolygon,  
booleanPointInPolygon  
} from '@turf/turf'

// 判断点是否在 geoJson 内  
const isPointInsideFeatureCollection = (featureCollection, pointCoordinates) => {  
  
    // 将点坐标转换为 Turf.js 对象  
    const point = turfPoint(pointCoordinates);  

    // 遍历 FeatureCollection 中的每个 Feature  
    for (const feature of featureCollection.features) {  
    const multiPolygon = turfMultiPolygon(feature.geometry.coordinates);  
    const isPointInsidePolygon = booleanPointInPolygon(point, multiPolygon);  

    if (isPointInsidePolygon) {  
    return true; // 如果点在任何一个 Feature 内,返回 true  
    }  
    }  

    return false; // 如果点不在任何一个 Feature 内,返回 false  
}

生成随机点

这个逻辑也比较简单根据输入的生成数量执行 for 循环生成随机点然后判断是否在区域范围内,在的话就添加到数组。

js 复制代码
const pointArr = ref([]);
  
// num 由参数传入
for (let i = 0; i < num; i++) {  
    // 生成随机点
    const point = generateRandomPointInBoundingBox(areaInfo.bbox);  

    // 判断点是否在区域范围内
    const isInside = isPointInsideFeatureCollection(areaData, point);  

    // 添加到数组中
    if (isInside) {  
        pointArr.value.push(point)  
    }  
}

将点位添加到地图

作者使用的是 leafletjs 所以就以此为例,创建地图的过程就省略了。

js 复制代码
const pointArr = ref([]);  
const markerList = ref([]);  
  
const clearAllMarker = () => {  
markerList.value.map((item) => {  
    item.remove();  
    return item;  
    });  
    markerList.value = [];  
};  
  
// 获取 marker icon  
const getMarkerIcon = () => {  
    return L.icon({  
        iconUrl: point_icon,  
        iconSize: [40, 40],  
    });  
};  
  
const markersLayerGroup = ref();  

const addMarkerToMap = () => {  
    clearAllMarker()  

    // 图曾存在先清除  
    if (markersLayerGroup.value) {  
    mapObj.value.removeLayer(markersLayerGroup.value);  
    }  

    // 创建图层组 聚合图层 leaflet.markercluster 插件  
    markersLayerGroup.value = L.markerClusterGroup({  
        chunkedLoading: true,  
        showCoverageOnHover: false,  
    });  

    // 向图层添加数据  
    pointArr.value.map((item) => {  
        markersLayerGroup.value.addLayer(  
            L.marker(item.reverse(), {icon: getMarkerIcon()}), 
        );  
    });  

    // 将图层组加载到地图  
    mapObj.value.addLayer(markersLayerGroup.value);  
};

最终效果

总结

本文介绍了如何根据辖区范围生成随机点及 turfjs 的简单使用。

完整示例请查看 git 仓库: github.com/leafletjsEx...

往期文章

相关推荐
YWL8 分钟前
OpenLayers测距测面:完整测量工具
前端·javascript·vue.js·信息可视化·openlayers
zhanghaha131417 分钟前
HTML系列教程:2_HTML 编辑器(零基础超详细讲解
前端·编辑器·html
半旧51821 分钟前
【Java Web02】WEB服务器内部实现技术揭秘
java·服务器·前端
微学AI28 分钟前
把 GitHub Issue 的“第一轮脏活”交给 AI:Issue AI Agent 接入蓝耘元生代实战
人工智能·github·issue
拿本唠嗑AI研究30 分钟前
现代前端架构爬虫指南:从静态页面到 React/Vue 单页应用
前端·爬虫·架构
独孤九剑打醒他1 小时前
【原创开源】双层Master‑Worker软硬协同调度架构:从根源解决分布式数据一致性难题
前端·嵌入式硬件·架构·前端框架·硬件工程
阳墨余2 小时前
Git 同时管理 Gitee 和 GitHub 的 SSH 配置实战
git·gitee·github
程序员黑豆7 小时前
Java包装类:基本类型与对象的桥梁
java·前端·ai编程
bugcome_com9 小时前
JWT 知识小课堂:从入门到精通,一文吃透 JSON Web Token
前端·json
小弥儿9 小时前
GitHub今日热榜 | 2026-08-16:大模型微调与编码工具扎堆
学习·开源·github