在鸿蒙项目里,地图组件 Demo 往往只展示静态标记点,但实际开发经常要动态控制地图:移动到指定位置、缩放视野、让标记点动起来做轨迹回放。这些操作都要通过 MapContext 完成。本文结合一个地图上下文 Demo,整理 has.createMapContext 的常用 API、轨迹回放写法和实际踩坑。
一、初始化 MapContext
先通过地图组件 id 获取上下文:- Page({
- onReady() {
- this.mapCtx = has.createMapContext('myMap');
- }
- });
复制代码 在 onReady 里调用比较稳妥,此时地图组件已经渲染完成。拿到 mapCtx 后,就能调用各种方法控制地图。
二、获取地图信息
获取中心点经纬度:- this.mapCtx.getCenterLocation({
- success: (res) => {
- console.info(`中心点: ${res.latitude}, ${res.longitude}`);
- }
- });
复制代码 返回 gcj02 坐标系经纬度。
获取视野范围:- this.mapCtx.getRegion({
- success: (res) => {
- console.info('西南角:', res.southwest);
- console.info('东北角:', res.northeast);
- }
- });
复制代码 返回西南角和东北角经纬度,可判断点是否在当前视野内。
获取缩放级别、旋转角、倾斜角:- this.mapCtx.getScale({
- success: (res) => { console.info('缩放级别:', res.scale); }
- });
- this.mapCtx.getRotate({
- success: (res) => { console.info('旋转角:', res.rotate); }
- });
- this.mapCtx.getSkew({
- success: (res) => { console.info('倾斜角:', res.skew); }
- });
复制代码 这三个方法用法一致,都是读取地图当前状态参数。
三、移动地图与视野控制
移动到指定位置:- this.mapCtx.moveToLocation({
- longitude: 116.397428,
- latitude: 39.90923,
- success: () => {
- console.info('已移动到天安门');
- }
- });
复制代码 如果不传经纬度,会移动到当前定位点。需要地图组件设置 show-location="true",并且有定位权限。
自动缩放包含所有点:- this.mapCtx.includePoints({
- points: [
- { latitude: 31.984, longitude: 118.766 },
- { latitude: 39.909, longitude: 116.397 },
- { latitude: 31.230, longitude: 121.473 }
- ],
- padding: [50, 50, 50, 50],
- success: () => {
- console.info('已包含所有点');
- }
- });
复制代码 padding 是坐标点形成的矩形到地图边缘的距离,防止点贴着边缘显示。
设置中心偏移:- this.mapCtx.setCenterOffset({
- offset: [0.5, 0.35],
- success: () => {
- console.info('中心偏移已设置');
- }
- });
复制代码 offset 为 [水平, 垂直],范围 0.25~0.75,默认 [0.5, 0.5],改成 [0.5, 0.35] 就是中心点上移。
四、标记动画与轨迹回放
平移标记:- this.mapCtx.translateMarker({
- markerId: 1,
- destination: {
- latitude: 32.0,
- longitude: 118.8
- },
- autoRotate: true,
- duration: 2000,
- animationEnd: () => {
- console.info('平移动画结束');
- }
- });
复制代码 autoRotate 设为 true 后,标记会自动转向移动方向,模拟导航效果。
轨迹回放用 moveAlong,可以让标记沿路径移动,适合行程回放、配送追踪:- const path = [
- { latitude: 31.984, longitude: 118.766 },
- { latitude: 31.986, longitude: 118.767 },
- { latitude: 31.988, longitude: 118.769 },
- { latitude: 31.990, longitude: 118.771 },
- { latitude: 31.992, longitude: 118.774 }
- ];
- this.mapCtx.moveAlong({
- markerId: 1,
- path: path,
- autoRotate: true,
- isMapMoving: true,
- color: '#0A59F7CC',
- width: 6,
- duration: 5000,
- success: () => {
- console.info('轨迹回放开始');
- }
- });
复制代码 isMapMoving 为 true 后,地图视角会跟着标记移动,像导航一样;color 和 width 控制轨迹线样式。
五、经纬度转屏幕坐标
叠加自定义 UI 时,需要知道经纬度对应的屏幕位置:- this.mapCtx.toScreenLocation({
- longitude: 118.766,
- latitude: 31.984,
- success: (res) => {
- console.info(`屏幕坐标: x=${res.x}, y=${res.y}`);
- }
- });
复制代码 注意:ASCF 运行时 2.0.1 之前返回 px 单位,2.0.1 及以上返回 vp 单位。版本差异会影响叠加层定位,做适配时要留意。
六、动态管理标记
添加标记:- this.mapCtx.addMarkers({
- markers: [
- { id: 100, latitude: 31.99, longitude: 118.77, title: '标记A' },
- { id: 101, latitude: 31.98, longitude: 118.76, title: '标记B' }
- ],
- clear: false,
- success: () => {
- console.info('标记添加成功');
- }
- });
复制代码 clear 为 true 会先清空已有标记再添加。
移除标记:- this.mapCtx.removeMarkers({
- markerIds: [100, 101],
- success: () => {
- console.info('标记移除成功');
- }
- });
复制代码
设置定位点图标:- this.mapCtx.setLocMarkerIcon({
- iconPath: '/image/custom_location.png',
- success: () => {
- console.info('定位图标已更换');
- }
- });
复制代码 可自定义当前位置的蓝色圆点图标。
七、Demo 与三个实际场景
项目里新建了一个地图上下文 Demo,在“接口” -> “位置”分类下可以找到“地图上下文”入口。Demo 包含:获取中心点、视野范围、缩放级别;移动到当前位置、天安门;缩放视野包含南京/北京/上海三点;标记平移动画;轨迹回放;动态添加/移除标记。
场景一:门店定位。用户选择城市后展示该城市所有门店,并自动缩放视野包含所有门店:- Page({
- data: {
- markers: []
- },
- onLoad() {
- this.loadStores('南京');
- },
- loadStores(city) {
- const stores = [
- { id: 1, name: '新街口店', lat: 32.039, lon: 118.787 },
- { id: 2, name: '河西店', lat: 32.022, lon: 118.743 },
- { id: 3, name: '江宁店', lat: 31.953, lon: 118.839 }
- ];
- const markers = stores.map(s => ({
- id: s.id,
- latitude: s.lat,
- longitude: s.lon,
- title: s.name,
- callout: { content: s.name, display: 'ALWAYS' }
- }));
- this.setData({ markers });
- this.mapCtx.includePoints({
- points: stores.map(s => ({ latitude: s.lat, longitude: s.lon })),
- padding: [60, 60, 60, 60]
- });
- }
- });
复制代码
场景二:配送员实时位置。外卖或快递场景,配送员位置实时更新,地图跟随移动:- Page({
- data: {
- driverMarker: { id: 999, latitude: 0, longitude: 0 }
- },
- onReady() {
- this.mapCtx = has.createMapContext('deliveryMap');
- this.startTracking();
- },
- startTracking() {
- this.trackingTimer = setInterval(() => {
- const newLat = this.data.driverMarker.latitude + 0.0001;
- const newLon = this.data.driverMarker.longitude + 0.0001;
- this.mapCtx.translateMarker({
- markerId: 999,
- destination: { latitude: newLat, longitude: newLon },
- autoRotate: true,
- duration: 1000
- });
- this.setData({
- 'driverMarker.latitude': newLat,
- 'driverMarker.longitude': newLon
- });
- }, 2000);
- },
- onUnload() {
- clearInterval(this.trackingTimer);
- }
- });
复制代码 这里用 translateMarker 而不是直接更新 markers 数据,可以实现平滑移动动画,避免标记“跳”。
场景三:行程轨迹展示。用户完成一段行程后,在地图上展示轨迹:- Page({
- data: {
- routeMarkers: []
- },
- showTripRoute(routePoints) {
- this.mapCtx.addMarkers({
- clear: true,
- markers: [
- {
- id: 'start',
- latitude: routePoints[0].latitude,
- longitude: routePoints[0].longitude,
- title: '起点',
- callout: { content: '起点', display: 'ALWAYS' }
- },
- {
- id: 'end',
- latitude: routePoints[routePoints.length - 1].latitude,
- longitude: routePoints[routePoints.length - 1].longitude,
- title: '终点',
- callout: { content: '终点', display: 'ALWAYS' }
- }
- ]
- });
- this.mapCtx.includePoints({
- points: routePoints,
- padding: [80, 80, 80, 80]
- });
- }
- });
复制代码
八、踩坑与适配建议
1. moveToLocation 需要定位权限。不传经纬度会移动到当前定位点,但没有权限会走 fail 回调。调用前先检查定位权限,或者传默认经纬度兜底。
2. moveAlong 的 duration 最小值是 100ms。如果传小于 100,会被设为 5000ms。想做快速轨迹回放,duration 至少设 100。
3. includePoints 的 padding 单位是像素,不是 rpx。不同设备上同样像素值看起来间距不一样。多屏适配时建议根据设备宽度动态计算 padding。
4. addMarkers 不会自动去重。连续添加同一个 id 的标记会出现两个重叠标记。添加前检查,或用 clear: true 先清空再添加。
5. getCenterLocation 使用网络资源时需要先配置服务器域名。真机调试可能碰到,开发工具里一般没问题。
九、小结
MapContext 方法很多,但常用的是 moveToLocation 移动位置、includePoints 自动缩放、moveAlong 轨迹回放、addMarkers 动态管理标记。掌握这几个,大部分地图场景都能覆盖。轨迹回放场景中,moveAlong 配合 isMapMoving: true 让地图跟随移动,体验不错,适合物流追踪或行程回放类功能。 |