主要介绍了 HTML5 原生地图定位、百度地图定位的使用,也说明了 GPS 定位、ip 地址定位、基站定位、wifi 定位,分析了地图定位不准的原因
1. HTML5 原生地图定位
HTML5 原生地图定位通过geolocation
实现,具体 API 使用可以查看官网:Geolocation API
用来获取设备当前位置:navigator.geolocation.getCurrentPosition(success, error, options)
js
export function getLocalPosition() {
return new Promise((resolved, rejected) => {
// 检查浏览器是否支持地理位置功能
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
// 1. 成功的回调处理:
(position) => {
// 获取的gps位置(经纬度),需要转为地图对应坐标
let lat = position.coords.latitude;
let lng = position.coords.longitude;
// 转为百度坐标
const pointBak = new BMap.Point(lng, lat); // 使用经纬度创建百度地图的坐标点
const convertor = new BMap.Convertor(); // 创建百度地图的坐标转换器
convertor.translate([pointBak], 1, 5, (resPoint) => {
if (
resPoint &&
resPoint.status === 0 &&
resPoint.points &&
resPoint.points.length
) {
// 坐标转换成功,更新经度和纬度为转换后的坐标
lng = resPoint.points[0].lng;
lat = resPoint.points[0].lat;
resolved(resPoint.points[0]);
} else {
rejected("坐标转化失败");
}
});
},
// 2. 失败的回调处理
(err) => {
let errMsg = "";
switch (err.code) {
case err.PERMISSION_DENIED:
errMsg = "未开启获取位置信息的权限";
break;
case err.POSITION_UNAVAILABLE:
errMsg = "获取位置信息出错";
break;
case err.TIMEOUT:
errMsg = "获取位置信息超时";
break;
default:
errMsg = "获取位置时发生未知错误";
break;
}
rejected(errMsg);
},
// 3. 可选参数配置
{
timeout: 5000, // 超时时长
enableHighAccuracy: true, // 设置为高精度定位
maximumAge: 0, // 可接受返回的可能缓存位置的最大期限
}
);
} else {
rejected("当前浏览器不支持html5定位");
}
});
}
2. 百度地图定位
百度地图定位,具体可查看官网教程:JavaScript API v2.0 之定位
js
export function getBaiduPosition() {
return new Promise((resolved, rejected) => {
// 获取地址文字信息
const geolocation = new BMap.Geolocation();
// 浏览器定位:优先调用浏览器H5定位接口,如果失败会调用IP定位
geolocation.getCurrentPosition(
(data) => {
if (data) {
resolved(data);
} else {
rejected("获取位置信息失败");
}
},
{ enableHighAccuracy: true }
);
});
}
3. 地图定位组件
使用的是@uiw/react-baidu-map,基于 React 封装的百度地图组件
ts
import { Marker, Map, GeolocationControl, Circle } from "@uiw/react-baidu-map";
function map(props: iProps) {
const [position, setPosition] = useState({ lng, lat })
// 地图全部加载完毕
function mapLoaded() {
// 获取当前坐标
getBaiduPosition()
.then(points => {
// 获取当前位置经纬度
const lng = points.longitude || points.lng
const lat = points.latitude || points.lat
const point = new BMap.Point(lng, lat)
// 获取当前位置
const geo = new BMap.Geocoder()
geo.getLocation(point, data => {
// 获取详细地址信息
const { address, surroundingPois } = data
setAddress(address)
const detail = surroundingPois[0]?.title || '' // 详细地址不存在 则置为空
setAddressMesDetail(detail)
})
})
}
// 手动定位
function locationManual(result: any) {
const { point } = result
// 设置地址坐标
setPosition(point)
}
return (
<>
<Map
zoom={15}
center={position}
onTilesLoaded={mapLoaded}
enableDragging={false}
enablePinchToZoom={false}
enableScrollWheelZoom={false}
enableMapClick={false}
enableDoubleClickZoom={false}
>
<Marker icon={icon} animation={2} position={position} />
<Circle
radius={400}
enableEditing={false}
strokeOpacity={0.3}
strokeWeight={1}
strokeColor="#BBDEFF"
fillColor="#BBDEFF"
fillOpacity={0.5}
center={position}
/>
{previewInfo ? (
<></>
) : (
// 定位不准时,可以手动定位处理
<GeolocationControl
enableAutoLocation={true}
offset={new BMap.Size(20, 70)}
anchor={BMAP_ANCHOR_BOTTOM_RIGHT}
onLocationSuccess={locationManual}
onLocationError={(StatusCode) => {
Toast.fail(`定位失败, ${StatusCode}`, 2);
}}
/>
)}
</>
</>
);
}
export default map;
4. 定位分类
-
- GPS 定位:全球定位系统,通过卫星位置和设备距离计算设备位置
- 优点:精度高
- 缺点:在室内时,讯号会被阻挡,所以室内 GPS 定位不准
-
- ip 地址定位:根据联网设备的 ip,通过查到数据库,可以粗略地知道这个 ip 所在的地理位置。
- 缺点:靠的是大量的信息收集,而不是直接确定用户当前位置
-
- 基站定位:基站是能进行信号交换的站点。基站位置是已知的,根据手机接收基站信号强度计算位置
- 缺点:手机必须处于 SIM 卡注册状态下。受信号干扰和基站密度影响,精度较低
-
- wifi 定位:记录 WiFi 信号和设备位置,通过算法确定位置,解决室内定位问题
- 缺点:当某个 WiFi 搬家后,数据库没有及时更新,就会出现定位不准的问题
5. 地图定位不准分析
浏览器定位实际上都是使用了 HTML5 的 Geolocation 功能,但不是那么好用,由于科学上网的限制,国内的手机"阉割"了谷歌 GMS 服务包,导致 HTML5 的 geolocation 无法使用 wifi 和基站定位服务,所以经常会定位失败。
当然,我们也可以用其他的厂商,如百度、高德、搜狗等,他们的策略是如下:
浏览器原生定位接口定位失败后,系统会调用 IP 定位
,返回定位点所在城市中心点
。此时,定位精度范围返回"null"。
最终解决方案是:配置好百度或高德的 SDK,使用 HTML5+API 的 geolocation.getCurrentPosition()利用原生定位获取到坐标点后,再用百度或高德的 JS API 去实现其他的地图模块功能。