地图应用开发中,搜索功能是绕不开的话题。用户想找个地方、定位个坐标、或者输入时来点智能提示——这些看似简单的需求,背后都需要地图检索服务来支撑。
好消息是,MapV-Three框架已经把这些服务封装得明明白白了。今天我们就来聊聊三个核心API:LocalSearch、Geocoder、AutoComplete。掌握它们,基本就能应对大部分地图搜索场景。
先搞清楚它们各自能干啥:
核心能力:根据关键词在指定区域内搜索地点信息,返回匹配的POI列表。
适用场景:
支持的服务源:百度地图、天地图
核心能力:实现地址与坐标之间的双向转换。
适用场景:
支持的服务源:百度地图、天地图
核心能力:用户输入关键词时实时返回候选地点列表。
适用场景:
支持的服务源:仅支持百度地图
了解完基础概念,接下来看看怎么用。
先看最常用的功能——根据关键词搜索地点。
import {useRef} from 'react';
import * as mapvthree from '@baidu/mapv-three';
const ref = useRef();
const center = [116, 40];
async function callback(engine) {
// 创建本地搜索服务实例
const localSearch = new mapvthree.services.LocalSearch({
renderOptions: {
engine,
autoViewport: true, // 自动调整视野范围
},
pageNum: 0, // 分页参数
});
// 执行搜索
localSearch.search('北京大学').then(result => {
console.log('搜索结果:', result);
});
return engine;
}
<App ref={ref} initConfig={{
map: {
center: center,
range: 10000,
provider: new mapvthree.BaiduVectorTileProvider(),
},
rendering: {
enableAnimationLoop: true,
}
}} callback={callback} />关键配置说明:
autoViewport: true:搜索完成后,地图会自动调整视野到搜索结果位置pageNum: 0:控制分页,0表示返回第一页结果renderOptions 中传入 engine 实例,服务会自动在地图上渲染搜索结果这段代码运行后,地图会自动飞到"北京大学"的位置并显示标注。相当省心。
如果项目需要使用天地图服务,只需在创建实例前设置API源:
async function callback(engine) {
// 设置API服务源
mapvthree.services.setApiSource(mapvthree.services.API_SOURCE_TIANDITU);
// 创建本地搜索服务实例
const localSearch = new mapvthree.services.LocalSearch({
renderOptions: {
engine,
autoViewport: true,
},
pageNum: 0,
});
// 执行搜索
localSearch.search('北京大学').then(result => {
console.log('搜索结果:', result);
});
const mapView = engine.add(new mapvthree.MapView({
imageryProvider: new mapvthree.TiandituImageryTileProvider()
}));
return engine;
}注意事项:
setApiSource()TiandituImageryTileProvider)很多时候,我们需要在地址和坐标之间进行转换。Geocoder就是干这个的。
将地址字符串转换为经纬度坐标:
import {useRef} from 'react';
import * as mapvthree from '@baidu/mapv-three';
const ref = useRef();
const center = [116.403414, 39.924091];
async function callback(engine) {
// 创建地理编码服务实例
const geocoder = new mapvthree.services.Geocoder();
// 地理编码:地址转坐标
geocoder.getPoint('故宫博物院', (point, detailInfo) => {
if (point) {
const labelItem = engine.rendering.label.addLabel({
text: detailInfo.address,
position: [point.x, point.y],
mapSrc: 'assets/images/marker/libarary.png',
iconSize: [60, 60],
textFillStyle: '#000000',
textStrokeStyle: '#ffffff',
textStrokeWidth: 2,
textAnchor: 'left',
});
}
}).then(res => {
console.log('Promise 结果:', res);
});
const mapView = engine.add(new mapvthree.MapView({
terrainProvider: null,
vectorProvider: new mapvthree.BaiduVectorTileProvider({
displayOptions: {
poi: false,
}
})
}));
return engine;
}这个API提供了两种使用方式:
.then() 链式调用两种方式都可以,看个人习惯。回调函数适合简单场景,Promise适合需要错误处理或链式调用的复杂场景。
将坐标转换为详细地址信息:
import {useRef} from 'react';
import * as mapvthree from '@baidu/mapv-three';
const ref = useRef();
const center = [116.28069, 40.050241];
async function callback(engine) {
// 创建地理编码服务实例
const geocoder = new mapvthree.services.Geocoder();
const targetPoint = center;
// 逆地理编码:坐标转地址
geocoder.getLocation(targetPoint, (geocoderResult) => {
if (geocoderResult && geocoderResult.address) {
engine.rendering.label.addLabel({
text: geocoderResult.address,
position: targetPoint,
textFillStyle: '#ff0000',
textStrokeStyle: '#ffffff',
textStrokeWidth: 2,
})
}
});
const mapView = engine.add(new mapvthree.MapView({
terrainProvider: null,
vectorProvider: new mapvthree.BaiduVectorTileProvider({
displayOptions: {
poi: false,
}
})
}))
return engine;
}逆向解析常用于地图点击事件的响应。当用户点击地图某个位置时,可以通过逆向解析显示该位置的详细地址。
实用提示:
geocoderResult 包含 address(完整地址)和 addressComponents(省市区等结构化信息)Geocoder同样支持天地图服务:
async function callback(engine) {
// 设置API服务源
mapvthree.services.setApiSource(mapvthree.services.API_SOURCE_TIANDITU);
// 创建地理编码服务实例
const geocoder = new mapvthree.services.Geocoder();
// 地理编码:地址转坐标
geocoder.getPoint('故宫博物院', (point, detailInfo) => {
if (point) {
const labelItem = engine.rendering.label.addLabel({
text: detailInfo.address,
position: [point.x, point.y],
mapSrc: 'assets/images/marker/libarary.png',
iconSize: [60, 60],
textFillStyle: '#000000',
textStrokeStyle: '#ffffff',
textStrokeWidth: 2,
textAnchor: 'left',
});
}
}).then(res => {
console.log('Promise 结果:', res);
});
const mapView = engine.add(new mapvthree.MapView({
imageryProvider: new mapvthree.TiandituImageryTileProvider()
}));
return engine;
}如果想实现类似百度地图那种"边输入边提示"的体验,就需要用到AutoComplete服务。
AutoComplete的使用稍微复杂一些,因为它涉及到UI交互。下面是一个完整的实现:
import React, {useRef, useEffect, useState} from 'react';
import * as mapvthree from '@baidu/mapv-three';
const ref = useRef();
const center = [116.403414, 39.924091];
async function callback(engine) {
const {gui, input, params, setResults, clearResults} = setupGui(ref);
const autoComplete = new mapvthree.services.AutoComplete({
apiSource: mapvthree.services.API_SOURCE_BAIDU,
input
});
const label = addLabel(engine);
autoComplete.addEventListener('searchComplete', e => {
const pois = e.results?.pois || e.results || [];
if (!pois.length) {
clearResults();
return;
}
setResults(pois, (poi) => {
if (!poi.location) {
return;
}
flyTo(engine, poi.location);
updateLabel(label, poi);
});
});
input.addEventListener('input', () => {
if (input.value.trim() === '') {
clearResults();
}
});
return engine;
}
function addLabel(engine) {
const label = engine.add(new mapvthree.Label({
type: 'icontext',
mapSrc: '/mapvthree/assets/images/marker_red.png',
textFillStyle: 'white',
iconWidth: 20,
iconHeight: 20,
textSize: 14,
textStrokeStyle: 'black',
textStrokeWidth: 1,
textAnchor: 'bottom'
}));
const dataSource = mapvthree.GeoJSONDataSource.fromGeoJSON([]);
dataSource.defineAttribute('text', 'name');
label.dataSource = dataSource;
return label;
}
function updateLabel(label, poi) {
if (!poi.location) {
return;
}
label.dataSource.setData([{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [poi.location.x, poi.location.y],
},
properties: {
name: poi.street.trim() || '未命名地点'
}
}]);
}
function flyTo(engine, location) {
engine.map.flyTo(location.toArray(), {
range: 1000,
pitch: 0,
heading: 0
});
}核心流程:
searchComplete 事件,获取搜索结果input 事件,当输入框清空时清除候选列表几个要点:
searchComplete 事件会在每次输入变化后触发AutoComplete在用户快速输入时会频繁触发请求,建议添加防抖:
function debounce(func, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), delay);
};
}
// 在实际项目中,可以对搜索逻辑进行防抖处理
const debouncedSearch = debounce(() => {
// 搜索逻辑
}, 300);地图服务可能因为网络、API限制等原因失败,务必做好错误处理:
localSearch.search('关键词')
.then(result => {
if (!result || !result.pois || result.pois.length === 0) {
console.log('未找到匹配结果');
return;
}
// 处理结果
})
.catch(error => {
console.error('搜索失败:', error);
// 显示错误提示
});当搜索结果较多时,使用GeoJSON批量添加标注比逐个添加性能更好:
const features = pois.map(poi => ({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [poi.location.lng, poi.location.lat],
},
properties: {
name: poi.name,
}
}));
const dataSource = mapvthree.GeoJSONDataSource.fromGeoJSON(features);
label.dataSource = dataSource;百度地图使用BD-09坐标系,天地图使用GCJ-02坐标系。如果需要在两者之间切换,要注意坐标转换问题。
MapV-Three的三个地图检索服务各有分工:
这三个服务配合使用,基本能覆盖地图应用中90%的搜索需求。而且API设计得相当简洁,上手成本低,性价比很高。
最后提醒几点:
autoViewport: true,让搜索结果自动展示掌握这些,地图搜索功能基本就稳了。
参考资料:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。